|
|
|
@ -1,7 +1,6 @@
|
|
|
|
|
import 'dart:async';
|
|
|
|
|
import 'dart:typed_data';
|
|
|
|
|
|
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
|
import 'package:flutter/services.dart';
|
|
|
|
|
import 'package:nearby_connections/src/classes.dart';
|
|
|
|
|
import 'package:nearby_connections/src/defs.dart';
|
|
|
|
@ -14,24 +13,24 @@ import 'package:nearby_connections/src/defs.dart';
|
|
|
|
|
/// All methods are asynchronous.
|
|
|
|
|
class Nearby {
|
|
|
|
|
//Singleton pattern for maintaining only 1 instance of this class
|
|
|
|
|
static Nearby _instance;
|
|
|
|
|
static Nearby? _instance;
|
|
|
|
|
|
|
|
|
|
factory Nearby() {
|
|
|
|
|
if (_instance == null) {
|
|
|
|
|
_instance = Nearby._();
|
|
|
|
|
}
|
|
|
|
|
return _instance;
|
|
|
|
|
return _instance!;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Nearby._() {
|
|
|
|
|
_channel.setMethodCallHandler((handler) {
|
|
|
|
|
Map<dynamic, dynamic> args = handler.arguments;
|
|
|
|
|
_channel.setMethodCallHandler((MethodCall handler) {
|
|
|
|
|
Map<dynamic, dynamic> args = handler.arguments!;
|
|
|
|
|
switch (handler.method) {
|
|
|
|
|
case "ad.onConnectionInitiated":
|
|
|
|
|
String endpointId = args['endpointId'];
|
|
|
|
|
String endpointName = args['endpointName'];
|
|
|
|
|
String authenticationToken = args['authenticationToken'];
|
|
|
|
|
bool isIncomingConnection = args['isIncomingConnection'];
|
|
|
|
|
String endpointId = args['endpointId'] ?? '-1';
|
|
|
|
|
String endpointName = args['endpointName'] ?? '-1';
|
|
|
|
|
String authenticationToken = args['authenticationToken'] ?? '-1';
|
|
|
|
|
bool isIncomingConnection = args['isIncomingConnection'] ?? false;
|
|
|
|
|
|
|
|
|
|
_advertConnectionInitiated?.call(
|
|
|
|
|
endpointId,
|
|
|
|
@ -40,24 +39,25 @@ class Nearby {
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
case "ad.onConnectionResult":
|
|
|
|
|
String endpointId = args['endpointId'];
|
|
|
|
|
Status statusCode = Status.values[args['statusCode']];
|
|
|
|
|
String endpointId = args['endpointId'] ?? '-1';
|
|
|
|
|
Status statusCode =
|
|
|
|
|
Status.values[args['statusCode'] ?? Status.ERROR.index];
|
|
|
|
|
|
|
|
|
|
_advertConnectionResult?.call(endpointId, statusCode);
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
case "ad.onDisconnected":
|
|
|
|
|
String endpointId = args['endpointId'];
|
|
|
|
|
String endpointId = args['endpointId'] ?? '-1';
|
|
|
|
|
|
|
|
|
|
_advertDisconnected?.call(endpointId);
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
case "dis.onConnectionInitiated":
|
|
|
|
|
String endpointId = args['endpointId'];
|
|
|
|
|
String endpointName = args['endpointName'];
|
|
|
|
|
String authenticationToken = args['authenticationToken'];
|
|
|
|
|
bool isIncomingConnection = args['isIncomingConnection'];
|
|
|
|
|
String endpointId = args['endpointId'] ?? '-1';
|
|
|
|
|
String endpointName = args['endpointName'] ?? '-1';
|
|
|
|
|
String authenticationToken = args['authenticationToken'] ?? '-1';
|
|
|
|
|
bool isIncomingConnection = args['isIncomingConnection'] ?? false;
|
|
|
|
|
|
|
|
|
|
_discoverConnectionInitiated?.call(
|
|
|
|
|
endpointId,
|
|
|
|
@ -66,38 +66,39 @@ class Nearby {
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
case "dis.onConnectionResult":
|
|
|
|
|
String endpointId = args['endpointId'];
|
|
|
|
|
Status statusCode = Status.values[args['statusCode']];
|
|
|
|
|
String endpointId = args['endpointId'] ?? '-1';
|
|
|
|
|
Status statusCode =
|
|
|
|
|
Status.values[args['statusCode'] ?? Status.ERROR.index];
|
|
|
|
|
|
|
|
|
|
_discoverConnectionResult?.call(endpointId, statusCode);
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
case "dis.onDisconnected":
|
|
|
|
|
String endpointId = args['endpointId'];
|
|
|
|
|
String endpointId = args['endpointId'] ?? '-1';
|
|
|
|
|
|
|
|
|
|
_discoverDisconnected?.call(endpointId);
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
case "dis.onEndpointFound":
|
|
|
|
|
String endpointId = args['endpointId'];
|
|
|
|
|
String endpointName = args['endpointName'];
|
|
|
|
|
String serviceId = args['serviceId'];
|
|
|
|
|
String endpointId = args['endpointId'] ?? '-1';
|
|
|
|
|
String endpointName = args['endpointName'] ?? '-1';
|
|
|
|
|
String serviceId = args['serviceId'] ?? '-1';
|
|
|
|
|
_onEndpointFound?.call(endpointId, endpointName, serviceId);
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
case "dis.onEndpointLost":
|
|
|
|
|
String endpointId = args['endpointId'];
|
|
|
|
|
String endpointId = args['endpointId'] ?? '-1';
|
|
|
|
|
|
|
|
|
|
_onEndpointLost?.call(endpointId);
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
case "onPayloadReceived":
|
|
|
|
|
String endpointId = args['endpointId'];
|
|
|
|
|
int type = args['type'];
|
|
|
|
|
Uint8List bytes = args['bytes'];
|
|
|
|
|
int payloadId = args['payloadId'];
|
|
|
|
|
String filePath = args['filePath'];
|
|
|
|
|
String endpointId = args['endpointId'] ?? '-1';
|
|
|
|
|
int type = args['type'] ?? PayloadType.NONE;
|
|
|
|
|
Uint8List bytes = args['bytes'] ?? Uint8List(0);
|
|
|
|
|
int payloadId = args['payloadId'] ?? -1;
|
|
|
|
|
String filePath = args['filePath'] ?? '';
|
|
|
|
|
|
|
|
|
|
Payload payload = Payload(
|
|
|
|
|
type: PayloadType.values[type],
|
|
|
|
@ -110,11 +111,11 @@ class Nearby {
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case "onPayloadTransferUpdate":
|
|
|
|
|
String endpointId = args['endpointId'];
|
|
|
|
|
int payloadId = args['payloadId'];
|
|
|
|
|
int status = args['status'];
|
|
|
|
|
int bytesTransferred = args['bytesTransferred'];
|
|
|
|
|
int totalBytes = args['totalBytes'];
|
|
|
|
|
String endpointId = args['endpointId'] ?? '-1';
|
|
|
|
|
int payloadId = args['payloadId'] ?? -1;
|
|
|
|
|
int status = args['status'] ?? Status.ERROR.index;
|
|
|
|
|
int bytesTransferred = args['bytesTransferred'] ?? 0;
|
|
|
|
|
int totalBytes = args['totalBytes'] ?? 0;
|
|
|
|
|
|
|
|
|
|
PayloadTransferUpdate payloadTransferUpdate = PayloadTransferUpdate(
|
|
|
|
|
id: payloadId,
|
|
|
|
@ -127,22 +128,22 @@ class Nearby {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
});
|
|
|
|
|
} as Future<dynamic> Function(MethodCall)?);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//for advertisers
|
|
|
|
|
OnConnectionInitiated _advertConnectionInitiated,
|
|
|
|
|
OnConnectionInitiated? _advertConnectionInitiated,
|
|
|
|
|
_discoverConnectionInitiated;
|
|
|
|
|
OnConnectionResult _advertConnectionResult, _discoverConnectionResult;
|
|
|
|
|
OnDisconnected _advertDisconnected, _discoverDisconnected;
|
|
|
|
|
OnConnectionResult? _advertConnectionResult, _discoverConnectionResult;
|
|
|
|
|
OnDisconnected? _advertDisconnected, _discoverDisconnected;
|
|
|
|
|
|
|
|
|
|
//for discoverers
|
|
|
|
|
OnEndpointFound _onEndpointFound;
|
|
|
|
|
OnEndpointLost _onEndpointLost;
|
|
|
|
|
OnEndpointFound? _onEndpointFound;
|
|
|
|
|
OnEndpointLost? _onEndpointLost;
|
|
|
|
|
|
|
|
|
|
//for receiving payload
|
|
|
|
|
OnPayloadReceived _onPayloadReceived;
|
|
|
|
|
OnPayloadTransferUpdate _onPayloadTransferUpdate;
|
|
|
|
|
OnPayloadReceived? _onPayloadReceived;
|
|
|
|
|
OnPayloadTransferUpdate? _onPayloadTransferUpdate;
|
|
|
|
|
|
|
|
|
|
static const MethodChannel _channel =
|
|
|
|
|
const MethodChannel('nearby_connections');
|
|
|
|
@ -151,21 +152,23 @@ class Nearby {
|
|
|
|
|
///
|
|
|
|
|
/// returns true/false based on location permissions.
|
|
|
|
|
/// Discovery cannot be started with insufficient permission
|
|
|
|
|
Future<bool> checkLocationPermission() async => await _channel.invokeMethod(
|
|
|
|
|
Future<bool> checkLocationPermission() async =>
|
|
|
|
|
await _channel.invokeMethod(
|
|
|
|
|
'checkLocationPermission',
|
|
|
|
|
);
|
|
|
|
|
) ??
|
|
|
|
|
false;
|
|
|
|
|
|
|
|
|
|
/// convenience method
|
|
|
|
|
///
|
|
|
|
|
/// Asks location permission
|
|
|
|
|
Future<bool> askLocationPermission() async =>
|
|
|
|
|
await _channel.invokeMethod('askLocationPermission');
|
|
|
|
|
await _channel.invokeMethod('askLocationPermission') ?? false;
|
|
|
|
|
|
|
|
|
|
/// convenience method
|
|
|
|
|
///
|
|
|
|
|
/// returns true/false based on external storage permissions.
|
|
|
|
|
Future<bool> checkExternalStoragePermission() async =>
|
|
|
|
|
await _channel.invokeMethod('checkExternalStoragePermission');
|
|
|
|
|
await _channel.invokeMethod('checkExternalStoragePermission') ?? false;
|
|
|
|
|
|
|
|
|
|
/// convenience method
|
|
|
|
|
///
|
|
|
|
@ -174,13 +177,13 @@ class Nearby {
|
|
|
|
|
/// If Location isn't enabled, devices may disconnect often.
|
|
|
|
|
/// Some devices may immediately disconnect
|
|
|
|
|
Future<bool> checkLocationEnabled() async =>
|
|
|
|
|
await _channel.invokeMethod('checkLocationEnabled');
|
|
|
|
|
await _channel.invokeMethod('checkLocationEnabled') ?? false;
|
|
|
|
|
|
|
|
|
|
/// convenience method
|
|
|
|
|
///
|
|
|
|
|
/// directs user to Location Settings, so they can turn on their Location/GPS
|
|
|
|
|
Future<bool> enableLocationServices() async =>
|
|
|
|
|
await _channel.invokeMethod('enableLocationServices');
|
|
|
|
|
await _channel.invokeMethod('enableLocationServices') ?? false;
|
|
|
|
|
|
|
|
|
|
/// convenience method
|
|
|
|
|
///
|
|
|
|
@ -201,22 +204,21 @@ class Nearby {
|
|
|
|
|
Future<bool> startAdvertising(
|
|
|
|
|
String userNickName,
|
|
|
|
|
Strategy strategy, {
|
|
|
|
|
@required OnConnectionInitiated onConnectionInitiated,
|
|
|
|
|
@required OnConnectionResult onConnectionResult,
|
|
|
|
|
@required OnDisconnected onDisconnected,
|
|
|
|
|
required OnConnectionInitiated onConnectionInitiated,
|
|
|
|
|
required OnConnectionResult onConnectionResult,
|
|
|
|
|
required OnDisconnected onDisconnected,
|
|
|
|
|
String serviceId = "com.pkmnapps.nearby_connections",
|
|
|
|
|
}) async {
|
|
|
|
|
assert(userNickName != null && strategy != null && serviceId != null);
|
|
|
|
|
|
|
|
|
|
this._advertConnectionInitiated = onConnectionInitiated;
|
|
|
|
|
this._advertConnectionResult = onConnectionResult;
|
|
|
|
|
this._advertDisconnected = onDisconnected;
|
|
|
|
|
|
|
|
|
|
return await _channel.invokeMethod('startAdvertising', <String, dynamic>{
|
|
|
|
|
'userNickName': userNickName,
|
|
|
|
|
'strategy': strategy.index,
|
|
|
|
|
'serviceId': serviceId,
|
|
|
|
|
});
|
|
|
|
|
'userNickName': userNickName,
|
|
|
|
|
'strategy': strategy.index,
|
|
|
|
|
'serviceId': serviceId,
|
|
|
|
|
}) ??
|
|
|
|
|
false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Stop Advertising
|
|
|
|
@ -236,19 +238,19 @@ class Nearby {
|
|
|
|
|
Future<bool> startDiscovery(
|
|
|
|
|
String userNickName,
|
|
|
|
|
Strategy strategy, {
|
|
|
|
|
@required OnEndpointFound onEndpointFound,
|
|
|
|
|
@required OnEndpointLost onEndpointLost,
|
|
|
|
|
required OnEndpointFound onEndpointFound,
|
|
|
|
|
required OnEndpointLost onEndpointLost,
|
|
|
|
|
String serviceId = "com.pkmnapps.nearby_connections",
|
|
|
|
|
}) async {
|
|
|
|
|
assert(userNickName != null && strategy != null && serviceId != null);
|
|
|
|
|
this._onEndpointFound = onEndpointFound;
|
|
|
|
|
this._onEndpointLost = onEndpointLost;
|
|
|
|
|
|
|
|
|
|
return await _channel.invokeMethod('startDiscovery', <String, dynamic>{
|
|
|
|
|
'userNickName': userNickName,
|
|
|
|
|
'strategy': strategy.index,
|
|
|
|
|
'serviceId': serviceId,
|
|
|
|
|
});
|
|
|
|
|
'userNickName': userNickName,
|
|
|
|
|
'strategy': strategy.index,
|
|
|
|
|
'serviceId': serviceId,
|
|
|
|
|
}) ??
|
|
|
|
|
false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Stop Discovery
|
|
|
|
@ -278,7 +280,6 @@ class Nearby {
|
|
|
|
|
/// this will call the onDisconnected method on callbacks of
|
|
|
|
|
/// connected endPoint
|
|
|
|
|
Future<void> disconnectFromEndpoint(String endpointId) async {
|
|
|
|
|
assert(endpointId != null);
|
|
|
|
|
await _channel.invokeMethod(
|
|
|
|
|
'disconnectFromEndpoint', <String, dynamic>{'endpointId': endpointId});
|
|
|
|
|
}
|
|
|
|
@ -293,24 +294,22 @@ class Nearby {
|
|
|
|
|
Future<bool> requestConnection(
|
|
|
|
|
String userNickName,
|
|
|
|
|
String endpointId, {
|
|
|
|
|
@required OnConnectionInitiated onConnectionInitiated,
|
|
|
|
|
@required OnConnectionResult onConnectionResult,
|
|
|
|
|
@required OnDisconnected onDisconnected,
|
|
|
|
|
required OnConnectionInitiated onConnectionInitiated,
|
|
|
|
|
required OnConnectionResult onConnectionResult,
|
|
|
|
|
required OnDisconnected onDisconnected,
|
|
|
|
|
}) async {
|
|
|
|
|
this._discoverConnectionInitiated = onConnectionInitiated;
|
|
|
|
|
this._discoverConnectionResult = onConnectionResult;
|
|
|
|
|
this._discoverDisconnected = onDisconnected;
|
|
|
|
|
|
|
|
|
|
assert(endpointId != null);
|
|
|
|
|
assert(userNickName != null);
|
|
|
|
|
|
|
|
|
|
return await _channel.invokeMethod(
|
|
|
|
|
'requestConnection',
|
|
|
|
|
<String, dynamic>{
|
|
|
|
|
'userNickName': userNickName,
|
|
|
|
|
'endpointId': endpointId,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
'requestConnection',
|
|
|
|
|
<String, dynamic>{
|
|
|
|
|
'userNickName': userNickName,
|
|
|
|
|
'endpointId': endpointId,
|
|
|
|
|
},
|
|
|
|
|
) ??
|
|
|
|
|
false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Needs be called by both discoverer and advertiser
|
|
|
|
@ -323,20 +322,19 @@ class Nearby {
|
|
|
|
|
/// only if both of them accept the connection
|
|
|
|
|
Future<bool> acceptConnection(
|
|
|
|
|
String endpointId, {
|
|
|
|
|
@required OnPayloadReceived onPayLoadRecieved,
|
|
|
|
|
OnPayloadTransferUpdate onPayloadTransferUpdate,
|
|
|
|
|
required OnPayloadReceived onPayLoadRecieved,
|
|
|
|
|
OnPayloadTransferUpdate? onPayloadTransferUpdate,
|
|
|
|
|
}) async {
|
|
|
|
|
this._onPayloadReceived = onPayLoadRecieved;
|
|
|
|
|
this._onPayloadTransferUpdate = onPayloadTransferUpdate;
|
|
|
|
|
|
|
|
|
|
assert(endpointId != null);
|
|
|
|
|
|
|
|
|
|
return await _channel.invokeMethod(
|
|
|
|
|
'acceptConnection',
|
|
|
|
|
<String, dynamic>{
|
|
|
|
|
'endpointId': endpointId,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
'acceptConnection',
|
|
|
|
|
<String, dynamic>{
|
|
|
|
|
'endpointId': endpointId,
|
|
|
|
|
},
|
|
|
|
|
) ??
|
|
|
|
|
false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Reject Connection
|
|
|
|
@ -349,14 +347,13 @@ class Nearby {
|
|
|
|
|
/// [OnConnectionResult] is called on both
|
|
|
|
|
/// even if one of them rejects the connection
|
|
|
|
|
Future<bool> rejectConnection(String endpointId) async {
|
|
|
|
|
assert(endpointId != null);
|
|
|
|
|
|
|
|
|
|
return await _channel.invokeMethod(
|
|
|
|
|
'rejectConnection',
|
|
|
|
|
<String, dynamic>{
|
|
|
|
|
'endpointId': endpointId,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
'rejectConnection',
|
|
|
|
|
<String, dynamic>{
|
|
|
|
|
'endpointId': endpointId,
|
|
|
|
|
},
|
|
|
|
|
) ??
|
|
|
|
|
false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Send bytes [Uint8List] payload to endpoint
|
|
|
|
@ -374,8 +371,6 @@ class Nearby {
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
Future<void> sendBytesPayload(String endpointId, Uint8List bytes) async {
|
|
|
|
|
assert(endpointId != null);
|
|
|
|
|
|
|
|
|
|
return await _channel.invokeMethod(
|
|
|
|
|
'sendPayload',
|
|
|
|
|
<String, dynamic>{
|
|
|
|
@ -392,9 +387,7 @@ class Nearby {
|
|
|
|
|
/// You must also send a bytes payload to send the filename and extension
|
|
|
|
|
/// so that receiver can rename the file accordingly
|
|
|
|
|
/// Send the payloadID and filename to receiver as bytes payload
|
|
|
|
|
Future<int> sendFilePayload(String endpointId, String filePath) async {
|
|
|
|
|
assert(endpointId != null);
|
|
|
|
|
|
|
|
|
|
Future<int?> sendFilePayload(String endpointId, String filePath) async {
|
|
|
|
|
return await _channel.invokeMethod(
|
|
|
|
|
'sendFilePayload',
|
|
|
|
|
<String, dynamic>{
|
|
|
|
@ -406,8 +399,6 @@ class Nearby {
|
|
|
|
|
|
|
|
|
|
/// Use it to cancel/stop a payload transfer
|
|
|
|
|
Future<void> cancelPayload(int payloadId) async {
|
|
|
|
|
assert(payloadId != null);
|
|
|
|
|
|
|
|
|
|
return await _channel.invokeMethod(
|
|
|
|
|
'cancelPayload',
|
|
|
|
|
<String, dynamic>{
|
|
|
|
|