A generic library to search for external device using various connection technologies. Support Bluetooth LE (Android/iOS) and USB (Android only).
- Update your app
android/app/build.gradle
and update minSdkVersion to at least 21
defaultConfig {
applicationId "com.example.app"
minSdkVersion 21
// ...
}
- Add Jitpack in your
android/build.gradle
file
allprojects {
repositories {
// ...
maven { url 'https://jitpack.io' }
}
}
- Setup required permissions according to OS and technology:
- Add the following to your main
AndroidManifest.xml
. See Android Developers and this StackOverflow answer for more information about permission settings.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.flutter_device_searcher_example">
<!-- Set android:required="false" if Bluetooth feature is not required by your app.-->
<uses-feature android:name="android.hardware.bluetooth" android:required="true" />
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" tools:targetApi="s" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="30" />
<!-- ... -->
</manifest>
- Add the following to your main
AndroidManifest.xml
.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.flutter_device_searcher_example">
<!-- Set android:required="false" if USB feature is not required by your app.-->
<uses-feature android:name="android.hardware.usb.host" android:required="true" />
<uses-permission android:name="hk.gogovan.flutter_device_searcher.USB_PERMISSION" />
<!-- ... -->
</manifest>
- Create a searcher according to connection technology desired. All searchers implement
DeviceSearcherInterface
.
- For BLE, use
BluetoothSearcher
- For USB, use
UsbSearcher
- Invoke and listen to the Dart
Stream
returned fromsearch()
method. Subclasses ofDeviceSearchResult
s are sent to your listener.
- For BLE, you will receive a
BluetoothResult
.id
is an identifier for the device, it being a MAC address (may be randomized) in Android and a random UUID in iOS.- This may change over different connections even to the same device, so do not store it over app sessions or hold onto it for extended period of time.
name
is the display name for the device.
- For USB, you will receive a
UsbResult
.deviceName
is the name of the device as identified by the OS. Use this to connect to device in theUsbDevice
constructor.- This may change over different connections even to the same device, so do not store it over app sessions or hold onto it for extended period of time.
- Other information are also retrieved and can be found in
UsbResult
. You can use these data to determine which device you want to connect to.- For details refer to Android documentation, in particular:
final searchStream = btSearcher?.search().listen(cancelOnError: true, (event) {
final id = event.id;
// Store the event for later connection.
});
- Stop the search before connecting to a device, by cancelling the search stream. Failure to stop the search may cause inability to connect to devices in some phones.
await searchStream.cancel();
- To connect a device, create a
DeviceInterface
implementation such asBluetoothDevice
, passing the device you want to connect. Then callconnect
to connect to the device.
final btDevice = BluetoothDevice(deviceSearcher, searchedBtResult[index]);
await btDevice.connect();
- After connecting to device, you may query available services and characteristics.
final list = await btDevice.getServices();
- Synchronous read/write from/to the device is done by
read
andwrite
call respectively. - Asynchronous read is done by
readAsStream
method, which returns a DartStream
. Listen to stream to receive results.
- Set interface index and then endpoint number before sending or receiving data. Details of these can be found in the
UsbResult
.
await usbDevice?.setInterfaceIndex(index);
await usbDevice?.setEndpointIndex(index);
- After interface and endpoint is set, use
transfer
to either read or write data, depending on whether the interface is read or write.
List<int> result = await usbDevice?.transfer(Uint8List(0));
- To disconnect from the device, call
disconnect
on the device.
await btDevice.disconnect();
If you are using Bluetooth, you can also elect to use the provided BluetoothConnectionMixin
, which handles device searching and connection management.
Override the methods includeResult
, includeService
and includeCharacteristic
methods to specify which Bluetooth device, service and characteristic you are interested in. It should filter results, services and characteristics down to one of each.