diff --git a/CHANGELOG.md b/CHANGELOG.md index ba8f903..96d20f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.3 + +* Update send message function + ## 0.0.2 * fix static analysis. diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 40d8fdd..62d6e10 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -257,6 +257,7 @@ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", "${PODS_ROOT}/../Flutter/Flutter.framework", "${BUILT_PRODUCTS_DIR}/SwiftyJSON/SwiftyJSON.framework", + "${BUILT_PRODUCTS_DIR}/Toast/Toast.framework", "${BUILT_PRODUCTS_DIR}/flutter_nearby_connections/flutter_nearby_connections.framework", "${BUILT_PRODUCTS_DIR}/fluttertoast/fluttertoast.framework", ); @@ -264,6 +265,7 @@ outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyJSON.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Toast.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_nearby_connections.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/fluttertoast.framework", ); diff --git a/example/lib/main.dart b/example/lib/main.dart index 19cfef8..daec07d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_nearby_connections/flutter_nearby_connections.dart'; import 'package:fluttertoast/fluttertoast.dart'; @@ -112,10 +113,8 @@ class _DevicesListScreenState extends State { }); }); - receivedDataSubscription = - nearbyService.dataReceivedSubscription(callback: (data) { - Fluttertoast.showToast( - msg: "Device ID: ${data.deviceID} , message: ${data.message}"); + receivedDataSubscription = nearbyService.dataReceivedSubscription(callback: (data) { + Fluttertoast.showToast(msg: jsonEncode(data)); }); if (widget.deviceType == DeviceType.browser) { @@ -265,8 +264,8 @@ class _DevicesListScreenState extends State { FlatButton( child: Text("Send"), onPressed: () { - nearbyService.sendMessage( - device.deviceID, myController.text); + String jsonData = '{ "message": \" ${myController.text}\" }'; + nearbyService.sendMessage(device.deviceID, jsonDecode(jsonData)); myController.text = ''; }, ) diff --git a/ios/Classes/Device.swift b/ios/Classes/Device.swift index 9df84af..229d17e 100644 --- a/ios/Classes/Device.swift +++ b/ios/Classes/Device.swift @@ -1,6 +1,6 @@ import Foundation import MultipeerConnectivity - +import SwiftyJSON class Device: NSObject { let peerID: MCPeerID var session: MCSession? @@ -43,10 +43,7 @@ extension Device: MCSessionDelegate { } public func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) { - if let message = try? JSONDecoder().decode(Message.self, from: data) { - self.lastMessageReceived = message - NotificationCenter.default.post(name: Device.messageReceivedNotification, object: nil, userInfo: ["from": peerID]) - } + NotificationCenter.default.post(name: Device.messageReceivedNotification, object: nil, userInfo: ["from": peerID, "data": data]) } public func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) { } diff --git a/ios/Classes/Message.swift b/ios/Classes/Message.swift index f0aeee6..3eb1a04 100644 --- a/ios/Classes/Message.swift +++ b/ios/Classes/Message.swift @@ -6,6 +6,7 @@ // import Foundation +import SwiftyJSON struct Message: Codable { let body: String @@ -13,8 +14,67 @@ struct Message: Codable { extension Device { func send(text: String) throws { - let message = Message(body: text) - let payload = try JSONEncoder().encode(message) - try self.session?.send(payload, toPeers: [self.peerID], with: .reliable) + try self.session?.send(text.data(using: .utf8) ?? Data(), toPeers: [self.peerID], with: .reliable) + } + + func send(json: JSON) throws { + try self.session?.send(json.rawData(), toPeers: [self.peerID], with: .reliable) + } + + func send(data: Data) throws { + try self.session?.send(data, toPeers: [self.peerID], with: .reliable) + } +} + +struct ReceivedResponse { + var deviceID: String? + var message: MessageReponse + + init(json: JSON) { + deviceID = json["deviceID"].string + message = MessageReponse(json: json["message"]) } } + +struct MessageReponse { + var items: [MessageResponseItem] = [] + var subTotal: NSNumber? + var rounding: NSNumber? + var total: NSNumber? + + init(json: JSON) { + items = json["items"].array?.compactMap({return MessageResponseItem(json: $0)}) ?? [] + subTotal = json["subTotal"].number + rounding = json["rounding"].number + total = json["total"].number + } +} + +struct MessageResponseItem { + var quantity: NSNumber? + var itemCollection: MessageItemCollection? + + init(json: JSON) { + quantity = json["quantity"].number + itemCollection = MessageItemCollection(json: json["itemCollection"]) + } +} + +struct MessageItemCollection { + var name: String? + var status: MessageItemCollectionStatus? + var imageUrl: String? + var price: NSNumber? + + init(json: JSON) { + name = json["name"].string + status = MessageItemCollectionStatus(rawValue: json["status"].stringValue) + imageUrl = json["imageUrl"].string + price = json["price"].number + } +} + +enum MessageItemCollectionStatus: String { + case active = "ACTIVE" +} + diff --git a/ios/Classes/SwiftFlutterNearbyConnectionsPlugin.swift b/ios/Classes/SwiftFlutterNearbyConnectionsPlugin.swift index 0575f00..9d40658 100644 --- a/ios/Classes/SwiftFlutterNearbyConnectionsPlugin.swift +++ b/ios/Classes/SwiftFlutterNearbyConnectionsPlugin.swift @@ -11,120 +11,116 @@ enum MethodCall: String { case initNearbyService = "init_nearby_service" case startAdvertisingPeer = "start_advertising_peer" case startBrowsingForPeers = "start_browsing_for_peers" - + case stopAdvertisingPeer = "stop_advertising_peer" case stopBrowsingForPeers = "stop_browsing_for_peers" - + case invitePeer = "invite_peer" case disconnectPeer = "disconnect_peer" - + case sendMessage = "send_message" } public class SwiftFlutterNearbyConnectionsPlugin: NSObject, FlutterPlugin { - public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel(name: "flutter_nearby_connections", binaryMessenger: registrar.messenger()) - let instance = SwiftFlutterNearbyConnectionsPlugin(channel: channel) - registrar.addMethodCallDelegate(instance, channel: channel) - } - - var currentReceivedDevice: Device? = Device(peerID: MPCManager.instance.localPeerID) - - let channel: FlutterMethodChannel - - struct DeviceJson { - var deviceID:String - var displayName:String - var state:Int - - func toStringAnyObject() -> [String: Any] { - return [ - "deviceID": deviceID, - "displayName": displayName, - "state": state - ] - } - } - - struct MessageJson { - var deviceID:String - var message:String + public static func register(with registrar: FlutterPluginRegistrar) { + let channel = FlutterMethodChannel(name: "flutter_nearby_connections", binaryMessenger: registrar.messenger()) + let instance = SwiftFlutterNearbyConnectionsPlugin(channel: channel) + registrar.addMethodCallDelegate(instance, channel: channel) + } + + var currentReceivedDevice: Device? = Device(peerID: MPCManager.instance.localPeerID) + + let channel: FlutterMethodChannel + + struct DeviceJson { + var deviceID:String + var displayName:String + var state:Int + + func toStringAnyObject() -> [String: Any] { + return [ + "deviceID": deviceID, + "displayName": displayName, + "state": state + ] + } + } + + struct MessageJson { + var deviceID:String + var message:String + + func toStringAnyObject() -> [String: Any] { + return [ + "deviceID": deviceID, + "message": message + ] + } + } + + @objc func stateChanged(){ + let devices = MPCManager.instance.devices.compactMap({return DeviceJson(deviceID: $0.deviceId, displayName: $0.peerID.displayName, state: $0.state.rawValue)}) + channel.invokeMethod(INVOKE_CHANGE_STATE_METHOD, arguments: JSON(devices.compactMap({return $0.toStringAnyObject()})).rawString()) + } + + @objc func messageReceived(notification: Notification) { + do { + if let data = notification.userInfo?["data"] as? Data, let stringData = JSON(data).rawString() { + self.channel.invokeMethod(INVOKE_MESSAGE_RECEIVE_METHOD, + arguments: stringData) + } + } catch let e { + print(e.localizedDescription) + } + } + + public init(channel:FlutterMethodChannel) { + self.channel = channel + super.init() + + NotificationCenter.default.addObserver(self, selector: #selector(stateChanged), name: MPCManager.Notifications.deviceDidChangeState, object: nil) + + NotificationCenter.default.addObserver(self, selector: #selector(messageReceived), name: Device.messageReceivedNotification, object: nil) + + MPCManager.instance.deviceDidChange = {[weak self] in + self?.stateChanged() + } + } + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + switch MethodCall(rawValue: call.method) { + case .initNearbyService: + let serviceType:String = call.arguments as? String ?? SERVICE_TYPE + MPCManager.instance.setup(serviceType: serviceType) + case .startAdvertisingPeer: + MPCManager.instance.startAdvertisingPeer() + case .startBrowsingForPeers: + MPCManager.instance.startBrowsingForPeers() + case .stopAdvertisingPeer: + MPCManager.instance.stopAdvertisingPeer() + case .stopBrowsingForPeers: + MPCManager.instance.stopBrowsingForPeers() + case .invitePeer: + let deviceID:String? = call.arguments as? String ?? nil + if(deviceID != nil){ + MPCManager.instance.invitePeer(deviceID: deviceID!) + } + case .disconnectPeer: + let deviceID:String? = call.arguments as? String ?? nil + if(deviceID != nil){ + MPCManager.instance.disconnectPeer(deviceID: deviceID!) + } + case .sendMessage: + guard let jsonData = call.arguments as? String, let data = jsonData.data(using: String.Encoding.utf8) else {fatalError()} + do { + let json = JSON(data) + if let device = MPCManager.instance.device(for: json["device_id"].stringValue) { + currentReceivedDevice = device + try device.send(data: data) + } + } catch let error as NSError { + print(error) + } + } - func toStringAnyObject() -> [String: Any] { - return [ - "deviceID": deviceID, - "message": message - ] - } - } - - @objc func stateChanged(){ - let devices = MPCManager.instance.devices.compactMap({return DeviceJson(deviceID: $0.deviceId, displayName: $0.peerID.displayName, state: $0.state.rawValue)}) - channel.invokeMethod(INVOKE_CHANGE_STATE_METHOD, arguments: JSON(devices.compactMap({return $0.toStringAnyObject()})).rawString()) - } - - @objc func messageReceived(notification: Notification) { - if let formDevice = notification.userInfo?["from"] as? MCPeerID, let device = MPCManager.instance.devices.first(where: {return $0.peerID == formDevice}) { - let message = MessageJson(deviceID: device.deviceId, message: device.lastMessageReceived?.body ?? "") - channel.invokeMethod(INVOKE_MESSAGE_RECEIVE_METHOD, - arguments: JSON(message.toStringAnyObject()).rawString()) - } - } - - public init(channel:FlutterMethodChannel) { - self.channel = channel - super.init() - - NotificationCenter.default.addObserver(self, selector: #selector(stateChanged), name: MPCManager.Notifications.deviceDidChangeState, object: nil) - - NotificationCenter.default.addObserver(self, selector: #selector(messageReceived), name: Device.messageReceivedNotification, object: nil) - - MPCManager.instance.deviceDidChange = {[weak self] in - self?.stateChanged() - } - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - switch MethodCall(rawValue: call.method) { - case .initNearbyService: - let serviceType:String = call.arguments as? String ?? SERVICE_TYPE - MPCManager.instance.setup(serviceType: serviceType) - case .startAdvertisingPeer: - MPCManager.instance.startAdvertisingPeer() - case .startBrowsingForPeers: - MPCManager.instance.startBrowsingForPeers() - case .stopAdvertisingPeer: - MPCManager.instance.stopAdvertisingPeer() - case .stopBrowsingForPeers: - MPCManager.instance.stopBrowsingForPeers() - case .invitePeer: - let deviceID:String? = call.arguments as? String ?? nil - if(deviceID != nil){ - MPCManager.instance.invitePeer(deviceID: deviceID!) - } - case .disconnectPeer: - let deviceID:String? = call.arguments as? String ?? nil - if(deviceID != nil){ - MPCManager.instance.disconnectPeer(deviceID: deviceID!) - } - case .sendMessage: - let jsonData: String? = call.arguments as? String ?? nil - if(jsonData != nil){ - var dictonary:NSDictionary? - if let data = jsonData!.data(using: String.Encoding.utf8) { - do { - dictonary = try JSONSerialization.jsonObject(with: data, options: []) as? [String:AnyObject] as NSDictionary? - if dictonary != nil, let device = MPCManager.instance.device(for: dictonary?["deviceID"] as? String ?? "") { - currentReceivedDevice = device - try device.send(text: dictonary?["message"] as? String ?? "") - } - } catch let error as NSError { - print(error) - } - } - } - default: - break - } - } - } +} diff --git a/lib/src/nearby_service.dart b/lib/src/nearby_service.dart index f5033a9..f06c926 100644 --- a/lib/src/nearby_service.dart +++ b/lib/src/nearby_service.dart @@ -17,7 +17,7 @@ typedef StateChangedCallback = Function(List arguments); /// [DataReceivedCallback] is used to call back an object under List. /// [DataReceivedCallback] will call when you register in [dataReceivedSubscription] -typedef DataReceivedCallback = Function(Message data); +typedef DataReceivedCallback = Function(dynamic data); class NearbyService { static const MethodChannel _channel = @@ -28,11 +28,15 @@ class NearbyService { Stream> get _stateChangedStream => _stateChangedController.stream; - final _dataReceivedController = StreamController.broadcast(); + final _dataReceivedController = StreamController.broadcast(); - Stream get _dataReceivedStream => _dataReceivedController.stream; + Stream get _dataReceivedStream => _dataReceivedController.stream; - /// The class [NearbyService] supports the discovery of services provided by nearby devices and supports communicating with those services through message-based data, streaming data, and resources (such as files). In iOS, the framework uses infrastructure Wi-Fi networks, peer-to-peer Wi-Fi, and Bluetooth personal area networks for the underlying transport. + /// The class [NearbyService] supports the discovery of services provided by + /// nearby devices and supports communicating with those services through + /// message-based data, streaming data, and resources (such as files). + /// In iOS, the framework uses infrastructure Wi-Fi networks, peer-to-peer Wi-Fi, + /// and Bluetooth personal area networks for the underlying transport. /// param [serviceType] max length 15 character NearbyService({@required String serviceType}) : assert(serviceType.length <= 15) { @@ -47,21 +51,25 @@ class NearbyService { _stateChangedController.add(devices); break; case _invokeMessageReceiveMethod: - Message data = Message.fromJson(jsonDecode(call.arguments)); - _dataReceivedController.add(data); + _dataReceivedController.add(jsonDecode(call.arguments)); break; } }); } /// Begins advertising the service provided by a local peer. - /// The [startAdvertisingPeer] publishes an advertisement for a specific service that your app provides through the flutter_nearby_connections plugin and notifies its delegate about invitations from nearby peers. + /// The [startAdvertisingPeer] publishes an advertisement for a specific service + /// that your app provides through the flutter_nearby_connections plugin and + /// notifies its delegate about invitations from nearby peers. FutureOr startAdvertisingPeer() { _channel.invokeMethod(_startAdvertisingPeer); } /// Starts browsing for peers. - /// Searches (by [serviceType]) for services offered by nearby devices using infrastructure Wi-Fi, peer-to-peer Wi-Fi, and Bluetooth or Ethernet, and provides the ability to easily invite those [Device] to a earby connections session [SessionState]. + /// Searches (by [serviceType]) for services offered by nearby devices using + /// infrastructure Wi-Fi, peer-to-peer Wi-Fi, and Bluetooth or Ethernet, and + /// provides the ability to easily invite those [Device] to a earby connections + /// session [SessionState]. FutureOr startBrowsingForPeers() { _channel.invokeMethod(_startBrowsingForPeers); } @@ -89,23 +97,23 @@ class NearbyService { } /// Sends a message encapsulated in a Data instance to nearby peers. - FutureOr sendMessage(String deviceID, String argument) { + FutureOr sendMessage(String deviceID, Map argument) { + argument['device_id'] = deviceID; _channel.invokeMethod( - _sendMessage, - "{" - "\"deviceID\":\"$deviceID\"," - "\"message\": \"$argument\"" - "}"); + _sendMessage, jsonEncode(argument)); } - /// [stateChangedSubscription] helps you listen to the changes of peers with the circumstances: find a new peer, a peer is invited, a peer is disconnected, a peer is invited to connect by another peer, or 2 peers are connected. + /// [stateChangedSubscription] helps you listen to the changes of peers with + /// the circumstances: find a new peer, a peer is invited, a peer is disconnected, + /// a peer is invited to connect by another peer, or 2 peers are connected. /// [stateChangedSubscription] will return you a list of [Device]. /// see [StateChangedCallback] StreamSubscription stateChangedSubscription( {@required StateChangedCallback callback}) => _stateChangedStream.listen(callback); - /// The [dataReceivedSubscription] helps you listen when a peer sends you text messages. and it returns you a object [Data]. + /// The [dataReceivedSubscription] helps you listen when a peer sends you + /// text messages. and it returns you a object [Data]. /// It returns a [StreamSubscription] so you can cancel listening at any time. /// see [DataReceivedCallback] StreamSubscription dataReceivedSubscription( diff --git a/pubspec.yaml b/pubspec.yaml index 6d01d0a..5fd615e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_nearby_connections description: Flutter plugin supports peer-to-peer connectivity and discovers nearby devices for Android and IOS -version: 0.0.2 +version: 0.0.3 author: vn.apnic@gmail.com homepage: https://github.com/VNAPNIC/flutter_nearby_connections @@ -12,6 +12,7 @@ dependencies: flutter: sdk: flutter pedantic: ^1.9.0 + fluttertoast: ^7.1.1 dev_dependencies: flutter_test: