[Android, iOS]: Initialization check, no disconnect on closing (#9)
* feat(android, dart): add check for initialization, show proper error messages * feat(exception): add exception mapper for android and ios * feat(ios): check initialization in swift * fix(android): add initialization check for methods, remove disconnect() inside onDetachedFromEngine * chore: code style, version, changelog
This commit is contained in:
@@ -3,6 +3,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:nearby_service/nearby_service.dart';
|
||||
|
||||
import 'nearby_service_platform_interface.dart';
|
||||
import 'src/utils/result_handler.dart';
|
||||
|
||||
/// An implementation of [NearbyServicePlatform] that uses method channels.
|
||||
class MethodChannelNearbyService extends NearbyServicePlatform {
|
||||
@@ -11,22 +12,24 @@ class MethodChannelNearbyService extends NearbyServicePlatform {
|
||||
final methodChannel = const MethodChannel('nearby_service');
|
||||
|
||||
@override
|
||||
Future<String?> getPlatformVersion() {
|
||||
return methodChannel.invokeMethod<String>('getPlatformVersion');
|
||||
Future<String?> getPlatformVersion() async {
|
||||
final result = await methodChannel.invokeMethod<String>(
|
||||
'getPlatformVersion',
|
||||
);
|
||||
return ResultHandler.instance.handle<String?>(result);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String?> getPlatformModel() {
|
||||
return methodChannel.invokeMethod<String>('getPlatformModel');
|
||||
Future<String?> getPlatformModel() async {
|
||||
final result = await methodChannel.invokeMethod<String>('getPlatformModel');
|
||||
return ResultHandler.instance.handle<String?>(result);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<NearbyDeviceInfo?> getCurrentDeviceInfo() async {
|
||||
return NearbyDeviceMapper.instance
|
||||
.mapToDevice(
|
||||
await methodChannel.invokeMethod('getCurrentDevice'),
|
||||
)
|
||||
?.info;
|
||||
final result = await methodChannel.invokeMethod('getCurrentDevice');
|
||||
final updatedResult = ResultHandler.instance.handle(result);
|
||||
return NearbyDeviceMapper.instance.mapToDevice(updatedResult)?.info;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -36,16 +39,17 @@ class MethodChannelNearbyService extends NearbyServicePlatform {
|
||||
|
||||
@override
|
||||
Future<List<NearbyDevice>> getPeers() async {
|
||||
return NearbyDeviceMapper.instance.mapToDeviceList(
|
||||
await methodChannel.invokeMethod('getPeers'),
|
||||
);
|
||||
final result = await methodChannel.invokeMethod('getPeers');
|
||||
final updatedResult = ResultHandler.instance.handle(result);
|
||||
return NearbyDeviceMapper.instance.mapToDeviceList(updatedResult);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<List<NearbyDevice>> getPeersStream() {
|
||||
const peersChannel = EventChannel("nearby_service_peers");
|
||||
return peersChannel.receiveBroadcastStream().map((e) {
|
||||
return NearbyDeviceMapper.instance.mapToDeviceList(e);
|
||||
final updatedResult = ResultHandler.instance.handle(e);
|
||||
return NearbyDeviceMapper.instance.mapToDeviceList(updatedResult);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -54,8 +58,11 @@ class MethodChannelNearbyService extends NearbyServicePlatform {
|
||||
const connectedDeviceChannel = EventChannel(
|
||||
"nearby_service_connected_device",
|
||||
);
|
||||
return connectedDeviceChannel.receiveBroadcastStream(device.info.id).map(
|
||||
(e) => NearbyDeviceMapper.instance.mapToDevice(e),
|
||||
);
|
||||
return connectedDeviceChannel
|
||||
.receiveBroadcastStream(device.info.id)
|
||||
.map((e) {
|
||||
final updatedResult = ResultHandler.instance.handle(e);
|
||||
return NearbyDeviceMapper.instance.mapToDevice(updatedResult);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:nearby_service/nearby_service.dart';
|
||||
import 'package:nearby_service/src/platforms/android/utils/mapper.dart';
|
||||
import 'package:nearby_service/src/platforms/ios/utils/mapper.dart';
|
||||
|
||||
abstract class NearbyServiceExceptionMapper {
|
||||
static NearbyServiceExceptionMapper get instance {
|
||||
if (Platform.isAndroid) {
|
||||
return NearbyServiceAndroidExceptionMapper();
|
||||
} else if (Platform.isIOS) {
|
||||
return NearbyServiceIOSExceptionMapper();
|
||||
}
|
||||
throw NearbyServiceException.unsupportedPlatform(
|
||||
caller: 'NearbyServiceExceptionMapper',
|
||||
);
|
||||
}
|
||||
|
||||
bool canMap(String error);
|
||||
|
||||
NearbyServiceException map(String error);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:nearby_service/src/utils/unknown.dart';
|
||||
import 'package:nearby_service/src/utils/constants.dart';
|
||||
|
||||
///
|
||||
/// Minimal information about the device.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:nearby_service/src/utils/constants.dart';
|
||||
import 'package:nearby_service/src/utils/json_decoder.dart';
|
||||
import 'package:nearby_service/src/utils/unknown.dart';
|
||||
|
||||
///
|
||||
/// The class representing the connection information
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:nearby_service/nearby_service.dart';
|
||||
import 'package:nearby_service/src/utils/constants.dart';
|
||||
import 'package:nearby_service/src/utils/json_decoder.dart';
|
||||
import 'package:nearby_service/src/utils/unknown.dart';
|
||||
|
||||
///
|
||||
/// A device on a P2P network obtained from the Android platform.
|
||||
|
||||
@@ -2,8 +2,7 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:nearby_service/nearby_service.dart';
|
||||
import 'package:nearby_service/src/utils/logger.dart';
|
||||
|
||||
import 'utils/mapper.dart';
|
||||
import 'package:nearby_service/src/utils/result_handler.dart';
|
||||
|
||||
/// An implementation of [NearbyServiceAndroidPlatform] that uses method channels.
|
||||
class MethodChannelAndroidNearbyService extends NearbyServiceAndroidPlatform {
|
||||
@@ -13,42 +12,44 @@ class MethodChannelAndroidNearbyService extends NearbyServiceAndroidPlatform {
|
||||
|
||||
@override
|
||||
Future<bool> initialize() async {
|
||||
return (await methodChannel.invokeMethod<bool>(
|
||||
'initialize',
|
||||
{"logLevel": Logger.level.name},
|
||||
)) ??
|
||||
false;
|
||||
final result = await methodChannel.invokeMethod(
|
||||
'initialize',
|
||||
{"logLevel": Logger.level.name},
|
||||
);
|
||||
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> requestPermissions() async {
|
||||
return (await methodChannel.invokeMethod<bool>('requestPermissions')) ??
|
||||
false;
|
||||
final result = await methodChannel.invokeMethod('requestPermissions');
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> checkWifiService() async {
|
||||
return (await methodChannel.invokeMethod<bool>('checkWifiService')) ??
|
||||
false;
|
||||
final result = await methodChannel.invokeMethod('checkWifiService');
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<NearbyConnectionAndroidInfo?> getConnectionInfo() async {
|
||||
return NearbyConnectionInfoMapper.mapToInfo(
|
||||
final result = ResultHandler.instance.handle(
|
||||
await methodChannel.invokeMethod('getConnectionInfo'),
|
||||
);
|
||||
return NearbyConnectionInfoMapper.mapToInfo(result);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> discover() async {
|
||||
final result = await methodChannel.invokeMethod('discover');
|
||||
return _handleBooleanResult(result);
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> stopDiscovery() async {
|
||||
final result = await methodChannel.invokeMethod('stopDiscovery');
|
||||
return _handleBooleanResult(result);
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -57,19 +58,19 @@ class MethodChannelAndroidNearbyService extends NearbyServiceAndroidPlatform {
|
||||
"connect",
|
||||
{"deviceAddress": deviceAddress},
|
||||
);
|
||||
return _handleBooleanResult(result);
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> disconnect() async {
|
||||
final result = await methodChannel.invokeMethod("disconnect");
|
||||
return _handleBooleanResult(result);
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> cancelConnect() async {
|
||||
final result = await methodChannel.invokeMethod("cancelConnect");
|
||||
return _handleBooleanResult(result);
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -78,19 +79,9 @@ class MethodChannelAndroidNearbyService extends NearbyServiceAndroidPlatform {
|
||||
"nearby_service_connection_info",
|
||||
);
|
||||
return connectedDeviceChannel.receiveBroadcastStream().map(
|
||||
(e) => NearbyConnectionInfoMapper.mapToInfo(e),
|
||||
(e) => ResultHandler.instance.handle(
|
||||
NearbyConnectionInfoMapper.mapToInfo(e),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
bool _handleBooleanResult(dynamic result) {
|
||||
if (result is bool) {
|
||||
return result;
|
||||
} else if (result is String) {
|
||||
throw NearbyServiceAndroidExceptionMapper.map(result);
|
||||
} else {
|
||||
throw NearbyServiceException(
|
||||
'Got unknown value from native platform: $result',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:nearby_service/nearby_service.dart';
|
||||
|
||||
const _kNearbyServiceMessage = 'Got error from native platform with status=';
|
||||
import 'package:nearby_service/src/utils/constants.dart';
|
||||
|
||||
///
|
||||
/// Wi-Fi P2P is not supported on this device
|
||||
@@ -8,7 +7,7 @@ const _kNearbyServiceMessage = 'Got error from native platform with status=';
|
||||
class NearbyServiceP2PUnsupportedException extends NearbyServiceException {
|
||||
NearbyServiceP2PUnsupportedException()
|
||||
: super(
|
||||
'${_kNearbyServiceMessage}P2P_UNSUPPORTED',
|
||||
'${kNearbyServiceMessage}P2P_UNSUPPORTED',
|
||||
);
|
||||
|
||||
@override
|
||||
@@ -27,7 +26,7 @@ class NearbyServiceP2PUnsupportedException extends NearbyServiceException {
|
||||
class NearbyServiceBusyException extends NearbyServiceException {
|
||||
NearbyServiceBusyException()
|
||||
: super(
|
||||
'${_kNearbyServiceMessage}BUSY',
|
||||
'${kNearbyServiceMessage}BUSY',
|
||||
);
|
||||
|
||||
@override
|
||||
@@ -43,7 +42,7 @@ class NearbyServiceBusyException extends NearbyServiceException {
|
||||
class NearbyServiceNoServiceRequestsException extends NearbyServiceException {
|
||||
NearbyServiceNoServiceRequestsException()
|
||||
: super(
|
||||
'${_kNearbyServiceMessage}NO_SERVICE_REQUESTS',
|
||||
'${kNearbyServiceMessage}NO_SERVICE_REQUESTS',
|
||||
);
|
||||
|
||||
@override
|
||||
@@ -60,7 +59,7 @@ class NearbyServiceNoServiceRequestsException extends NearbyServiceException {
|
||||
class NearbyServiceGenericErrorException extends NearbyServiceException {
|
||||
NearbyServiceGenericErrorException()
|
||||
: super(
|
||||
'${_kNearbyServiceMessage}ERROR',
|
||||
'${kNearbyServiceMessage}ERROR',
|
||||
);
|
||||
|
||||
@override
|
||||
@@ -76,7 +75,7 @@ class NearbyServiceGenericErrorException extends NearbyServiceException {
|
||||
class NearbyServiceUnknownException extends NearbyServiceException {
|
||||
NearbyServiceUnknownException()
|
||||
: super(
|
||||
'${_kNearbyServiceMessage}UNKNOWN',
|
||||
'${kNearbyServiceMessage}UNKNOWN',
|
||||
);
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
// ignore_for_file: constant_identifier_names
|
||||
import 'package:nearby_service/nearby_service.dart';
|
||||
import 'package:nearby_service/src/interface/nearby_service_exception_mapper.dart';
|
||||
|
||||
class NearbyServiceAndroidExceptionMapper {
|
||||
NearbyServiceAndroidExceptionMapper._();
|
||||
class NearbyServiceAndroidExceptionMapper extends NearbyServiceExceptionMapper {
|
||||
@override
|
||||
bool canMap(String error) {
|
||||
return AndroidFailureCodes.values.any((element) => element.name == error);
|
||||
}
|
||||
|
||||
static NearbyServiceException map(String error) {
|
||||
@override
|
||||
NearbyServiceException map(String error) {
|
||||
AndroidFailureCodes? enumValue;
|
||||
try {
|
||||
enumValue = AndroidFailureCodes.values.firstWhere(
|
||||
@@ -17,10 +23,17 @@ class NearbyServiceAndroidExceptionMapper {
|
||||
NearbyServiceP2PUnsupportedException(),
|
||||
AndroidFailureCodes.NO_SERVICE_REQUESTS =>
|
||||
NearbyServiceNoServiceRequestsException(),
|
||||
AndroidFailureCodes.NO_INITIALIZATION =>
|
||||
NearbyServiceNoInitializationException(),
|
||||
_ => NearbyServiceUnknownException(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ignore: constant_identifier_names
|
||||
enum AndroidFailureCodes { P2P_UNSUPPORTED, BUSY, NO_SERVICE_REQUESTS, ERROR }
|
||||
enum AndroidFailureCodes {
|
||||
P2P_UNSUPPORTED,
|
||||
BUSY,
|
||||
NO_SERVICE_REQUESTS,
|
||||
ERROR,
|
||||
NO_INITIALIZATION,
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:async';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:nearby_service/nearby_service.dart';
|
||||
import 'package:nearby_service/src/utils/result_handler.dart';
|
||||
|
||||
/// An implementation of [NearbyServiceIOSPlatform] that uses method channels.
|
||||
class MethodChannelIOSNearbyService extends NearbyServiceIOSPlatform {
|
||||
@@ -31,72 +32,78 @@ class MethodChannelIOSNearbyService extends NearbyServiceIOSPlatform {
|
||||
break;
|
||||
}
|
||||
});
|
||||
return (await methodChannel.invokeMethod<bool>(
|
||||
'initialize',
|
||||
deviceName != null ? {"deviceName": deviceName} : null,
|
||||
) ??
|
||||
false);
|
||||
final result = await methodChannel.invokeMethod(
|
||||
'initialize',
|
||||
deviceName != null ? {"deviceName": deviceName} : null,
|
||||
);
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String?> getSavedDeviceName() async {
|
||||
return (await methodChannel.invokeMethod<String?>('getSavedDeviceName'));
|
||||
final result = await methodChannel.invokeMethod<String?>(
|
||||
'getSavedDeviceName',
|
||||
);
|
||||
return ResultHandler.instance.handle(result);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> startAdvertising() async {
|
||||
return (await methodChannel.invokeMethod<bool>('startAdvertising')) ??
|
||||
false;
|
||||
final result = await methodChannel.invokeMethod('startAdvertising');
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> startBrowsing() async {
|
||||
return (await methodChannel.invokeMethod<bool>('startBrowsing')) ?? false;
|
||||
final result = await methodChannel.invokeMethod('startBrowsing');
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> stopAdvertising() async {
|
||||
return (await methodChannel.invokeMethod<bool>('stopAdvertising')) ?? false;
|
||||
final result = await methodChannel.invokeMethod('stopAdvertising');
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> stopBrowsing() async {
|
||||
return (await methodChannel.invokeMethod<bool>('stopBrowsing')) ?? false;
|
||||
final result = await methodChannel.invokeMethod('stopBrowsing');
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> invite(String deviceId) async {
|
||||
return (await methodChannel.invokeMethod<bool?>(
|
||||
"invite",
|
||||
{"deviceId": deviceId},
|
||||
)) ??
|
||||
false;
|
||||
final result = await methodChannel.invokeMethod(
|
||||
"invite",
|
||||
{"deviceId": deviceId},
|
||||
);
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> acceptInvite(String deviceId) async {
|
||||
return (await methodChannel.invokeMethod<bool?>(
|
||||
"acceptInvite",
|
||||
{"deviceId": deviceId},
|
||||
)) ??
|
||||
false;
|
||||
final result = await methodChannel.invokeMethod(
|
||||
"acceptInvite",
|
||||
{"deviceId": deviceId},
|
||||
);
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> disconnect(String deviceId) async {
|
||||
return (await methodChannel.invokeMethod<bool?>(
|
||||
"disconnect",
|
||||
{"deviceId": deviceId},
|
||||
)) ??
|
||||
false;
|
||||
final result = await methodChannel.invokeMethod(
|
||||
"disconnect",
|
||||
{"deviceId": deviceId},
|
||||
);
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> send(OutgoingNearbyMessage message) async {
|
||||
return (await methodChannel.invokeMethod<bool?>(
|
||||
"send",
|
||||
message.toJson(),
|
||||
)) ??
|
||||
false;
|
||||
final result = await methodChannel.invokeMethod(
|
||||
"send",
|
||||
message.toJson(),
|
||||
);
|
||||
return ResultHandler.instance.handle<bool?>(result) ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// ignore_for_file: constant_identifier_names
|
||||
import 'package:nearby_service/nearby_service.dart';
|
||||
import 'package:nearby_service/src/interface/nearby_service_exception_mapper.dart';
|
||||
|
||||
class NearbyServiceIOSExceptionMapper extends NearbyServiceExceptionMapper {
|
||||
@override
|
||||
bool canMap(String error) {
|
||||
return IOSFailureCodes.values.any((element) => element.name == error);
|
||||
}
|
||||
|
||||
@override
|
||||
NearbyServiceException map(String error) {
|
||||
IOSFailureCodes? enumValue;
|
||||
try {
|
||||
enumValue = IOSFailureCodes.values.firstWhere(
|
||||
(element) => element.name == error,
|
||||
);
|
||||
} catch (_) {}
|
||||
return switch (enumValue) {
|
||||
IOSFailureCodes.NO_INITIALIZATION =>
|
||||
NearbyServiceNoInitializationException(),
|
||||
_ => NearbyServiceUnknownException(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
enum IOSFailureCodes { NO_INITIALIZATION }
|
||||
@@ -0,0 +1,2 @@
|
||||
const kNearbyUnknown = 'unknown';
|
||||
const kNearbyServiceMessage = 'Got error from native platform with status=';
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:nearby_service/nearby_service.dart';
|
||||
import 'package:nearby_service/src/utils/constants.dart';
|
||||
import 'package:nearby_service/src/utils/logger.dart';
|
||||
|
||||
///
|
||||
@@ -98,3 +99,18 @@ class NearbyServiceInvalidMessageException extends NearbyServiceException {
|
||||
return 'NearbyServiceInvalidMessageException{error: $error}';
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Error when the plugin is not initialized. Please call initialize() method first.
|
||||
///
|
||||
class NearbyServiceNoInitializationException extends NearbyServiceException {
|
||||
NearbyServiceNoInitializationException()
|
||||
: super(
|
||||
'${kNearbyServiceMessage}NO_INITIALIZATION',
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NearbyServiceNoInitializationException{error: $error}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import 'package:nearby_service/nearby_service.dart';
|
||||
import 'package:nearby_service/src/interface/nearby_service_exception_mapper.dart';
|
||||
|
||||
class ResultHandler {
|
||||
ResultHandler._();
|
||||
|
||||
static ResultHandler instance = ResultHandler._();
|
||||
|
||||
T handle<T>(dynamic result) {
|
||||
if (result is String &&
|
||||
NearbyServiceExceptionMapper.instance.canMap(result)) {
|
||||
throw NearbyServiceExceptionMapper.instance.map(result);
|
||||
}
|
||||
if (result is T) {
|
||||
return result;
|
||||
}
|
||||
|
||||
throw NearbyServiceException(
|
||||
'Got unknown value from native platform: $result',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
const kNearbyUnknown = 'unknown';
|
||||
Reference in New Issue
Block a user