import 'dart:async'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:nearby_service/nearby_service.dart'; import 'package:nearby_service/nearby_service_platform_interface.dart'; import 'package:nearby_service/src/utils/logger.dart'; export 'package:nearby_service/src/platforms/android/android.dart'; export 'package:nearby_service/src/platforms/ios/ios.dart'; export 'src/model/model.dart'; export 'src/utils/utils.dart'; export 'src/types/types.dart'; export 'src/base/base.dart'; export 'src/interface/interface.dart'; /// /// The main tool for working with a P2P network. /// Implementations: /// * for Android - [NearbyAndroidService] /// * for Darwin - [NearbyDarwinService] /// /// **The plugin is not supported for other platforms yet** /// abstract class NearbyService { /// /// The only way to get an instance of [NearbyService]. /// /// Creates a service suitable for the current platform. /// Otherwise it throws [NearbyServiceException]. /// static NearbyService getInstance({NearbyServiceLogLevel? logLevel}) { if (logLevel != null) { Logger.level = logLevel; } if (Platform.isAndroid) { Logger.debug('Created Nearby Android Service'); return NearbyAndroidService(); } else if (Platform.isIOS || Platform.isMacOS) { Logger.debug('Created Nearby Darwin Service'); return NearbyDarwinService(); } else { throw NearbyServiceException.unsupportedPlatform( caller: 'getInstance()', ); } } /// /// Returns [NearbyService] cast as [NearbyDarwinService] if the current /// platform is IOS or MacOS. Otherwise, returns null. /// late final NearbyDarwinService? darwin = get( onDarwin: (e) => e, ); /// /// Returns [NearbyService] cast as [NearbyAndroidService] if the current /// platform is Android. Otherwise, returns null. /// late final NearbyAndroidService? android = get( onAndroid: (e) => e, ); /// /// **A value to determine the communication channel's status.** /// /// For **Android** this is the socket connection state. /// The server can wait for the client to connect, /// and the client can be waiting for the server to be created. /// Also, both can be in connected and unconnected states. /// /// For **IOS** this is the state of the message stream subscription. /// which is generated for the device with the current connected device ID. /// @Deprecated( 'Use getCommunicationChannelStateStream or communicationChannelStateValue instead', ) ValueListenable get communicationChannelState; /// /// **A value to determine the communication channel's status.** /// /// For **Android** this is the socket connection state. /// The server can wait for the client to connect, /// and the client can be waiting for the server to be created. /// Also, both can be in connected and unconnected states. /// /// For **IOS** this is the state of the message stream subscription. /// which is generated for the device with the current connected device ID. /// /// **Can be used to retrieve the current state of the communication channel without listening to the stream via** [getCommunicationChannelStateStream]. /// CommunicationChannelState get communicationChannelStateValue; /// /// Gets version of current platform. /// /// * Sample answer for Android: "Android 14" /// * Sample answer for iOS: "IOS 17.2" /// Future getPlatformVersion() { return NearbyServicePlatform.instance.getPlatformVersion(); } /// /// Gets model of current device. /// /// * Sample answer for Android: "Android" /// * Sample answer for iOS: "IPhone 15 Pro" /// Future getPlatformModel() { return NearbyServicePlatform.instance.getPlatformModel(); } /// /// Getting info about the current device in P2P scope. /// /// This method can be used to define the name /// of the current device to be displayed on the network to other users. /// /// Also [NearbyDeviceInfo] contains the connection ID. Note that /// the ID obtained from [getCurrentDeviceInfo] for Android /// will always be **02:00:00:00:00:00** for privacy issues. /// For iOS, it can be safely used. /// Future getCurrentDeviceInfo() { return NearbyServicePlatform.instance.getCurrentDeviceInfo(); } /// /// Since Wi-fi must be enabled to use the plugin in Android, /// [openServicesSettings] can be used to redirect the user to the **Wi-fi** /// service settings on Android. /// /// For iOS it is not necessary to have Wi-fi enabled. /// In case of its absence, the platform will try to establish a connection /// by other methods. However, this method will open the settings page /// for iOS, if you want the user to use Wi-fi. /// Future openServicesSettings() { return NearbyServicePlatform.instance.openServicesSettings(); } /// /// A single retrieval of the current list of devices in a P2P network. /// /// Returns the list of [NearbyDevice] that have been stored so far. /// If you want to use a constantly updated list of devices, use [getPeersStream]. /// Future> getPeers() { return NearbyServicePlatform.instance.getPeers(); } /// /// Returns a constantly updating list of [NearbyDevice] that /// the platform-specific service has found at each point in time. /// Stream> getPeersStream() { return NearbyServicePlatform.instance.getPeersStream(); } /// /// Returns the constantly updating [NearbyDevice] you are currently connected to. /// If it returns null, then there is no connection at the moment. /// @Deprecated('Use getConnectedDeviceStreamById instead') Stream getConnectedDeviceStream(NearbyDevice device) { return NearbyServicePlatform.instance.getConnectedDeviceStream(device); } /// /// Returns the constantly updating [NearbyDevice] you are currently connected to. /// If it returns null, then there is no connection at the moment. /// Stream getConnectedDeviceStreamById(String deviceId) { return NearbyServicePlatform.instance .getConnectedDeviceStreamById(deviceId); } /// /// Initialization of a platform-specific service. /// /// The [initialize] method must be called before calling any /// other getters and methods related to P2P network (all except /// [getPlatformVersion] and [getPlatformModel]). /// Future initialize({ NearbyInitializeData data = const NearbyInitializeData(), }); /// /// Starts searching for devices using a platform-specific service. /// /// Note that the [NearbyDarwinService] implementation starts **browsing** or /// **advertising** depending on the [NearbyDarwinService.isBrowserValue]. /// /// On Android can throw mapped from native platform exceptions: /// 1. [NearbyServiceBusyException] /// 2. [NearbyServiceP2PUnsupportedException] /// 3. [NearbyServiceNoServiceRequestsException] /// 4. [NearbyServiceGenericErrorException] /// 5. [NearbyServiceUnknownException] /// Future discover(); /// /// Stops searching for devices using a platform-specific service. /// /// Note that the [NearbyDarwinService] implementation stops **browsing** or /// **advertising** depending on the [NearbyDarwinService.isBrowserValue]. /// /// On Android can throw mapped from native platform exceptions: /// 1. [NearbyServiceBusyException] /// 2. [NearbyServiceP2PUnsupportedException] /// 3. [NearbyServiceNoServiceRequestsException] /// 4. [NearbyServiceGenericErrorException] /// 5. [NearbyServiceUnknownException] /// Future stopDiscovery(); /// /// Connects to passed [device] using a platform-specific service. /// /// Note that the [NearbyDarwinService] implementation **invites** or /// **accepts invite** depending on the [NearbyDarwinService.isBrowser]. /// /// Note that if [Platform.isIOS] == true, [NearbyDarwinDevice] 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] /// @Deprecated('Use connectById instead') Future connect(NearbyDevice device); /// /// Connects to passed [deviceId] using a platform-specific service. /// /// Note that the [NearbyDarwinService] implementation **invites** or /// **accepts invite** depending on the [NearbyDarwinService.isBrowserValue]. /// /// Note that if [Platform.isIOS] == true, [NearbyDarwinDevice] 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 connectById(String deviceId); /// /// Disconnects from passed [device] using a platform-specific service. /// /// Note that if [Platform.isIOS] == true, [NearbyDarwinDevice] 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] /// /// **For IOS [device] is required!!!** @Deprecated('Use disconnectById instead') Future disconnect([NearbyDevice? device]); /// /// Disconnects from passed [deviceId] using a platform-specific service. /// /// Note that if [Platform.isIOS] or [Platform.isMacOS] == true, [NearbyDarwinDevice] 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] /// /// **For IOS [deviceId] is required!!!** Future disconnectById([String? deviceId]); /// /// If the device is already connected, it does not mean that you can /// send and receive data. /// /// There is a separate function for this in [NearbyService] - communication channel. /// You need to call [startCommunicationChannel] before using [send]. /// A communication channel can only be created if you are connected to some device. /// /// You can monitor changes in communication channel state using the [getCommunicationChannelStateStream] method. /// FutureOr startCommunicationChannel(NearbyCommunicationChannelData data); /// /// If you called [startCommunicationChannel], remember that you have /// created a subscription to receive messages. /// /// Accordingly, it is essential to terminate any subscription. /// Use [endCommunicationChannel] for this purpose. /// FutureOr endCommunicationChannel(); /// /// **A stream with values of [CommunicationChannelState] to determine the communication channel's status.** /// /// For **Android** this is the socket connection state. /// The server can wait for the client to connect, /// and the client can be waiting for the server to be created. /// Also, both can be in connected and unconnected states. /// /// For **IOS** this is the state of the message stream subscription. /// which is generated for the device with the current connected device ID. /// Stream getCommunicationChannelStateStream(); /// /// Method to send data to the created communication channel. /// FutureOr send(OutgoingNearbyMessage message); } extension NearbyServiceGetterExtension on NearbyService { /// /// If you want to do different actions or get different data /// **depending on the platform**, use [get]. /// /// * The [onAndroid] callback returns this instance of [NearbyService], /// cast as [NearbyAndroidService] if [Platform.isAndroid] is true. /// /// * The [onDarwin] callback returns this instance of [NearbyService], /// cast as [NearbyDarwinService] if [Platform.isIOS] or [Platform.isMacOS] is true. /// /// * The [onAny] callback returns this instance of [NearbyService] with /// no casting if both [Platform.isAndroid] and [Platform.isIOS] or [Platform.isMacOS] are false. /// /// **Note: any of the callbacks must not be null!** /// T? get({ T Function(NearbyAndroidService)? onAndroid, T Function(NearbyDarwinService)? onDarwin, T Function(NearbyService)? onAny, }) { assert( onAndroid != null || onDarwin != null || onAny != null, 'You should provide at least one of (onAndroid, onDarwin, onAny)', ); if (this is NearbyAndroidService && onAndroid != null) { return onAndroid(this as NearbyAndroidService); } if (this is NearbyDarwinService && onDarwin != null) { return onDarwin(this as NearbyDarwinService); } if (onAny != null) { return onAny(this); } return null; } }