diff --git a/CHANGELOG.md b/CHANGELOG.md index f614d93..2f8bb08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.0.9 + +- Add initialization checks for Android and IOS +- Fix issue for Android platform: https://github.com/ksenia312/nearby_service/issues/8 + ## 0.0.8 - Add `cancelLastConnectionProcess` for Android manager diff --git a/README.md b/README.md index f2eede0..0d9b175 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,10 @@ #### Connecting phones in a P2P network -[![Xenikii Website](https://img.shields.io/badge/-xenikii.one-1D5FA7?style=flat&logoColor=white)](https://xenikii.one) -[![LICENSE BSD](https://img.shields.io/badge/License-BSD-4577d9)](https://github.com/ksenia312/nearby_service/blob/main/LICENSE) +[![Xenikii Website](https://img.shields.io/badge/-xenikii.one-313866?style=for-the-badge&logoColor=white)](https://xenikii.one) +[![LICENSE BSD](https://img.shields.io/badge/License-BSD-504099?style=for-the-badge)](https://github.com/ksenia312/nearby_service/blob/main/LICENSE) +[![Pub package](https://img.shields.io/pub/v/nearby_service.svg?style=for-the-badge&color=974EC3)](https://pub.dev/packages/nearby_service) +[![Pub Likes](https://img.shields.io/pub/likes/nearby_service?style=for-the-badge&color=FE7BE5)](https://pub.dev/packages/nearby_service) Nearby Service Flutter Plugin is used to create connections in a P2P network. The plugin supports sending text messages and files. With it, diff --git a/android/src/main/kotlin/com/xenikii/nearby_service/ErrorCodes.kt b/android/src/main/kotlin/com/xenikii/nearby_service/ErrorCodes.kt new file mode 100644 index 0000000..f8171c0 --- /dev/null +++ b/android/src/main/kotlin/com/xenikii/nearby_service/ErrorCodes.kt @@ -0,0 +1,12 @@ +package com.xenikii.nearby_service + +class ErrorCodes { + companion object { + const val P2P_UNSUPPORTED = "P2P_UNSUPPORTED" + const val ERROR = "ERROR" + const val BUSY = "BUSY" + const val NO_SERVICE_REQUESTS = "NO_SERVICE_REQUESTS" + const val UNKNOWN = "UNKNOWN" + const val NO_INITIALIZATION = "NO_INITIALIZATION" + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/com/xenikii/nearby_service/NearbyServiceManager.kt b/android/src/main/kotlin/com/xenikii/nearby_service/NearbyServiceManager.kt index 370d43d..0cba49b 100644 --- a/android/src/main/kotlin/com/xenikii/nearby_service/NearbyServiceManager.kt +++ b/android/src/main/kotlin/com/xenikii/nearby_service/NearbyServiceManager.kt @@ -87,6 +87,8 @@ class NearbyServiceManager(private var context: Context) { * It also may be null. */ fun getCurrentDevice(result: Result) { + if (!checkInitialization(result)) return + try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { wifiManager.requestDeviceInfo(wifiChannel) { device -> @@ -119,6 +121,8 @@ class NearbyServiceManager(private var context: Context) { * All permissions from [NearbyServicePermissionsHandler] are required. */ fun discover(result: Result) { + if (!checkInitialization(result)) return + try { wifiManager.discoverPeers( wifiChannel, getActionListener( @@ -139,6 +143,8 @@ class NearbyServiceManager(private var context: Context) { * Stop discovery for peers in Wi-fi Direct scope. */ fun stopDiscovery(result: Result) { + if (!checkInitialization(result)) return + wifiManager.stopPeerDiscovery( wifiChannel, getActionListener( result, @@ -152,6 +158,8 @@ class NearbyServiceManager(private var context: Context) { * Returns peers from [NearbyServiceBroadcastReceiver]. */ fun getPeers(result: Result) { + if (!checkInitialization(result)) return + result.success(receiver.peers) } @@ -159,6 +167,8 @@ class NearbyServiceManager(private var context: Context) { * Returns connection info from [NearbyServiceBroadcastReceiver] in json string. */ fun getConnectionInfo(result: Result) { + if (!checkInitialization(result)) return + val info = receiver.wifiInfo?.toJsonString() result.success(info) } @@ -167,6 +177,8 @@ class NearbyServiceManager(private var context: Context) { * Connects to provided [deviceAddress] in Wi-fi Direct scope. */ fun connect(result: Result, deviceAddress: String) { + if (!checkInitialization(result)) return + val config = WifiP2pConfig() if (receiver.connectedDevice?.deviceAddress == deviceAddress) { Logger.i("Already connected to the device $deviceAddress") @@ -196,6 +208,8 @@ class NearbyServiceManager(private var context: Context) { * Disconnect from a previous device in Wi-fi Direct scope. */ fun disconnect(result: Result? = null) { + if (!checkInitialization(result)) return + val actionListener = getActionListener( result, "Disconnected from last device", "Failed to disconnect" ) @@ -204,6 +218,8 @@ class NearbyServiceManager(private var context: Context) { } fun cancelConnect(result: Result? = null) { + if (!checkInitialization(result)) return + val actionListener = getActionListener( result, "Last connection request was cancelled", @@ -240,6 +256,31 @@ class NearbyServiceManager(private var context: Context) { } } + private fun checkInitialization(result: Result?, shouldLog: Boolean = true): Boolean { + try { + if (!::wifiManager.isInitialized) { + Logger.e("WifiManager is not initialized. Please call 'initialize()' first") + result?.success(ErrorCodes.NO_INITIALIZATION) + return false + } + if (!::wifiChannel.isInitialized) { + Logger.e("WifiChannel is not initialized. Please call 'initialize()' first") + result?.success(ErrorCodes.NO_INITIALIZATION) + return false + } + if (!::receiver.isInitialized) { + Logger.e("Broadcast Receiver is not initialized. Please call 'initialize()' first") + result?.success(ErrorCodes.NO_INITIALIZATION) + return false + } + } catch (e: Exception) { + Logger.e("Failed to check initialization, please call 'initialize()' first") + result?.success(ErrorCodes.NO_INITIALIZATION) + return false + } + return true + } + private fun getActionListener( result: Result?, successMessage: String? = null, @@ -262,11 +303,11 @@ class NearbyServiceManager(private var context: Context) { else -> "An unknown error occurred. Please check the device's Wi-Fi P2P settings and ensure the device supports Wi-Fi P2P." } val stringifyReasonCode = when (reasonCode) { - WifiP2pManager.P2P_UNSUPPORTED -> "P2P_UNSUPPORTED" - WifiP2pManager.ERROR -> "ERROR" - WifiP2pManager.BUSY -> "BUSY" - WifiP2pManager.NO_SERVICE_REQUESTS -> "NO_SERVICE_REQUESTS" - else -> "UNKNOWN" + WifiP2pManager.P2P_UNSUPPORTED -> ErrorCodes.P2P_UNSUPPORTED + WifiP2pManager.ERROR -> ErrorCodes.ERROR + WifiP2pManager.BUSY -> ErrorCodes.BUSY + WifiP2pManager.NO_SERVICE_REQUESTS -> ErrorCodes.NO_SERVICE_REQUESTS + else -> ErrorCodes.UNKNOWN } Logger.e("$errorMessage, Reason code: $reasonCode, Reason: $reason") result?.success(stringifyReasonCode) @@ -281,6 +322,8 @@ class NearbyServiceManager(private var context: Context) { val postCallback = object : Runnable { override fun run() { + if (!checkInitialization(null, false)) return + handler.post { eventSink?.success("${receiver.peers}") } handler.postDelayed(this, 1000) } @@ -306,6 +349,8 @@ class NearbyServiceManager(private var context: Context) { val postCallback = object : Runnable { override fun run() { + if (!checkInitialization(null, false)) return + handler.post { eventSink?.success(receiver.connectedDevice?.toJsonString()) } handler.postDelayed(this, 1000) } @@ -330,6 +375,8 @@ class NearbyServiceManager(private var context: Context) { val postCallback = object : Runnable { override fun run() { + if (!checkInitialization(null, false)) return + handler.post { eventSink?.success(receiver.wifiInfo?.toJsonString()) } handler.postDelayed(this, 1000) } diff --git a/android/src/main/kotlin/com/xenikii/nearby_service/NearbyServicePlugin.kt b/android/src/main/kotlin/com/xenikii/nearby_service/NearbyServicePlugin.kt index 631d2de..edfff4e 100644 --- a/android/src/main/kotlin/com/xenikii/nearby_service/NearbyServicePlugin.kt +++ b/android/src/main/kotlin/com/xenikii/nearby_service/NearbyServicePlugin.kt @@ -177,7 +177,6 @@ class NearbyServicePlugin : FlutterPlugin, MethodCallHandler, ActivityAware { channel.setMethodCallHandler(null) peersChannel.setStreamHandler(null) connectedDeviceChannel.setStreamHandler(null) - manager.disconnect() } override fun onAttachedToActivity(binding: ActivityPluginBinding) { diff --git a/ios/Classes/NearbyManager.swift b/ios/Classes/NearbyManager.swift index 52f2096..5688e90 100644 --- a/ios/Classes/NearbyManager.swift +++ b/ios/Classes/NearbyManager.swift @@ -30,6 +30,8 @@ class NearbyManager: NSObject { } func getCurrentDevice(result: @escaping FlutterResult) { + if (!checkInitialization(result: result)) { return } + result(device.toDartFormat()) } @@ -43,32 +45,44 @@ class NearbyManager: NSObject { } func startAdvertising(result: @escaping FlutterResult) { + if (!checkInitialization(result: result)) { return } + self.advertiser.startAdvertisingPeer() result(true) } func startBrowsing(result: @escaping FlutterResult) { + if (!checkInitialization(result: result)) { return } + self.browser.startBrowsingForPeers() result(true) } func stopAdvertising(result: @escaping FlutterResult) { + if (!checkInitialization(result: result)) { return } + self.advertiser.stopAdvertisingPeer() NearbyDevicesStore.instance.clear() result(true) } func stopBrowsing(result: @escaping FlutterResult) { + if (!checkInitialization(result: result)) { return } + self.browser.stopBrowsingForPeers() NearbyDevicesStore.instance.clear() result(true) } func getPeers(result: @escaping FlutterResult) { + if (!checkInitialization(result: result)) { return } + result(NearbyDevicesStore.instance.toDartFormat()) } func invite(for deviceId: String, result: @escaping FlutterResult) { + if (!checkInitialization(result: result)) { return } + do { let device = NearbyDevicesStore.instance.find(for: deviceId) if let requireDevice = device { @@ -87,6 +101,8 @@ class NearbyManager: NSObject { } } func acceptInvite(for deviceId: String, result: @escaping FlutterResult) { + if (!checkInitialization(result: result)) { return } + let device = NearbyDevicesStore.instance.find(for: deviceId) if let requireDevice = device { let nearbySession = requireDevice.createSession(for: self.device.peerID) @@ -96,12 +112,16 @@ class NearbyManager: NSObject { } func disconnect(for deviceId: String, result: @escaping FlutterResult) { + if (!checkInitialization(result: result)) { return } + let device = NearbyDevicesStore.instance.find(for: deviceId) device?.deleteSession() result(true) } func send(for content: NearbyMessageContent, with receiverId: String, result: @escaping FlutterResult) { + if (!checkInitialization(result: result)) { return } + let device = NearbyDevicesStore.instance.find(for: receiverId) do { @@ -158,6 +178,18 @@ class NearbyManager: NSObject { Logger.error(message: error.localizedDescription) } } + + func checkInitialization(result: @escaping FlutterResult) -> Bool { + guard let _ = self.device, + let _ = self.advertiser, + let _ = self.browser else { + Logger.error(message: "NearbyManager is not initialized. Please call 'initialize()' first") + result(ERROR_NO_INITIALIZATION) + return false + } + + return true + } } extension NearbyManager: MCNearbyServiceAdvertiserDelegate { diff --git a/ios/Classes/Utils/Constants.swift b/ios/Classes/Utils/Constants.swift index 5629041..151b8fc 100644 --- a/ios/Classes/Utils/Constants.swift +++ b/ios/Classes/Utils/Constants.swift @@ -16,3 +16,5 @@ let ON_RESOURCE_RECEIVED = Notification.Name("NearbySessionOnResourceReceived") let DART_COMMAND_MESSAGE_RECEIVED = "invoke_nearby_service_message_received" let DART_COMMAND_RESOURCES_RECEIVED = "invoke_nearby_service_resources_received" + +let ERROR_NO_INITIALIZATION = "NO_INITIALIZATION" diff --git a/lib/nearby_service_method_channel.dart b/lib/nearby_service_method_channel.dart index eaf11b9..6a0e81b 100644 --- a/lib/nearby_service_method_channel.dart +++ b/lib/nearby_service_method_channel.dart @@ -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 getPlatformVersion() { - return methodChannel.invokeMethod('getPlatformVersion'); + Future getPlatformVersion() async { + final result = await methodChannel.invokeMethod( + 'getPlatformVersion', + ); + return ResultHandler.instance.handle(result); } @override - Future getPlatformModel() { - return methodChannel.invokeMethod('getPlatformModel'); + Future getPlatformModel() async { + final result = await methodChannel.invokeMethod('getPlatformModel'); + return ResultHandler.instance.handle(result); } @override Future 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> 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> 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); + }); } } diff --git a/lib/src/interface/nearby_service_exception_mapper.dart b/lib/src/interface/nearby_service_exception_mapper.dart new file mode 100644 index 0000000..487d299 --- /dev/null +++ b/lib/src/interface/nearby_service_exception_mapper.dart @@ -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); +} \ No newline at end of file diff --git a/lib/src/model/nearby_device_info.dart b/lib/src/model/nearby_device_info.dart index 50d1469..2d706dc 100644 --- a/lib/src/model/nearby_device_info.dart +++ b/lib/src/model/nearby_device_info.dart @@ -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. diff --git a/lib/src/platforms/android/model/nearby_connection_info.dart b/lib/src/platforms/android/model/nearby_connection_info.dart index b1e5803..16e564f 100644 --- a/lib/src/platforms/android/model/nearby_connection_info.dart +++ b/lib/src/platforms/android/model/nearby_connection_info.dart @@ -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 diff --git a/lib/src/platforms/android/model/nearby_device.dart b/lib/src/platforms/android/model/nearby_device.dart index 4697c3b..bef1209 100644 --- a/lib/src/platforms/android/model/nearby_device.dart +++ b/lib/src/platforms/android/model/nearby_device.dart @@ -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. diff --git a/lib/src/platforms/android/nearby_service_android_method_channel.dart b/lib/src/platforms/android/nearby_service_android_method_channel.dart index 921da14..a4d9e6e 100644 --- a/lib/src/platforms/android/nearby_service_android_method_channel.dart +++ b/lib/src/platforms/android/nearby_service_android_method_channel.dart @@ -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 initialize() async { - return (await methodChannel.invokeMethod( - 'initialize', - {"logLevel": Logger.level.name}, - )) ?? - false; + final result = await methodChannel.invokeMethod( + 'initialize', + {"logLevel": Logger.level.name}, + ); + + return ResultHandler.instance.handle(result) ?? false; } @override Future requestPermissions() async { - return (await methodChannel.invokeMethod('requestPermissions')) ?? - false; + final result = await methodChannel.invokeMethod('requestPermissions'); + return ResultHandler.instance.handle(result) ?? false; } @override Future checkWifiService() async { - return (await methodChannel.invokeMethod('checkWifiService')) ?? - false; + final result = await methodChannel.invokeMethod('checkWifiService'); + return ResultHandler.instance.handle(result) ?? false; } @override Future getConnectionInfo() async { - return NearbyConnectionInfoMapper.mapToInfo( + final result = ResultHandler.instance.handle( await methodChannel.invokeMethod('getConnectionInfo'), ); + return NearbyConnectionInfoMapper.mapToInfo(result); } @override Future discover() async { final result = await methodChannel.invokeMethod('discover'); - return _handleBooleanResult(result); + return ResultHandler.instance.handle(result) ?? false; } @override Future stopDiscovery() async { final result = await methodChannel.invokeMethod('stopDiscovery'); - return _handleBooleanResult(result); + return ResultHandler.instance.handle(result) ?? false; } @override @@ -57,19 +58,19 @@ class MethodChannelAndroidNearbyService extends NearbyServiceAndroidPlatform { "connect", {"deviceAddress": deviceAddress}, ); - return _handleBooleanResult(result); + return ResultHandler.instance.handle(result) ?? false; } @override Future disconnect() async { final result = await methodChannel.invokeMethod("disconnect"); - return _handleBooleanResult(result); + return ResultHandler.instance.handle(result) ?? false; } @override Future cancelConnect() async { final result = await methodChannel.invokeMethod("cancelConnect"); - return _handleBooleanResult(result); + return ResultHandler.instance.handle(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', - ); - } - } } diff --git a/lib/src/platforms/android/utils/exception.dart b/lib/src/platforms/android/utils/exception.dart index 8e1a740..69deab2 100644 --- a/lib/src/platforms/android/utils/exception.dart +++ b/lib/src/platforms/android/utils/exception.dart @@ -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 diff --git a/lib/src/platforms/android/utils/mapper.dart b/lib/src/platforms/android/utils/mapper.dart index b4fc183..eb99aad 100644 --- a/lib/src/platforms/android/utils/mapper.dart +++ b/lib/src/platforms/android/utils/mapper.dart @@ -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, +} diff --git a/lib/src/platforms/ios/nearby_service_ios_method_channel.dart b/lib/src/platforms/ios/nearby_service_ios_method_channel.dart index 63b2bc4..360505d 100644 --- a/lib/src/platforms/ios/nearby_service_ios_method_channel.dart +++ b/lib/src/platforms/ios/nearby_service_ios_method_channel.dart @@ -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( - 'initialize', - deviceName != null ? {"deviceName": deviceName} : null, - ) ?? - false); + final result = await methodChannel.invokeMethod( + 'initialize', + deviceName != null ? {"deviceName": deviceName} : null, + ); + return ResultHandler.instance.handle(result) ?? false; } @override Future getSavedDeviceName() async { - return (await methodChannel.invokeMethod('getSavedDeviceName')); + final result = await methodChannel.invokeMethod( + 'getSavedDeviceName', + ); + return ResultHandler.instance.handle(result); } @override Future startAdvertising() async { - return (await methodChannel.invokeMethod('startAdvertising')) ?? - false; + final result = await methodChannel.invokeMethod('startAdvertising'); + return ResultHandler.instance.handle(result) ?? false; } @override Future startBrowsing() async { - return (await methodChannel.invokeMethod('startBrowsing')) ?? false; + final result = await methodChannel.invokeMethod('startBrowsing'); + return ResultHandler.instance.handle(result) ?? false; } @override Future stopAdvertising() async { - return (await methodChannel.invokeMethod('stopAdvertising')) ?? false; + final result = await methodChannel.invokeMethod('stopAdvertising'); + return ResultHandler.instance.handle(result) ?? false; } @override Future stopBrowsing() async { - return (await methodChannel.invokeMethod('stopBrowsing')) ?? false; + final result = await methodChannel.invokeMethod('stopBrowsing'); + return ResultHandler.instance.handle(result) ?? false; } @override Future invite(String deviceId) async { - return (await methodChannel.invokeMethod( - "invite", - {"deviceId": deviceId}, - )) ?? - false; + final result = await methodChannel.invokeMethod( + "invite", + {"deviceId": deviceId}, + ); + return ResultHandler.instance.handle(result) ?? false; } @override Future acceptInvite(String deviceId) async { - return (await methodChannel.invokeMethod( - "acceptInvite", - {"deviceId": deviceId}, - )) ?? - false; + final result = await methodChannel.invokeMethod( + "acceptInvite", + {"deviceId": deviceId}, + ); + return ResultHandler.instance.handle(result) ?? false; } @override Future disconnect(String deviceId) async { - return (await methodChannel.invokeMethod( - "disconnect", - {"deviceId": deviceId}, - )) ?? - false; + final result = await methodChannel.invokeMethod( + "disconnect", + {"deviceId": deviceId}, + ); + return ResultHandler.instance.handle(result) ?? false; } @override Future send(OutgoingNearbyMessage message) async { - return (await methodChannel.invokeMethod( - "send", - message.toJson(), - )) ?? - false; + final result = await methodChannel.invokeMethod( + "send", + message.toJson(), + ); + return ResultHandler.instance.handle(result) ?? false; } } diff --git a/lib/src/platforms/ios/utils/mapper.dart b/lib/src/platforms/ios/utils/mapper.dart new file mode 100644 index 0000000..29354e0 --- /dev/null +++ b/lib/src/platforms/ios/utils/mapper.dart @@ -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 } diff --git a/lib/src/utils/constants.dart b/lib/src/utils/constants.dart new file mode 100644 index 0000000..81efa98 --- /dev/null +++ b/lib/src/utils/constants.dart @@ -0,0 +1,2 @@ +const kNearbyUnknown = 'unknown'; +const kNearbyServiceMessage = 'Got error from native platform with status='; diff --git a/lib/src/utils/exception.dart b/lib/src/utils/exception.dart index 3a00808..07edff1 100644 --- a/lib/src/utils/exception.dart +++ b/lib/src/utils/exception.dart @@ -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}'; + } +} diff --git a/lib/src/utils/result_handler.dart b/lib/src/utils/result_handler.dart new file mode 100644 index 0000000..cbe4eb0 --- /dev/null +++ b/lib/src/utils/result_handler.dart @@ -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(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', + ); + } +} diff --git a/lib/src/utils/unknown.dart b/lib/src/utils/unknown.dart deleted file mode 100644 index aa77eea..0000000 --- a/lib/src/utils/unknown.dart +++ /dev/null @@ -1 +0,0 @@ -const kNearbyUnknown = 'unknown'; diff --git a/pubspec.yaml b/pubspec.yaml index cae9f79..24ca7b1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: nearby_service description: Nearby Service Flutter Plugin is used to create connections in a P2P network. Supports sending text messages and files. -version: 0.0.8 +version: 0.0.9 homepage: https://github.com/ksenia312/nearby_service repository: https://github.com/ksenia312/nearby_service