Prep for new Release

TODO: add a way to edit the filename
This commit is contained in:
Prerak Mann 2019-08-12 00:03:47 +05:30
parent 73ab07452c
commit 4d666c42a5
11 changed files with 489 additions and 453 deletions

View File

@ -1,3 +1,9 @@
## 1.0.0
* Added support for Files (sendFilePayload)
* Breaking Change (sendPayload method signature is changed)
* Updated Example and Readme for file transfer
## 0.1.3+1 ## 0.1.3+1
* Update documentation and Readme * Update documentation and Readme

View File

@ -13,6 +13,7 @@ An **android** flutter plugin for the Nearby Connections API
* [Accept Connection](#accept-connection) * [Accept Connection](#accept-connection)
* [Sending Data](#sending-data) * [Sending Data](#sending-data)
* [Sending Bytes Payload](#sending-bytes-payload) * [Sending Bytes Payload](#sending-bytes-payload)
* [Sending Files](#sending-file-payload)
## Setup ## Setup
@ -120,7 +121,23 @@ Nearby().acceptConnection(
### Sending Bytes Payload ### Sending Bytes Payload
```dart ```dart
Nearby().sendPayload(endpointId, bytes_array); Nearby().sendBytesPayload(endpointId, bytes_array);
// payloads are recieved by callback given to acceptConnection method.
```
### Sending File Payload
You need to send the File Payload and File Name seperately.
File is stored in DOWNLOAD_DIRECTORY and given a generic name
So you would need to rename the file on receivers end.
```dart
//creates file with generic name (without extension) in Downloads Directory
Nearby().sendFilePayload(endpointId, filePath);
//Send filename as well so that receiver can rename the file
Nearby().sendBytesPayload(endpointId,fileNameEncoded);
// payloads are recieved by callback given to acceptConnection method. // payloads are recieved by callback given to acceptConnection method.
``` ```

View File

@ -78,12 +78,12 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
result.success(null); result.success(null);
break; break;
case "stopAdvertising": case "stopAdvertising":
Log.d("NearbyCon java", "stopAdvertising"); Log.d("nearby_connections", "stopAdvertising");
Nearby.getConnectionsClient(activity).stopAdvertising(); Nearby.getConnectionsClient(activity).stopAdvertising();
result.success(null); result.success(null);
break; break;
case "stopDiscovery": case "stopDiscovery":
Log.d("NearbyCon java", "stopDiscovery"); Log.d("nearby_connections", "stopDiscovery");
Nearby.getConnectionsClient(activity).stopDiscovery(); Nearby.getConnectionsClient(activity).stopDiscovery();
result.success(null); result.success(null);
break; break;
@ -101,7 +101,7 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
.addOnSuccessListener(new OnSuccessListener<Void>() { .addOnSuccessListener(new OnSuccessListener<Void>() {
@Override @Override
public void onSuccess(Void aVoid) { public void onSuccess(Void aVoid) {
Log.d("NearbyCon java", "startAdvertising"); Log.d("nearby_connections", "startAdvertising");
result.success(true); result.success(true);
} }
}) })
@ -125,7 +125,7 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
.addOnSuccessListener(new OnSuccessListener<Void>() { .addOnSuccessListener(new OnSuccessListener<Void>() {
@Override @Override
public void onSuccess(Void aVoid) { public void onSuccess(Void aVoid) {
Log.d("NearbyCon java", "startDiscovery"); Log.d("nearby_connections", "startDiscovery");
result.success(true); result.success(true);
} }
}) })
@ -138,12 +138,12 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
break; break;
} }
case "stopAllEndpoints": case "stopAllEndpoints":
Log.d("NearbyCon java", "stopAllEndpoints"); Log.d("nearby_connections", "stopAllEndpoints");
Nearby.getConnectionsClient(activity).stopAllEndpoints(); Nearby.getConnectionsClient(activity).stopAllEndpoints();
result.success(null); result.success(null);
break; break;
case "disconnectFromEndpoint": { case "disconnectFromEndpoint": {
Log.d("NearbyCon java", "disconnectFromEndpoint"); Log.d("nearby_connections", "disconnectFromEndpoint");
String endpointId = call.argument("endpointId"); String endpointId = call.argument("endpointId");
assert endpointId != null; assert endpointId != null;
Nearby.getConnectionsClient(activity).disconnectFromEndpoint(endpointId); Nearby.getConnectionsClient(activity).disconnectFromEndpoint(endpointId);
@ -151,7 +151,7 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
break; break;
} }
case "requestConnection": { case "requestConnection": {
Log.d("NearbyCon java", "requestConnection"); Log.d("nearby_connections", "requestConnection");
String userNickName = (String) call.argument("userNickName"); String userNickName = (String) call.argument("userNickName");
String endpointId = (String) call.argument("endpointId"); String endpointId = (String) call.argument("endpointId");
@ -220,7 +220,7 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
assert endpointId != null; assert endpointId != null;
assert bytes != null; assert bytes != null;
Nearby.getConnectionsClient(activity).sendPayload(endpointId, Payload.fromBytes(bytes)); Nearby.getConnectionsClient(activity).sendPayload(endpointId, Payload.fromBytes(bytes));
Log.d("NearbyCon java", "sentPayload"); Log.d("nearby_connections", "sentPayload");
result.success(true); result.success(true);
break; break;
} }
@ -236,10 +236,10 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
Payload filePayload = Payload.fromFile(file); Payload filePayload = Payload.fromFile(file);
Nearby.getConnectionsClient(activity).sendPayload(endpointId, filePayload); Nearby.getConnectionsClient(activity).sendPayload(endpointId, filePayload);
Log.d("NearbyCon java", "sentFilePayload"); Log.d("nearby_connections", "sentFilePayload");
result.success(filePayload.getId()); //return payload id to dart result.success(filePayload.getId()); //return payload id to dart
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
Log.e("NearbyCon java", "File not found", e); Log.e("nearby_connections", "File not found", e);
result.error("Failure", "File Not found", null); result.error("Failure", "File Not found", null);
return; return;
} }
@ -253,7 +253,7 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
private final ConnectionLifecycleCallback advertConnectionLifecycleCallback = new ConnectionLifecycleCallback() { private final ConnectionLifecycleCallback advertConnectionLifecycleCallback = new ConnectionLifecycleCallback() {
@Override @Override
public void onConnectionInitiated(@NonNull String endpointId, @NonNull ConnectionInfo connectionInfo) { public void onConnectionInitiated(@NonNull String endpointId, @NonNull ConnectionInfo connectionInfo) {
Log.d("NearbyCon java", "ad.onConnectionInitiated"); Log.d("nearby_connections", "ad.onConnectionInitiated");
Map<String, Object> args = new HashMap<>(); Map<String, Object> args = new HashMap<>();
args.put("endpointId", endpointId); args.put("endpointId", endpointId);
args.put("endpointName", connectionInfo.getEndpointName()); args.put("endpointName", connectionInfo.getEndpointName());
@ -264,7 +264,7 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
@Override @Override
public void onConnectionResult(@NonNull String endpointId, @NonNull ConnectionResolution connectionResolution) { public void onConnectionResult(@NonNull String endpointId, @NonNull ConnectionResolution connectionResolution) {
Log.d("NearbyCon java", "ad.onConnectionResult"); Log.d("nearby_connections", "ad.onConnectionResult");
Map<String, Object> args = new HashMap<>(); Map<String, Object> args = new HashMap<>();
args.put("endpointId", endpointId); args.put("endpointId", endpointId);
int statusCode = -1; int statusCode = -1;
@ -290,7 +290,7 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
@Override @Override
public void onDisconnected(@NonNull String endpointId) { public void onDisconnected(@NonNull String endpointId) {
Log.d("NearbyCon java", "ad.onDisconnected"); Log.d("nearby_connections", "ad.onDisconnected");
Map<String, Object> args = new HashMap<>(); Map<String, Object> args = new HashMap<>();
args.put("endpointId", endpointId); args.put("endpointId", endpointId);
channel.invokeMethod("ad.onDisconnected", args); channel.invokeMethod("ad.onDisconnected", args);
@ -300,7 +300,7 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
private final ConnectionLifecycleCallback discoverConnectionLifecycleCallback = new ConnectionLifecycleCallback() { private final ConnectionLifecycleCallback discoverConnectionLifecycleCallback = new ConnectionLifecycleCallback() {
@Override @Override
public void onConnectionInitiated(@NonNull String endpointId, @NonNull ConnectionInfo connectionInfo) { public void onConnectionInitiated(@NonNull String endpointId, @NonNull ConnectionInfo connectionInfo) {
Log.d("NearbyCon java", "dis.onConnectionInitiated"); Log.d("nearby_connections", "dis.onConnectionInitiated");
Map<String, Object> args = new HashMap<>(); Map<String, Object> args = new HashMap<>();
args.put("endpointId", endpointId); args.put("endpointId", endpointId);
args.put("endpointName", connectionInfo.getEndpointName()); args.put("endpointName", connectionInfo.getEndpointName());
@ -311,7 +311,7 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
@Override @Override
public void onConnectionResult(@NonNull String endpointId, @NonNull ConnectionResolution connectionResolution) { public void onConnectionResult(@NonNull String endpointId, @NonNull ConnectionResolution connectionResolution) {
Log.d("NearbyCon java", "dis.onConnectionResult"); Log.d("nearby_connections", "dis.onConnectionResult");
Map<String, Object> args = new HashMap<>(); Map<String, Object> args = new HashMap<>();
args.put("endpointId", endpointId); args.put("endpointId", endpointId);
int statusCode = -1; int statusCode = -1;
@ -337,7 +337,7 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
@Override @Override
public void onDisconnected(@NonNull String endpointId) { public void onDisconnected(@NonNull String endpointId) {
Log.d("NearbyCon java", "dis.onDisconnected"); Log.d("nearby_connections", "dis.onDisconnected");
Map<String, Object> args = new HashMap<>(); Map<String, Object> args = new HashMap<>();
args.put("endpointId", endpointId); args.put("endpointId", endpointId);
channel.invokeMethod("dis.onDisconnected", args); channel.invokeMethod("dis.onDisconnected", args);
@ -347,7 +347,7 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
private final PayloadCallback payloadCallback = new PayloadCallback() { private final PayloadCallback payloadCallback = new PayloadCallback() {
@Override @Override
public void onPayloadReceived(@NonNull String endpointId, @NonNull Payload payload) { public void onPayloadReceived(@NonNull String endpointId, @NonNull Payload payload) {
Log.d("NearbyCon java", "onPayloadReceived"); Log.d("nearby_connections", "onPayloadReceived");
Map<String, Object> args = new HashMap<>(); Map<String, Object> args = new HashMap<>();
args.put("endpointId", endpointId); args.put("endpointId", endpointId);
args.put("payloadId", payload.getId()); args.put("payloadId", payload.getId());
@ -366,7 +366,7 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
public void onPayloadTransferUpdate(@NonNull String endpointId, @NonNull PayloadTransferUpdate payloadTransferUpdate) { public void onPayloadTransferUpdate(@NonNull String endpointId, @NonNull PayloadTransferUpdate payloadTransferUpdate) {
//required for files and streams //required for files and streams
Log.d("NearbyCon java", "onPayloadTransferUpdate"); Log.d("nearby_connections", "onPayloadTransferUpdate");
Map<String, Object> args = new HashMap<>(); Map<String, Object> args = new HashMap<>();
args.put("endpointId", endpointId); args.put("endpointId", endpointId);
args.put("payloadId", payloadTransferUpdate.getPayloadId()); args.put("payloadId", payloadTransferUpdate.getPayloadId());
@ -381,7 +381,7 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
private final EndpointDiscoveryCallback endpointDiscoveryCallback = new EndpointDiscoveryCallback() { private final EndpointDiscoveryCallback endpointDiscoveryCallback = new EndpointDiscoveryCallback() {
@Override @Override
public void onEndpointFound(@NonNull String endpointId, @NonNull DiscoveredEndpointInfo discoveredEndpointInfo) { public void onEndpointFound(@NonNull String endpointId, @NonNull DiscoveredEndpointInfo discoveredEndpointInfo) {
Log.d("NearbyCon java", "onEndpointFound"); Log.d("nearby_connections", "onEndpointFound");
Map<String, Object> args = new HashMap<>(); Map<String, Object> args = new HashMap<>();
args.put("endpointId", endpointId); args.put("endpointId", endpointId);
args.put("endpointName", discoveredEndpointInfo.getEndpointName()); args.put("endpointName", discoveredEndpointInfo.getEndpointName());
@ -391,7 +391,7 @@ public class NearbyConnectionsPlugin implements MethodCallHandler {
@Override @Override
public void onEndpointLost(@NonNull String endpointId) { public void onEndpointLost(@NonNull String endpointId) {
Log.d("NearbyCon java", "onEndpointLost"); Log.d("nearby_connections", "onEndpointLost");
Map<String, Object> args = new HashMap<>(); Map<String, Object> args = new HashMap<>();
args.put("endpointId", endpointId); args.put("endpointId", endpointId);
channel.invokeMethod("dis.onEndpointLost", args); channel.invokeMethod("dis.onEndpointLost", args);

View File

@ -32,7 +32,6 @@ android {
} }
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.pkmnapps.nearby_connections_example" applicationId "com.pkmnapps.nearby_connections_example"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 28 targetSdkVersion 28
@ -43,7 +42,6 @@ android {
buildTypes { buildTypes {
release { release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works. // Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug signingConfig signingConfigs.debug
} }

View File

@ -160,7 +160,7 @@ class _MyBodyState extends State<Body> {
onPressed: () async { onPressed: () async {
String a = Random().nextInt(100).toString(); String a = Random().nextInt(100).toString();
showSnackbar("Sending $a to $cId"); showSnackbar("Sending $a to $cId");
Nearby().sendPayload(cId, Uint8List.fromList(a.codeUnits)); Nearby().sendBytesPayload(cId, Uint8List.fromList(a.codeUnits));
}, },
), ),
RaisedButton( RaisedButton(

View File

@ -73,7 +73,7 @@ packages:
path: ".." path: ".."
relative: true relative: true
source: path source: path
version: "0.1.3+1" version: "1.0.0"
path: path:
dependency: transitive dependency: transitive
description: description:

View File

@ -1,427 +1,6 @@
import 'dart:async'; /// https://pub.dev/packages/nearby_connections#-readme-tab-
import 'dart:typed_data'; library nearby_connections;
import 'package:flutter/foundation.dart'; export 'src/classes.dart';
import 'package:flutter/services.dart'; export 'src/defs.dart';
export 'src/nearby_connections.dart';
/// **P2P_CLUSTER** - best for small payloads and multiplayer games
///
/// **P2P_STAR** - best for medium payloads, higher bandwidth than cluster
///
/// **P2P_POINT_TO_POINT** - single connection, very high bandwidth
enum Strategy { P2P_CLUSTER, P2P_STAR, P2P_POINT_TO_POINT }
enum Status { CONNECTED, REJECTED, ERROR }
enum PayloadStatus { NONE, SUCCESS, FAILURE, IN_PROGRRESS, CANCELED }
enum PayloadType { NONE, BYTES, FILE, STREAM }
typedef void OnConnctionInitiated(
String endpointId, ConnectionInfo connectionInfo);
typedef void OnConnectionResult(String endpointId, Status status);
typedef void OnDisconnected(String endpointId);
typedef void OnEndpointFound(
String endpointId, String endpointName, String serviceId);
typedef void OnEndpointLost(String endpointId);
/// Bytes may be null if [Payload.type] is not [PayloadType.BYTES]
class Payload {
int id;
PayloadType type;
Uint8List bytes;
Payload({
this.id,
this.bytes,
this.type = PayloadType.NONE,
});
}
/// gives payload status, bytes transfered and total bytes.
class PayloadTransferUpdate {
int id, bytesTransferred, totalBytes;
PayloadStatus status;
PayloadTransferUpdate({
this.id,
this.bytesTransferred,
this.totalBytes,
this.status = PayloadStatus.NONE,
});
}
/// For Bytes, this contains the bytes data
///
/// For File, this marks the start of transfer
///
/// Uint8List bytes may be null, if [type] is not [PayloadType.BYTES]
typedef void OnPayloadReceived(String endpointId, Payload payload);
/// Called only once for Bytes and repeatedly for File until transfer is complete
typedef void OnPayloadTransferUpdate(
String endpointId, PayloadTransferUpdate payloadTransferUpdate);
// typedef void OnPayloadTransferUpdate();
/// The NearbyConnection class
///
/// Only one instance is maintained
/// even on calling Nearby() multiple times
///
/// All methods are asynchronous.
class Nearby {
//for maintaining only 1 instance of this class
static Nearby _instance;
factory Nearby() {
if (_instance == null) {
_instance = Nearby._();
}
return _instance;
}
Nearby._() {
_channel.setMethodCallHandler((handler) {
print("=========in handler============");
Map<dynamic, dynamic> args = handler.arguments;
print(handler.method);
args.forEach((s, d) {
print(s + " : " + d.toString());
});
print("=====================");
switch (handler.method) {
case "ad.onConnectionInitiated":
String endpointId = args['endpointId'];
String endpointName = args['endpointName'];
String authenticationToken = args['authenticationToken'];
bool isIncomingConnection = args['isIncomingConnection'];
_advertConnectionInitiated?.call(
endpointId,
ConnectionInfo(
endpointName, authenticationToken, isIncomingConnection));
return null;
case "ad.onConnectionResult":
String endpointId = args['endpointId'];
Status statusCode = Status.values[args['statusCode']];
_advertConnectionResult?.call(endpointId, statusCode);
return null;
case "ad.onDisconnected":
String endpointId = args['endpointId'];
_advertDisconnected?.call(endpointId);
return null;
case "dis.onConnectionInitiated":
String endpointId = args['endpointId'];
String endpointName = args['endpointName'];
String authenticationToken = args['authenticationToken'];
bool isIncomingConnection = args['isIncomingConnection'];
_discoverConnectionInitiated?.call(
endpointId,
ConnectionInfo(
endpointName, authenticationToken, isIncomingConnection));
return null;
case "dis.onConnectionResult":
String endpointId = args['endpointId'];
Status statusCode = Status.values[args['statusCode']];
_discoverConnectionResult?.call(endpointId, statusCode);
return null;
case "dis.onDisconnected":
String endpointId = args['endpointId'];
_discoverDisconnected?.call(endpointId);
return null;
case "dis.onEndpointFound":
print("in switch");
String endpointId = args['endpointId'];
String endpointName = args['endpointName'];
String serviceId = args['serviceId'];
_onEndpointFound?.call(endpointId, endpointName, serviceId);
return null;
case "dis.onEndpointLost":
String endpointId = args['endpointId'];
_onEndpointLost?.call(endpointId);
return null;
case "onPayloadReceived":
String endpointId = args['endpointId'];
int type = args['type'];
Uint8List bytes = args['bytes'];
int payloadId = args['payloadId'];
Payload payload = Payload(
type: PayloadType.values[type],
bytes: bytes,
id: payloadId,
);
_onPayloadReceived?.call(endpointId, payload);
break;
case "onPayloadTransferUpdate":
String endpointId = args['endpointId'];
int payloadId = args['payloadId'];
int status = args['status'];
int bytesTransferred = args['bytesTransferred'];
int totalBytes = args['totalBytes'];
PayloadTransferUpdate payloadTransferUpdate = PayloadTransferUpdate(
id: payloadId,
status: PayloadStatus.values[status],
bytesTransferred: bytesTransferred,
totalBytes: totalBytes,
);
_onPayloadTransferUpdate?.call(endpointId, payloadTransferUpdate);
break;
}
return null;
});
}
OnConnctionInitiated _advertConnectionInitiated, _discoverConnectionInitiated;
OnConnectionResult _advertConnectionResult, _discoverConnectionResult;
OnDisconnected _advertDisconnected, _discoverDisconnected;
OnEndpointFound _onEndpointFound;
OnEndpointLost _onEndpointLost;
OnPayloadReceived _onPayloadReceived;
OnPayloadTransferUpdate _onPayloadTransferUpdate;
static const MethodChannel _channel =
const MethodChannel('nearby_connections');
/// Convinience method
///
/// retruns true/false based on location permissions.
/// Discovery cannot be started with insufficient permission
Future<bool> checkPermissions() async => await _channel.invokeMethod(
'checkPermissions',
);
/// Convinience method
///
/// Asks location permission
Future<void> askPermission() async {
await _channel.invokeMethod(
'askPermissions',
);
}
/// Start Advertising
///
/// [userNickName] and [strategy] should not be null
Future<bool> startAdvertising(
String userNickName,
Strategy strategy, {
@required OnConnctionInitiated onConnectionInitiated,
@required OnConnectionResult onConnectionResult,
@required OnDisconnected onDisconnected,
}) async {
assert(userNickName != null && strategy != null);
this._advertConnectionInitiated = onConnectionInitiated;
this._advertConnectionResult = onConnectionResult;
this._advertDisconnected = onDisconnected;
return await _channel.invokeMethod('startAdvertising', <String, dynamic>{
'userNickName': userNickName,
'strategy': strategy.index
});
}
/// Stop Advertising
///
/// This doesn't disconnect from any connected Endpoint
///
/// For disconnection use
/// [stopAllEndpoints] or [disconnectFromEndpoint]
Future<void> stopAdvertising() async {
await _channel.invokeMethod('stopAdvertising');
}
/// Start Discovery
///
/// [userNickName] and [strategy] should not be null
Future<bool> startDiscovery(
String userNickName,
Strategy strategy, {
@required OnEndpointFound onEndpointFound,
@required OnEndpointLost onEndpointLost,
}) async {
assert(userNickName != null && strategy != null);
this._onEndpointFound = onEndpointFound;
this._onEndpointLost = onEndpointLost;
return await _channel.invokeMethod('startDiscovery', <String, dynamic>{
'userNickName': userNickName,
'strategy': strategy.index
});
}
/// Stop Discovery
///
/// This doesn't disconnect from any connected Endpoint
///
/// It is reccomended to call this method
/// once you have connected to an endPoint
/// as it uses heavy radio operations
/// which may affect connection speed and integrity
Future<void> stopDiscovery() async {
await _channel.invokeMethod('stopDiscovery');
}
/// Stop All Endpoints
///
/// Disconnects all connections,
/// this will call the onDisconnected method on callbacks of
/// all connected endPoints
Future<void> stopAllEndpoints() async {
await _channel.invokeMethod('stopAllEndpoints');
}
/// Disconnect from Endpoints
///
/// Disconnects the connections to given endPointId
/// this will call the onDisconnected method on callbacks of
/// connected endPoint
Future<void> disconnectFromEndpoint(String endpointId) async {
await _channel.invokeMethod(
'disconnectFromEndpoint', <String, dynamic>{'endpointId': endpointId});
}
/// Request Connection
///
/// Call this method when Discoverer calls the
/// [OnEndpointFound] method
///
/// This will call the [OnConnctionInitiated] method on
/// both the endPoint and this
Future<bool> requestConnection(
String userNickName,
String endpointId, {
@required OnConnctionInitiated onConnectionInitiated,
@required OnConnectionResult onConnectionResult,
@required OnDisconnected onDisconnected,
}) async {
this._discoverConnectionInitiated = onConnectionInitiated;
this._discoverConnectionResult = onConnectionResult;
this._discoverDisconnected = onDisconnected;
return await _channel.invokeMethod(
'requestConnection',
<String, dynamic>{
'userNickName': userNickName,
'endpointId': endpointId,
},
);
}
/// Needs be called by both discoverer and advertiser
/// to connect
///
/// Call this in [OnConnctionInitiated]
/// to accept an incoming connection
///
/// [OnConnectionResult] is called on both
/// only if both of them accept the connection
Future<bool> acceptConnection(
String endpointId, {
@required OnPayloadReceived onPayLoadRecieved,
OnPayloadTransferUpdate onPayloadTransferUpdate,
}) async {
this._onPayloadReceived = onPayLoadRecieved;
this._onPayloadTransferUpdate = onPayloadTransferUpdate;
return await _channel.invokeMethod(
'acceptConnection',
<String, dynamic>{
'endpointId': endpointId,
},
);
}
/// Reject Connection
///
/// To be called by both discoverer and advertiser
///
/// Call this in [OnConnctionInitiated]
/// to reject an incoming connection
///
/// [OnConnectionResult] is called on both
/// even if one of them rejects the connection
Future<bool> rejectConnection(String endpointId) async {
return await _channel.invokeMethod(
'rejectConnection',
<String, dynamic>{
'endpointId': endpointId,
},
);
}
/// Send bytes [Uint8List] payload to endpoint
///
/// Convert String to Uint8List as follows
///
/// ```dart
/// String a = "hello";
/// Uint8List bytes = Uint8List.fromList(a.codeUnits);
/// ```
Future<void> sendPayload(String endpointId, Uint8List bytes) async {
return await _channel.invokeMethod(
'sendPayload',
<String, dynamic>{
'endpointId': endpointId,
'bytes': bytes,
},
);
}
/// Returns the payloadID as soon as file transfer has begun
///
/// File is received in DOWNLOADS_DIRECTORY and is given a generic name
/// without extension
/// 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 {
return await _channel.invokeMethod(
'sendFilePayload',
<String, dynamic>{
'endpointId': endpointId,
'filePath': filePath,
},
);
}
}
/// ConnectionInfo class
///
/// Its a parameter in [OnConnctionInitiated]
///
/// [endPointName] is userNickName of requester
///
/// [authenticationToken] can be used to check the connection security
/// it must be same on both devices
class ConnectionInfo {
String endpointName, authenticationToken;
bool isIncomingConnection;
ConnectionInfo(
this.endpointName, this.authenticationToken, this.isIncomingConnection);
}
//TODO remove errors on failure for smooth experience
//TODO expose only relevant parts as library
//TODO publish to pub.dartlang

45
lib/src/classes.dart Normal file
View File

@ -0,0 +1,45 @@
// contains custom classes
import 'dart:typed_data';
import 'package:nearby_connections/src/defs.dart';
/// Bytes may be null if [Payload.type] is not [PayloadType.BYTES]
class Payload {
int id;
PayloadType type;
Uint8List bytes;
Payload({
this.id,
this.bytes,
this.type = PayloadType.NONE,
});
}
class PayloadTransferUpdate {
int id, bytesTransferred, totalBytes;
PayloadStatus status;
PayloadTransferUpdate({
this.id,
this.bytesTransferred,
this.totalBytes,
this.status = PayloadStatus.NONE,
});
}
/// ConnectionInfo class
///
/// Its a parameter in [OnConnctionInitiated]
///
/// [endPointName] is userNickName of requester
///
/// [authenticationToken] can be used to check the connection security
/// it must be same on both devices
class ConnectionInfo {
String endpointName, authenticationToken;
bool isIncomingConnection;
ConnectionInfo(
this.endpointName, this.authenticationToken, this.isIncomingConnection);
}

46
lib/src/defs.dart Normal file
View File

@ -0,0 +1,46 @@
// contains enums and typedefs
import 'package:nearby_connections/src/classes.dart';
/// **P2P_CLUSTER** - best for small payloads and multiplayer games
///
/// **P2P_STAR** - best for medium payloads, higher bandwidth than cluster
///
/// **P2P_POINT_TO_POINT** - single connection, very high bandwidth
enum Strategy { P2P_CLUSTER, P2P_STAR, P2P_POINT_TO_POINT }
enum Status { CONNECTED, REJECTED, ERROR }
enum PayloadStatus { NONE, SUCCESS, FAILURE, IN_PROGRRESS, CANCELED }
enum PayloadType { NONE, BYTES, FILE, STREAM }
//
//
//
// Advertising lifecycle callbacks
//
typedef void OnConnctionInitiated(
String endpointId, ConnectionInfo connectionInfo);
typedef void OnConnectionResult(String endpointId, Status status);
typedef void OnDisconnected(String endpointId);
//
//
//
// Discovery lifecycle callbacks
//
typedef void OnEndpointFound(
String endpointId, String endpointName, String serviceId);
typedef void OnEndpointLost(String endpointId);
//
//
//
/// For Bytes, this contains the bytes data
///
/// For File, this marks the start of transfer
///
/// Uint8List bytes may be null, if [type] is not [PayloadType.BYTES]
typedef void OnPayloadReceived(String endpointId, Payload payload);
/// Called only once for Bytes and repeatedly for File until transfer is complete
typedef void OnPayloadTransferUpdate(
String endpointId, PayloadTransferUpdate payloadTransferUpdate);

View File

@ -0,0 +1,345 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:nearby_connections/src/defs.dart';
import 'package:nearby_connections/src/classes.dart';
/// The NearbyConnection class
///
/// Only one instance is maintained
/// even on calling Nearby() multiple times
///
/// All methods are asynchronous.
class Nearby {
//Singleton pattern for maintaining only 1 instance of this class
static Nearby _instance;
factory Nearby() {
if (_instance == null) {
_instance = Nearby._();
}
return _instance;
}
Nearby._() {
_channel.setMethodCallHandler((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'];
_advertConnectionInitiated?.call(
endpointId,
ConnectionInfo(
endpointName, authenticationToken, isIncomingConnection));
return null;
case "ad.onConnectionResult":
String endpointId = args['endpointId'];
Status statusCode = Status.values[args['statusCode']];
_advertConnectionResult?.call(endpointId, statusCode);
return null;
case "ad.onDisconnected":
String endpointId = args['endpointId'];
_advertDisconnected?.call(endpointId);
return null;
case "dis.onConnectionInitiated":
String endpointId = args['endpointId'];
String endpointName = args['endpointName'];
String authenticationToken = args['authenticationToken'];
bool isIncomingConnection = args['isIncomingConnection'];
_discoverConnectionInitiated?.call(
endpointId,
ConnectionInfo(
endpointName, authenticationToken, isIncomingConnection));
return null;
case "dis.onConnectionResult":
String endpointId = args['endpointId'];
Status statusCode = Status.values[args['statusCode']];
_discoverConnectionResult?.call(endpointId, statusCode);
return null;
case "dis.onDisconnected":
String endpointId = args['endpointId'];
_discoverDisconnected?.call(endpointId);
return null;
case "dis.onEndpointFound":
String endpointId = args['endpointId'];
String endpointName = args['endpointName'];
String serviceId = args['serviceId'];
_onEndpointFound?.call(endpointId, endpointName, serviceId);
return null;
case "dis.onEndpointLost":
String endpointId = args['endpointId'];
_onEndpointLost?.call(endpointId);
return null;
case "onPayloadReceived":
String endpointId = args['endpointId'];
int type = args['type'];
Uint8List bytes = args['bytes'];
int payloadId = args['payloadId'];
Payload payload = Payload(
type: PayloadType.values[type],
bytes: bytes,
id: payloadId,
);
_onPayloadReceived?.call(endpointId, payload);
break;
case "onPayloadTransferUpdate":
String endpointId = args['endpointId'];
int payloadId = args['payloadId'];
int status = args['status'];
int bytesTransferred = args['bytesTransferred'];
int totalBytes = args['totalBytes'];
PayloadTransferUpdate payloadTransferUpdate = PayloadTransferUpdate(
id: payloadId,
status: PayloadStatus.values[status],
bytesTransferred: bytesTransferred,
totalBytes: totalBytes,
);
_onPayloadTransferUpdate?.call(endpointId, payloadTransferUpdate);
break;
}
return null;
});
}
//for advertisers
OnConnctionInitiated _advertConnectionInitiated, _discoverConnectionInitiated;
OnConnectionResult _advertConnectionResult, _discoverConnectionResult;
OnDisconnected _advertDisconnected, _discoverDisconnected;
//for discoverers
OnEndpointFound _onEndpointFound;
OnEndpointLost _onEndpointLost;
//for receiving payload
OnPayloadReceived _onPayloadReceived;
OnPayloadTransferUpdate _onPayloadTransferUpdate;
static const MethodChannel _channel =
const MethodChannel('nearby_connections');
/// Convinience method
///
/// retruns true/false based on location permissions.
/// Discovery cannot be started with insufficient permission
Future<bool> checkPermissions() async => await _channel.invokeMethod(
'checkPermissions',
);
/// Convinience method
///
/// Asks location permission
Future<void> askPermission() async => await _channel.invokeMethod(
'askPermissions',
);
/// Start Advertising
///
/// [userNickName] and [strategy] should not be null
Future<bool> startAdvertising(
String userNickName,
Strategy strategy, {
@required OnConnctionInitiated onConnectionInitiated,
@required OnConnectionResult onConnectionResult,
@required OnDisconnected onDisconnected,
}) async {
assert(userNickName != null && strategy != null);
this._advertConnectionInitiated = onConnectionInitiated;
this._advertConnectionResult = onConnectionResult;
this._advertDisconnected = onDisconnected;
return await _channel.invokeMethod('startAdvertising', <String, dynamic>{
'userNickName': userNickName,
'strategy': strategy.index
});
}
/// Stop Advertising
///
/// This doesn't disconnect from any connected Endpoint
///
/// For disconnection use
/// [stopAllEndpoints] or [disconnectFromEndpoint]
Future<void> stopAdvertising() async {
await _channel.invokeMethod('stopAdvertising');
}
/// Start Discovery
///
/// [userNickName] and [strategy] should not be null
Future<bool> startDiscovery(
String userNickName,
Strategy strategy, {
@required OnEndpointFound onEndpointFound,
@required OnEndpointLost onEndpointLost,
}) async {
assert(userNickName != null && strategy != null);
this._onEndpointFound = onEndpointFound;
this._onEndpointLost = onEndpointLost;
return await _channel.invokeMethod('startDiscovery', <String, dynamic>{
'userNickName': userNickName,
'strategy': strategy.index
});
}
/// Stop Discovery
///
/// This doesn't disconnect from already connected Endpoint
///
/// It is reccomended to call this method
/// once you have connected to an endPoint
/// as discovery uses heavy radio operations
/// which may affect connection speed and integrity
Future<void> stopDiscovery() async {
await _channel.invokeMethod('stopDiscovery');
}
/// Stop All Endpoints
///
/// Disconnects all connections,
/// this will call the onDisconnected method on callbacks of
/// all connected endPoints
Future<void> stopAllEndpoints() async {
await _channel.invokeMethod('stopAllEndpoints');
}
/// Disconnect from Endpoints
///
/// Disconnects the connections to given endPointId
/// this will call the onDisconnected method on callbacks of
/// connected endPoint
Future<void> disconnectFromEndpoint(String endpointId) async {
await _channel.invokeMethod(
'disconnectFromEndpoint', <String, dynamic>{'endpointId': endpointId});
}
/// Request Connection
///
/// Call this method when Discoverer calls the
/// [OnEndpointFound] method
///
/// This will call the [OnConnctionInitiated] method on
/// both the endPoint and this
Future<bool> requestConnection(
String userNickName,
String endpointId, {
@required OnConnctionInitiated onConnectionInitiated,
@required OnConnectionResult onConnectionResult,
@required OnDisconnected onDisconnected,
}) async {
this._discoverConnectionInitiated = onConnectionInitiated;
this._discoverConnectionResult = onConnectionResult;
this._discoverDisconnected = onDisconnected;
return await _channel.invokeMethod(
'requestConnection',
<String, dynamic>{
'userNickName': userNickName,
'endpointId': endpointId,
},
);
}
/// Needs be called by both discoverer and advertiser
/// to connect
///
/// Call this in [OnConnctionInitiated]
/// to accept an incoming connection
///
/// [OnConnectionResult] is called on both
/// only if both of them accept the connection
Future<bool> acceptConnection(
String endpointId, {
@required OnPayloadReceived onPayLoadRecieved,
OnPayloadTransferUpdate onPayloadTransferUpdate,
}) async {
this._onPayloadReceived = onPayLoadRecieved;
this._onPayloadTransferUpdate = onPayloadTransferUpdate;
return await _channel.invokeMethod(
'acceptConnection',
<String, dynamic>{
'endpointId': endpointId,
},
);
}
/// Reject Connection
///
/// To be called by both discoverer and advertiser
///
/// Call this in [OnConnctionInitiated]
/// to reject an incoming connection
///
/// [OnConnectionResult] is called on both
/// even if one of them rejects the connection
Future<bool> rejectConnection(String endpointId) async {
return await _channel.invokeMethod(
'rejectConnection',
<String, dynamic>{
'endpointId': endpointId,
},
);
}
/// Send bytes [Uint8List] payload to endpoint
///
/// Convert String to Uint8List as follows
///
/// ```dart
/// String a = "hello";
/// Uint8List bytes = Uint8List.fromList(a.codeUnits);
/// ```
Future<void> sendBytesPayload(String endpointId, Uint8List bytes) async {
return await _channel.invokeMethod(
'sendPayload',
<String, dynamic>{
'endpointId': endpointId,
'bytes': bytes,
},
);
}
/// Returns the payloadID as soon as file transfer has begun
///
/// File is received in DOWNLOADS_DIRECTORY and is given a generic name
/// without extension
/// 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 {
return await _channel.invokeMethod(
'sendFilePayload',
<String, dynamic>{
'endpointId': endpointId,
'filePath': filePath,
},
);
}
}

View File

@ -1,6 +1,6 @@
name: nearby_connections name: nearby_connections
description: Plugin for the android NearbyConnections API. Currently sending bytes (Uint8List) is possible. description: Plugin for the android NearbyConnections API. Bytes and Files Supported.
version: 0.1.3+1 version: 1.0.0
author: Prerak Mann <mannprerak2@gmail.com> author: Prerak Mann <mannprerak2@gmail.com>
homepage: https://github.com/mannprerak2/nearby_connections homepage: https://github.com/mannprerak2/nearby_connections