Fix: Android native connection errors are not displayed (#5)

* fix(android, lib): add error logging, handle running jobs exception

* doc(app_service): add comment

* fix(exampl_full, utils): move getCurrentDevice info and fix logs

* doc: add comments, update changelog

* doc: update changelog

* version: 0.0.7

* doc: update readme

* doc: update readme
This commit is contained in:
Kseniia Nikitina
2024-04-21 16:38:45 +02:00
committed by GitHub
parent 6abb8024dd
commit e4a8c2243f
19 changed files with 398 additions and 87 deletions
+29
View File
@@ -168,6 +168,13 @@ abstract class NearbyService {
/// Note that the [NearbyIOSService] implementation starts **browsing** or
/// **advertising** depending on the [NearbyIOSService.isBrowser].
///
/// On Android can throw mapped from native platform exceptions:
/// 1. [NearbyServiceBusyException]
/// 2. [NearbyServiceP2PUnsupportedException]
/// 3. [NearbyServiceNoServiceRequestsException]
/// 4. [NearbyServiceGenericErrorException]
/// 5. [NearbyServiceUnknownException]
///
Future<bool> discover();
///
@@ -176,6 +183,13 @@ abstract class NearbyService {
/// Note that the [NearbyIOSService] implementation stops **browsing** or
/// **advertising** depending on the [NearbyIOSService.isBrowser].
///
/// On Android can throw mapped from native platform exceptions:
/// 1. [NearbyServiceBusyException]
/// 2. [NearbyServiceP2PUnsupportedException]
/// 3. [NearbyServiceNoServiceRequestsException]
/// 4. [NearbyServiceGenericErrorException]
/// 5. [NearbyServiceUnknownException]
///
Future<bool> stopDiscovery();
///
@@ -187,6 +201,13 @@ abstract class NearbyService {
/// Note that if [Platform.isIOS] == true, [NearbyIOSDevice] should be passed.
/// If [Platform.isAndroid] == true, [NearbyAndroidDevice] should be passed.
///
/// On Android can throw mapped from native platform exceptions:
/// 1. [NearbyServiceBusyException]
/// 2. [NearbyServiceP2PUnsupportedException]
/// 3. [NearbyServiceNoServiceRequestsException]
/// 4. [NearbyServiceGenericErrorException]
/// 5. [NearbyServiceUnknownException]
///
Future<bool> connect(NearbyDevice device);
///
@@ -196,6 +217,14 @@ abstract class NearbyService {
/// If [Platform.isAndroid] == true, [NearbyAndroidDevice] should be passed.
///
/// **For IOS [device] is required!!!**
///
/// On Android can throw mapped from native platform exceptions:
/// 1. [NearbyServiceBusyException]
/// 2. [NearbyServiceP2PUnsupportedException]
/// 3. [NearbyServiceNoServiceRequestsException]
/// 4. [NearbyServiceGenericErrorException]
/// 5. [NearbyServiceUnknownException]
///
Future<bool> disconnect([NearbyDevice? device]);
///
+1 -1
View File
@@ -37,7 +37,7 @@ class MethodChannelNearbyService extends NearbyServicePlatform {
@override
Future<List<NearbyDevice>> getPeers() async {
return NearbyDeviceMapper.instance.mapToDeviceList(
await methodChannel.invokeMethod('fetchPeers'),
await methodChannel.invokeMethod('getPeers'),
);
}
+4 -4
View File
@@ -6,7 +6,7 @@ import 'package:nearby_service/nearby_service.dart';
/// Contains [value] - the message to be sent or received.
///
final class NearbyMessageTextRequest extends NearbyMessageContent {
const NearbyMessageTextRequest._({
const NearbyMessageTextRequest.createManually({
required this.value,
required super.id,
});
@@ -17,7 +17,7 @@ final class NearbyMessageTextRequest extends NearbyMessageContent {
/// Gets [NearbyMessageTextRequest] from [json]
///
factory NearbyMessageTextRequest.fromJson(Map<String, dynamic>? json) {
return NearbyMessageTextRequest._(
return NearbyMessageTextRequest.createManually(
id: json?['id'],
value: json?['value'],
);
@@ -76,7 +76,7 @@ final class NearbyMessageFilesRequest extends NearbyMessageContent {
///
/// Adds a [NearbyFileInfo] list to [id] to identify files.
///
const NearbyMessageFilesRequest._({
const NearbyMessageFilesRequest.createManually({
required super.id,
required this.files,
});
@@ -91,7 +91,7 @@ final class NearbyMessageFilesRequest extends NearbyMessageContent {
/// Gets [NearbyMessageFilesRequest] from [json].
///
factory NearbyMessageFilesRequest.fromJson(Map<String, dynamic>? json) {
return NearbyMessageFilesRequest._(
return NearbyMessageFilesRequest.createManually(
id: json?['id'],
files: [
...?(json?['files'] as List?)?.map(
+1
View File
@@ -2,3 +2,4 @@ export 'nearby_android_service.dart';
export 'nearby_service_android_interface.dart';
export 'model/nearby_connection_info.dart';
export 'model/nearby_device.dart';
export 'utils/exception.dart';
@@ -143,7 +143,7 @@ class NearbyAndroidMapper implements NearbyDeviceMapper {
final decoded = JSONDecoder.decodeList(value);
return [
...?decoded?.map(
(e) => NearbyAndroidDevice.fromJson(e as Map<String, dynamic>?),
(e) => NearbyAndroidDevice.fromJson(JSONDecoder.decodeMap(e)),
),
];
}
@@ -3,6 +3,8 @@ import 'package:flutter/services.dart';
import 'package:nearby_service/nearby_service.dart';
import 'package:nearby_service/src/utils/logger.dart';
import 'utils/mapper.dart';
/// An implementation of [NearbyServiceAndroidPlatform] that uses method channels.
class MethodChannelAndroidNearbyService extends NearbyServiceAndroidPlatform {
/// The method channel used to interact with the native platform.
@@ -39,26 +41,29 @@ class MethodChannelAndroidNearbyService extends NearbyServiceAndroidPlatform {
@override
Future<bool> discover() async {
return (await methodChannel.invokeMethod<bool>('discover')) ?? false;
final result = await methodChannel.invokeMethod('discover');
return _handleBooleanResult(result);
}
@override
Future<bool> stopDiscovery() async {
return (await methodChannel.invokeMethod<bool>('stopDiscovery')) ?? false;
final result = await methodChannel.invokeMethod('stopDiscovery');
return _handleBooleanResult(result);
}
@override
Future<bool> connect(String deviceAddress) async {
return (await methodChannel.invokeMethod<bool?>(
"connect",
{"deviceAddress": deviceAddress},
)) ??
false;
final result = await methodChannel.invokeMethod(
"connect",
{"deviceAddress": deviceAddress},
);
return _handleBooleanResult(result);
}
@override
Future<bool> disconnect() async {
return (await methodChannel.invokeMethod<bool?>("disconnect")) ?? false;
final result = await methodChannel.invokeMethod("disconnect");
return _handleBooleanResult(result);
}
@override
@@ -70,4 +75,16 @@ class MethodChannelAndroidNearbyService extends NearbyServiceAndroidPlatform {
(e) => 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',
);
}
}
}
@@ -0,0 +1,86 @@
import 'package:nearby_service/nearby_service.dart';
const _kNearbyServiceMessage = 'Got error from native platform with status=';
///
/// Wi-Fi P2P is not supported on this device
///
class NearbyServiceP2PUnsupportedException extends NearbyServiceException {
NearbyServiceP2PUnsupportedException()
: super(
'${_kNearbyServiceMessage}P2P_UNSUPPORTED',
);
@override
String toString() {
return 'NearbyServiceP2PUnsupportedException{error: $error}';
}
}
///
/// The Wi-Fi P2P framework is currently busy.
/// Please wait for the current operation to complete before initiating another.
///
/// Usually this means that you have sent a request to some device and
/// now one of the peers is CONNECTING.
///
class NearbyServiceBusyException extends NearbyServiceException {
NearbyServiceBusyException()
: super(
'${_kNearbyServiceMessage}BUSY',
);
@override
String toString() {
return 'NearbyServiceBusyException{error: $error}';
}
}
///
/// No service discovery requests have been made. Ensure that you have
/// initiated a service discovery request before attempting to connect.
///
class NearbyServiceNoServiceRequestsException extends NearbyServiceException {
NearbyServiceNoServiceRequestsException()
: super(
'${_kNearbyServiceMessage}NO_SERVICE_REQUESTS',
);
@override
String toString() {
return 'NearbyServiceNoServiceRequestsException{error: $error}';
}
}
///
/// A generic error occurred. This could be due to various reasons such as
/// hardware issues, Wi-Fi being turned off, or temporary issues with the
/// Wi-Fi P2P framework.
///
class NearbyServiceGenericErrorException extends NearbyServiceException {
NearbyServiceGenericErrorException()
: super(
'${_kNearbyServiceMessage}ERROR',
);
@override
String toString() {
return 'NearbyServiceGenericErrorException{error: $error}';
}
}
///
/// An unknown error occurred. Please check the device's Wi-Fi
/// P2P settings and ensure the device supports Wi-Fi P2P.
///
class NearbyServiceUnknownException extends NearbyServiceException {
NearbyServiceUnknownException()
: super(
'${_kNearbyServiceMessage}UNKNOWN',
);
@override
String toString() {
return 'NearbyServiceUnknownException{error: $error}';
}
}
@@ -0,0 +1,26 @@
import 'package:nearby_service/nearby_service.dart';
class NearbyServiceAndroidExceptionMapper {
NearbyServiceAndroidExceptionMapper._();
static NearbyServiceException map(String error) {
AndroidFailureCodes? enumValue;
try {
enumValue = AndroidFailureCodes.values.firstWhere(
(element) => element.name == error,
);
} catch (_) {}
return switch (enumValue) {
AndroidFailureCodes.BUSY => NearbyServiceBusyException(),
AndroidFailureCodes.ERROR => NearbyServiceGenericErrorException(),
AndroidFailureCodes.P2P_UNSUPPORTED =>
NearbyServiceP2PUnsupportedException(),
AndroidFailureCodes.NO_SERVICE_REQUESTS =>
NearbyServiceNoServiceRequestsException(),
_ => NearbyServiceUnknownException(),
};
}
}
// ignore: constant_identifier_names
enum AndroidFailureCodes { P2P_UNSUPPORTED, BUSY, NO_SERVICE_REQUESTS, ERROR }
@@ -78,7 +78,7 @@ class NearbyIOSMapper implements NearbyDeviceMapper {
final decoded = JSONDecoder.decodeList(value);
return [
...?decoded?.map(
(e) => NearbyIOSDevice.fromJson(e as Map<String, dynamic>?),
(e) => NearbyIOSDevice.fromJson(JSONDecoder.decodeMap(e)),
),
];
}
+71 -17
View File
@@ -14,28 +14,26 @@ class NearbyServiceException implements Exception {
}
///
/// A call from an unsupported platform.
/// Usage of the plugin on an unsupported platform
///
factory NearbyServiceException.unsupportedPlatform({required String caller}) {
return NearbyServiceException(
'$caller is not supported for platform ${Platform.operatingSystem}',
);
}
factory NearbyServiceException.unsupportedPlatform({
required String caller,
}) =>
NearbyServiceUnsupportedPlatformException(caller: caller);
///
/// A decoding error.
/// Error decoding messages from native platform to Dart (open an issue if
/// this happens!)
///
factory NearbyServiceException.unsupportedDecoding(dynamic value) {
return NearbyServiceException(
'Got unknown value=$value with runtimeType=${value.runtimeType}',
);
}
factory NearbyServiceException.unsupportedDecoding(dynamic value) =>
NearbyServiceUnsupportedDecodingException(value);
factory NearbyServiceException.invalidMessage(NearbyMessageContent content) {
return NearbyServiceException(
'The message="$content" is not valid',
);
}
///
/// An attempt to send an invalid message on the sender's side. Add content
/// validation to your messages
///
factory NearbyServiceException.invalidMessage(NearbyMessageContent content) =>
NearbyServiceInvalidMessageException(content);
final Object? error;
@@ -44,3 +42,59 @@ class NearbyServiceException implements Exception {
return 'NearbyServiceException{error: $error}';
}
}
///
/// Usage of the plugin on an unsupported platform
///
class NearbyServiceUnsupportedPlatformException extends NearbyServiceException {
///
/// Usage of the plugin on an unsupported platform - default constructor
///
NearbyServiceUnsupportedPlatformException({required String caller})
: super(
'$caller is not supported for platform ${Platform.operatingSystem}',
);
@override
String toString() {
return 'NearbyServiceUnsupportedPlatformException{error: $error}';
}
}
///
/// Error decoding messages from native platform to Dart (open an issue if
/// this happens!)
///
class NearbyServiceUnsupportedDecodingException extends NearbyServiceException {
///
/// A decoding error - default constructor
///
NearbyServiceUnsupportedDecodingException(dynamic value)
: super(
'Got unknown value=$value with runtimeType=${value.runtimeType}',
);
@override
String toString() {
return 'NearbyServiceUnsupportedDecodingException{error: $error}';
}
}
///
/// An attempt to send an invalid message on the sender's side. Add content
/// validation to your messages
///
class NearbyServiceInvalidMessageException extends NearbyServiceException {
///
/// Invalid message error - default constructor
///
NearbyServiceInvalidMessageException(NearbyMessageContent content)
: super(
'The message="$content" is not valid',
);
@override
String toString() {
return 'NearbyServiceInvalidMessageException{error: $error}';
}
}
+1 -1
View File
@@ -62,10 +62,10 @@ class FilesSocket {
addChunk(event);
} else if (event == separateCommandOf(_currentFileIndex)) {
_futures.add(_createFile(_currentFileIndex));
Logger.info('Completed receiving file №${_currentFileIndex + 1}');
_currentFileIndex = _currentFileIndex + 1;
_chunksCount = 0;
_bytesTable['$_currentFileIndex'] = [];
Logger.info('Completed receiving file №${_currentFileIndex - 1}');
} else if (event == finishCommand) {
await Future.wait(_futures);
Logger.info('Files pack ${filesRequest.id} was created');