feat: 重构项目 2.0.0 (#6)

* feat: 重构项目

* feat: 添加 bluez_central_manager

* feat: 联合插件

* feat: 拆分项目

* feat: 实现 linux 部分接口

* feat: 重新创建项目

* feat: 定义接口

* feat: 实现接入插件

* feat: 清空接入插件示例代码

* feat: 开发 linux 插件

* feat: 调整接口

* 临时提交

* feat: 实现 Android 接口

* fix: 修复 Android 问题

* fix: 移除多余文件

* feat: 重构项目 (#5)

* fix: 移除多余的状态判断

* fix: 外围设备断开时检查是否存在未完成的操作

* feat: 尝试使用 win32 实现接口

* fix: 修复大小写问题

* feat: 实现 macOS 接口

* feat: 实现 macOS 接口

* fix:支持使用16位短字符串生成UUID

* fix: 修复未清理已完成操作的问题

* fix: 规范命名

* 添加蓝牙使用描述

* fix: 更新 README.md
This commit is contained in:
Mr剑侠客
2023-08-17 17:49:26 +08:00
committed by GitHub
parent 3abe9d5b3d
commit d1726b52fa
371 changed files with 15666 additions and 15993 deletions

30
bluetooth_low_energy_android/.gitignore vendored Normal file
View File

@ -0,0 +1,30 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.packages
build/

View File

@ -0,0 +1,30 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.
version:
revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
channel: stable
project_type: plugin
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
- platform: android
create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

View File

@ -0,0 +1,4 @@
## 2.0.0
- Rewrite the whole project with federated plugins.
- Support macOS and Linux.

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 yanshouwang
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,15 @@
# bluetooth_low_energy_android
The Android implementation of [`bluetooth_low_energy`][1].
## Usage
This package is [endorsed][2], which means you can simply use `bluetooth_low_energy`
normally. This package will be automatically included in your app when you do,
so you do not need to add it to your `pubspec.yaml`.
However, if you `import` this package to use any of its APIs directly, you
should add it to your `pubspec.yaml` as usual.
[1]: https://pub.dev/packages/bluetooth_low_energy
[2]: https://flutter.dev/docs/development/packages-and-plugins/developing-packages#endorsed-federated-plugin

View File

@ -0,0 +1,4 @@
include: package:flutter_lints/flutter.yaml
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

View File

@ -0,0 +1,9 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.cxx

View File

@ -0,0 +1,64 @@
group 'dev.yanshouwang.bluetooth_low_energy'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '1.7.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 31
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
test.java.srcDirs += 'src/test/kotlin'
}
defaultConfig {
minSdkVersion 21
}
dependencies {
testImplementation 'org.jetbrains.kotlin:kotlin-test'
testImplementation 'org.mockito:mockito-core:5.0.0'
}
testOptions {
unitTests.all {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen {false}
showStandardStreams = true
}
}
}
}

View File

@ -0,0 +1 @@
rootProject.name = 'bluetooth_low_energy'

View File

@ -0,0 +1,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dev.yanshouwang.bluetooth_low_energy">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<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" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
</manifest>

View File

@ -0,0 +1,38 @@
package dev.yanshouwang.bluetooth_low_energy
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
/** BluetoothLowEnergyAndroid */
class BluetoothLowEnergyAndroid : FlutterPlugin, ActivityAware {
private lateinit var centralController: MyCentralController
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
val context = binding.applicationContext
val binaryMessenger = binding.binaryMessenger
centralController = MyCentralController(context, binaryMessenger)
MyCentralControllerHostApi.setUp(binaryMessenger, centralController)
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
val binaryMessenger = binding.binaryMessenger
MyCentralControllerHostApi.setUp(binaryMessenger, null)
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
centralController.onAttachedToActivity(binding)
}
override fun onDetachedFromActivityForConfigChanges() {
centralController.onDetachedFromActivity()
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
centralController.onAttachedToActivity(binding)
}
override fun onDetachedFromActivity() {
centralController.onDetachedFromActivity()
}
}

View File

@ -0,0 +1,653 @@
// Autogenerated from Pigeon (v10.1.6), do not edit directly.
// See also: https://pub.dev/packages/pigeon
package dev.yanshouwang.bluetooth_low_energy
import android.util.Log
import io.flutter.plugin.common.BasicMessageChannel
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.MessageCodec
import io.flutter.plugin.common.StandardMessageCodec
import java.io.ByteArrayOutputStream
import java.nio.ByteBuffer
private fun wrapResult(result: Any?): List<Any?> {
return listOf(result)
}
private fun wrapError(exception: Throwable): List<Any?> {
if (exception is FlutterError) {
return listOf(
exception.code,
exception.message,
exception.details
)
} else {
return listOf(
exception.javaClass.simpleName,
exception.toString(),
"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception)
)
}
}
/**
* Error class for passing custom error details to Flutter via a thrown PlatformException.
* @property code The error code.
* @property message The error message.
* @property details The error details. Must be a datatype supported by the api codec.
*/
class FlutterError (
val code: String,
override val message: String? = null,
val details: Any? = null
) : Throwable()
enum class MyCentralStateArgs(val raw: Int) {
UNKNOWN(0),
UNSUPPORTED(1),
UNAUTHORIZED(2),
POWEREDOFF(3),
POWEREDON(4);
companion object {
fun ofRaw(raw: Int): MyCentralStateArgs? {
return values().firstOrNull { it.raw == raw }
}
}
}
enum class MyGattCharacteristicPropertyArgs(val raw: Int) {
READ(0),
WRITE(1),
WRITEWITHOUTRESPONSE(2),
NOTIFY(3),
INDICATE(4);
companion object {
fun ofRaw(raw: Int): MyGattCharacteristicPropertyArgs? {
return values().firstOrNull { it.raw == raw }
}
}
}
enum class MyGattCharacteristicWriteTypeArgs(val raw: Int) {
WITHRESPONSE(0),
WITHOUTRESPONSE(1);
companion object {
fun ofRaw(raw: Int): MyGattCharacteristicWriteTypeArgs? {
return values().firstOrNull { it.raw == raw }
}
}
}
/** Generated class from Pigeon that represents data sent in messages. */
data class MyCentralControllerArgs (
val myStateNumber: Long
) {
companion object {
@Suppress("UNCHECKED_CAST")
fun fromList(list: List<Any?>): MyCentralControllerArgs {
val myStateNumber = list[0].let { if (it is Int) it.toLong() else it as Long }
return MyCentralControllerArgs(myStateNumber)
}
}
fun toList(): List<Any?> {
return listOf<Any?>(
myStateNumber,
)
}
}
/** Generated class from Pigeon that represents data sent in messages. */
data class MyPeripheralArgs (
val key: Long,
val uuid: String
) {
companion object {
@Suppress("UNCHECKED_CAST")
fun fromList(list: List<Any?>): MyPeripheralArgs {
val key = list[0].let { if (it is Int) it.toLong() else it as Long }
val uuid = list[1] as String
return MyPeripheralArgs(key, uuid)
}
}
fun toList(): List<Any?> {
return listOf<Any?>(
key,
uuid,
)
}
}
/** Generated class from Pigeon that represents data sent in messages. */
data class MyAdvertisementArgs (
val name: String? = null,
val manufacturerSpecificData: Map<Long?, ByteArray?>,
val serviceUUIDs: List<String?>,
val serviceData: Map<String?, ByteArray?>
) {
companion object {
@Suppress("UNCHECKED_CAST")
fun fromList(list: List<Any?>): MyAdvertisementArgs {
val name = list[0] as String?
val manufacturerSpecificData = list[1] as Map<Long?, ByteArray?>
val serviceUUIDs = list[2] as List<String?>
val serviceData = list[3] as Map<String?, ByteArray?>
return MyAdvertisementArgs(name, manufacturerSpecificData, serviceUUIDs, serviceData)
}
}
fun toList(): List<Any?> {
return listOf<Any?>(
name,
manufacturerSpecificData,
serviceUUIDs,
serviceData,
)
}
}
/** Generated class from Pigeon that represents data sent in messages. */
data class MyGattServiceArgs (
val key: Long,
val uuid: String
) {
companion object {
@Suppress("UNCHECKED_CAST")
fun fromList(list: List<Any?>): MyGattServiceArgs {
val key = list[0].let { if (it is Int) it.toLong() else it as Long }
val uuid = list[1] as String
return MyGattServiceArgs(key, uuid)
}
}
fun toList(): List<Any?> {
return listOf<Any?>(
key,
uuid,
)
}
}
/** Generated class from Pigeon that represents data sent in messages. */
data class MyGattCharacteristicArgs (
val key: Long,
val uuid: String,
val myPropertyNumbers: List<Long?>
) {
companion object {
@Suppress("UNCHECKED_CAST")
fun fromList(list: List<Any?>): MyGattCharacteristicArgs {
val key = list[0].let { if (it is Int) it.toLong() else it as Long }
val uuid = list[1] as String
val myPropertyNumbers = list[2] as List<Long?>
return MyGattCharacteristicArgs(key, uuid, myPropertyNumbers)
}
}
fun toList(): List<Any?> {
return listOf<Any?>(
key,
uuid,
myPropertyNumbers,
)
}
}
/** Generated class from Pigeon that represents data sent in messages. */
data class MyGattDescriptorArgs (
val key: Long,
val uuid: String
) {
companion object {
@Suppress("UNCHECKED_CAST")
fun fromList(list: List<Any?>): MyGattDescriptorArgs {
val key = list[0].let { if (it is Int) it.toLong() else it as Long }
val uuid = list[1] as String
return MyGattDescriptorArgs(key, uuid)
}
}
fun toList(): List<Any?> {
return listOf<Any?>(
key,
uuid,
)
}
}
@Suppress("UNCHECKED_CAST")
private object MyCentralControllerHostApiCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
return when (type) {
128.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
MyCentralControllerArgs.fromList(it)
}
}
129.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
MyGattCharacteristicArgs.fromList(it)
}
}
130.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
MyGattDescriptorArgs.fromList(it)
}
}
131.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
MyGattServiceArgs.fromList(it)
}
}
else -> super.readValueOfType(type, buffer)
}
}
override fun writeValue(stream: ByteArrayOutputStream, value: Any?) {
when (value) {
is MyCentralControllerArgs -> {
stream.write(128)
writeValue(stream, value.toList())
}
is MyGattCharacteristicArgs -> {
stream.write(129)
writeValue(stream, value.toList())
}
is MyGattDescriptorArgs -> {
stream.write(130)
writeValue(stream, value.toList())
}
is MyGattServiceArgs -> {
stream.write(131)
writeValue(stream, value.toList())
}
else -> super.writeValue(stream, value)
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface MyCentralControllerHostApi {
fun setUp(callback: (Result<MyCentralControllerArgs>) -> Unit)
fun tearDown()
fun startDiscovery(callback: (Result<Unit>) -> Unit)
fun stopDiscovery()
fun connect(myPeripheralKey: Long, callback: (Result<Unit>) -> Unit)
fun disconnect(myPeripheralKey: Long, callback: (Result<Unit>) -> Unit)
fun discoverGATT(myPeripheralKey: Long, callback: (Result<Unit>) -> Unit)
fun getServices(myPeripheralKey: Long): List<MyGattServiceArgs>
fun getCharacteristics(myServiceKey: Long): List<MyGattCharacteristicArgs>
fun getDescriptors(myCharacteristicKey: Long): List<MyGattDescriptorArgs>
fun readCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, callback: (Result<ByteArray>) -> Unit)
fun writeCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, value: ByteArray, myTypeNumber: Long, callback: (Result<Unit>) -> Unit)
fun notifyCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, state: Boolean, callback: (Result<Unit>) -> Unit)
fun readDescriptor(myPeripheralKey: Long, myDescriptorKey: Long, callback: (Result<ByteArray>) -> Unit)
fun writeDescriptor(myPeripheralKey: Long, myDescriptorKey: Long, value: ByteArray, callback: (Result<Unit>) -> Unit)
companion object {
/** The codec used by MyCentralControllerHostApi. */
val codec: MessageCodec<Any?> by lazy {
MyCentralControllerHostApiCodec
}
/** Sets up an instance of `MyCentralControllerHostApi` to handle messages through the `binaryMessenger`. */
@Suppress("UNCHECKED_CAST")
fun setUp(binaryMessenger: BinaryMessenger, api: MyCentralControllerHostApi?) {
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.setUp", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
api.setUp() { result: Result<MyCentralControllerArgs> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
val data = result.getOrNull()
reply.reply(wrapResult(data))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.tearDown", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
var wrapped: List<Any?>
try {
api.tearDown()
wrapped = listOf<Any?>(null)
} catch (exception: Throwable) {
wrapped = wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.startDiscovery", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
api.startDiscovery() { result: Result<Unit> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
reply.reply(wrapResult(null))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.stopDiscovery", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
var wrapped: List<Any?>
try {
api.stopDiscovery()
wrapped = listOf<Any?>(null)
} catch (exception: Throwable) {
wrapped = wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.connect", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long }
api.connect(myPeripheralKeyArg) { result: Result<Unit> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
reply.reply(wrapResult(null))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.disconnect", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long }
api.disconnect(myPeripheralKeyArg) { result: Result<Unit> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
reply.reply(wrapResult(null))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.discoverGATT", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long }
api.discoverGATT(myPeripheralKeyArg) { result: Result<Unit> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
reply.reply(wrapResult(null))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.getServices", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long }
var wrapped: List<Any?>
try {
wrapped = listOf<Any?>(api.getServices(myPeripheralKeyArg))
} catch (exception: Throwable) {
wrapped = wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.getCharacteristics", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val myServiceKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long }
var wrapped: List<Any?>
try {
wrapped = listOf<Any?>(api.getCharacteristics(myServiceKeyArg))
} catch (exception: Throwable) {
wrapped = wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.getDescriptors", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val myCharacteristicKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long }
var wrapped: List<Any?>
try {
wrapped = listOf<Any?>(api.getDescriptors(myCharacteristicKeyArg))
} catch (exception: Throwable) {
wrapped = wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.readCharacteristic", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long }
val myCharacteristicKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long }
api.readCharacteristic(myPeripheralKeyArg, myCharacteristicKeyArg) { result: Result<ByteArray> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
val data = result.getOrNull()
reply.reply(wrapResult(data))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.writeCharacteristic", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long }
val myCharacteristicKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long }
val valueArg = args[2] as ByteArray
val myTypeNumberArg = args[3].let { if (it is Int) it.toLong() else it as Long }
api.writeCharacteristic(myPeripheralKeyArg, myCharacteristicKeyArg, valueArg, myTypeNumberArg) { result: Result<Unit> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
reply.reply(wrapResult(null))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.notifyCharacteristic", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long }
val myCharacteristicKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long }
val stateArg = args[2] as Boolean
api.notifyCharacteristic(myPeripheralKeyArg, myCharacteristicKeyArg, stateArg) { result: Result<Unit> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
reply.reply(wrapResult(null))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.readDescriptor", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long }
val myDescriptorKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long }
api.readDescriptor(myPeripheralKeyArg, myDescriptorKeyArg) { result: Result<ByteArray> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
val data = result.getOrNull()
reply.reply(wrapResult(data))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.writeDescriptor", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val myPeripheralKeyArg = args[0].let { if (it is Int) it.toLong() else it as Long }
val myDescriptorKeyArg = args[1].let { if (it is Int) it.toLong() else it as Long }
val valueArg = args[2] as ByteArray
api.writeDescriptor(myPeripheralKeyArg, myDescriptorKeyArg, valueArg) { result: Result<Unit> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
reply.reply(wrapResult(null))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
}
}
}
@Suppress("UNCHECKED_CAST")
private object MyCentralControllerFlutterApiCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
return when (type) {
128.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
MyAdvertisementArgs.fromList(it)
}
}
129.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
MyPeripheralArgs.fromList(it)
}
}
else -> super.readValueOfType(type, buffer)
}
}
override fun writeValue(stream: ByteArrayOutputStream, value: Any?) {
when (value) {
is MyAdvertisementArgs -> {
stream.write(128)
writeValue(stream, value.toList())
}
is MyPeripheralArgs -> {
stream.write(129)
writeValue(stream, value.toList())
}
else -> super.writeValue(stream, value)
}
}
}
/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */
@Suppress("UNCHECKED_CAST")
class MyCentralControllerFlutterApi(private val binaryMessenger: BinaryMessenger) {
companion object {
/** The codec used by MyCentralControllerFlutterApi. */
val codec: MessageCodec<Any?> by lazy {
MyCentralControllerFlutterApiCodec
}
}
fun onStateChanged(myStateNumberArg: Long, callback: () -> Unit) {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onStateChanged", codec)
channel.send(listOf(myStateNumberArg)) {
callback()
}
}
fun onDiscovered(myPeripheralArgsArg: MyPeripheralArgs, rssiArg: Long, myAdvertisementArgsArg: MyAdvertisementArgs, callback: () -> Unit) {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onDiscovered", codec)
channel.send(listOf(myPeripheralArgsArg, rssiArg, myAdvertisementArgsArg)) {
callback()
}
}
fun onPeripheralStateChanged(myPeripheralKeyArg: Long, stateArg: Boolean, callback: () -> Unit) {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onPeripheralStateChanged", codec)
channel.send(listOf(myPeripheralKeyArg, stateArg)) {
callback()
}
}
fun onCharacteristicValueChanged(myCharacteristicKeyArg: Long, valueArg: ByteArray, callback: () -> Unit) {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onCharacteristicValueChanged", codec)
channel.send(listOf(myCharacteristicKeyArg, valueArg)) {
callback()
}
}
}

View File

@ -0,0 +1,57 @@
package dev.yanshouwang.bluetooth_low_energy
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCallback
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import java.util.concurrent.Executor
class MyBluetoothGattCallback(private val myCentralController: MyCentralController, private val executor: Executor) : BluetoothGattCallback() {
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
super.onConnectionStateChange(gatt, status, newState)
executor.execute {
myCentralController.onConnectionStateChange(gatt, status, newState)
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
super.onServicesDiscovered(gatt, status)
executor.execute {
myCentralController.onServicesDiscovered(gatt, status)
}
}
override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
super.onCharacteristicRead(gatt, characteristic, status)
executor.execute {
myCentralController.onCharacteristicRead(characteristic, status)
}
}
override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
super.onCharacteristicWrite(gatt, characteristic, status)
executor.execute {
myCentralController.onCharacteristicWrite(characteristic, status)
}
}
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
executor.execute {
myCentralController.onCharacteristicChanged(characteristic)
}
}
override fun onDescriptorRead(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) {
super.onDescriptorRead(gatt, descriptor, status)
executor.execute {
myCentralController.onDescriptorRead(descriptor, status)
}
}
override fun onDescriptorWrite(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) {
super.onDescriptorWrite(gatt, descriptor, status)
executor.execute {
myCentralController.onDescriptorWrite(descriptor, status)
}
}
}

View File

@ -0,0 +1,11 @@
package dev.yanshouwang.bluetooth_low_energy
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
class MyBroadcastReceiver(private val myCentralController: MyCentralController) : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
myCentralController.onReceive(intent)
}
}

View File

@ -0,0 +1,685 @@
package dev.yanshouwang.bluetooth_low_energy
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.bluetooth.BluetoothGattService
import android.bluetooth.BluetoothManager
import android.bluetooth.BluetoothProfile
import android.bluetooth.le.ScanFilter
import android.bluetooth.le.ScanResult
import android.bluetooth.le.ScanSettings
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.os.Build
import android.util.SparseArray
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.BinaryMessenger
import java.util.UUID
class MyCentralController(private val context: Context, binaryMessenger: BinaryMessenger) : MyCentralControllerHostApi {
companion object {
// const val DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xff.toByte()
private const val REQUEST_CODE = 443
// private val UUID_HEART_RATE_MEASUREMENT = UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb")
private val UUID_CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
}
private lateinit var binding: ActivityPluginBinding
private val manager = ContextCompat.getSystemService(context, BluetoothManager::class.java) as BluetoothManager
private val adapter = manager.adapter
private val scanner = adapter.bluetoothLeScanner
private val executor = ContextCompat.getMainExecutor(context)
private val myApi = MyCentralControllerFlutterApi(binaryMessenger)
private val myRequestPermissionResultListener = MyRequestPermissionResultListener(this)
private val myReceiver = MyBroadcastReceiver(this)
private val myScanCallback = MyScanCallback(this)
private val myGattCallback = MyBluetoothGattCallback(this, executor)
private val devices = mutableMapOf<Int, BluetoothDevice>()
private val gatts = mutableMapOf<Int, BluetoothGatt>()
private val services = mutableMapOf<Int, BluetoothGattService>()
private val characteristics = mutableMapOf<Int, BluetoothGattCharacteristic>()
private val descriptors = mutableMapOf<Int, BluetoothGattDescriptor>()
private var registered = false
private var discovering = false
private var setUpCallback: ((Result<MyCentralControllerArgs>) -> Unit)? = null
private var startDiscoveryCallback: ((Result<Unit>) -> Unit)? = null
private val connectCallbacks = mutableMapOf<Int, (Result<Unit>) -> Unit>()
private val disconnectCallbacks = mutableMapOf<Int, (Result<Unit>) -> Unit>()
private val discoverGattCallbacks = mutableMapOf<Int, (Result<Unit>) -> Unit>()
private val readCharacteristicCallbacks = mutableMapOf<Int, (Result<ByteArray>) -> Unit>()
private val writeCharacteristicCallbacks = mutableMapOf<Int, (Result<Unit>) -> Unit>()
private val readDescriptorCallbacks = mutableMapOf<Int, (Result<ByteArray>) -> Unit>()
private val writeDescriptorCallbacks = mutableMapOf<Int, (Result<Unit>) -> Unit>()
override fun setUp(callback: (Result<MyCentralControllerArgs>) -> Unit) {
try {
val available = context.packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
if (!available) {
val stateNumber = MyCentralStateArgs.UNSUPPORTED.raw.toLong()
val args = MyCentralControllerArgs(stateNumber)
callback(Result.success(args))
}
val unfinishedCallback = setUpCallback
if (unfinishedCallback != null) {
throw IllegalStateException()
}
val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_CONNECT)
} else {
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION)
}
val activity = binding.activity
ActivityCompat.requestPermissions(activity, permissions, REQUEST_CODE)
setUpCallback = callback
} catch (e: Throwable) {
callback(Result.failure(e))
}
}
override fun tearDown() {
if (registered) {
unregister()
}
if (discovering) {
stopDiscovery()
}
for (gatt in gatts.values) {
gatt.disconnect()
}
devices.clear()
gatts.clear()
services.clear()
characteristics.clear()
descriptors.clear()
}
private fun register() {
val filter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)
context.registerReceiver(myReceiver, filter)
registered = true
}
private fun unregister() {
context.unregisterReceiver(myReceiver)
registered = false
}
override fun startDiscovery(callback: (Result<Unit>) -> Unit) {
try {
val unfinishedCallback = startDiscoveryCallback
if (unfinishedCallback != null) {
throw IllegalStateException()
}
val filters = emptyList<ScanFilter>()
val settings = ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build()
scanner.startScan(filters, settings, myScanCallback)
executor.execute {
val finishedCallback = startDiscoveryCallback ?: return@execute
startDiscoveryCallback = null
finishedCallback(Result.success(Unit))
}
startDiscoveryCallback = callback
} catch (e: Throwable) {
callback(Result.failure(e))
}
}
override fun stopDiscovery() {
scanner.stopScan(myScanCallback)
discovering = false
}
override fun connect(myPeripheralKey: Long, callback: (Result<Unit>) -> Unit) {
try {
val deviceKey = myPeripheralKey.toInt()
val unfinishedCallback = connectCallbacks[deviceKey]
if (unfinishedCallback != null) {
throw IllegalStateException()
}
val device = devices[deviceKey] as BluetoothDevice
val autoConnect = false
gatts[deviceKey] = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val transport = BluetoothDevice.TRANSPORT_LE
device.connectGatt(context, autoConnect, myGattCallback, transport)
} else {
device.connectGatt(context, autoConnect, myGattCallback)
}
connectCallbacks[deviceKey] = callback
} catch (e: Throwable) {
callback(Result.failure(e))
}
}
override fun disconnect(myPeripheralKey: Long, callback: (Result<Unit>) -> Unit) {
try {
val deviceKey = myPeripheralKey.toInt()
val unfinishedCallback = disconnectCallbacks[deviceKey]
if (unfinishedCallback != null) {
throw IllegalStateException()
}
val gatt = gatts[deviceKey] as BluetoothGatt
gatt.disconnect()
disconnectCallbacks[deviceKey] = callback
} catch (e: Throwable) {
callback(Result.failure(e))
}
}
override fun discoverGATT(myPeripheralKey: Long, callback: (Result<Unit>) -> Unit) {
try {
val deviceKey = myPeripheralKey.toInt()
val unfinishedCallback = discoverGattCallbacks[deviceKey]
if (unfinishedCallback != null) {
throw IllegalStateException()
}
val gatt = gatts[deviceKey] as BluetoothGatt
val discovering = gatt.discoverServices()
if (!discovering) {
throw IllegalStateException()
}
discoverGattCallbacks[deviceKey] = callback
} catch (e: Throwable) {
callback(Result.failure(e))
}
}
override fun getServices(myPeripheralKey: Long): List<MyGattServiceArgs> {
val deviceKey = myPeripheralKey.toInt()
val gatt = gatts[deviceKey] as BluetoothGatt
val services = gatt.services
return services.map { service ->
val serviceKey = service.hashCode()
if (this.services[serviceKey] == null) {
this.services[serviceKey] = service
}
return@map service.toMyArgs()
}
}
override fun getCharacteristics(myServiceKey: Long): List<MyGattCharacteristicArgs> {
val serviceKey = myServiceKey.toInt()
val service = services[serviceKey] as BluetoothGattService
val characteristics = service.characteristics
return characteristics.map { characteristic ->
val characteristicKey = characteristic.hashCode()
if (this.characteristics[characteristicKey] == null) {
this.characteristics[characteristicKey] = characteristic
}
return@map characteristic.toMyArgs()
}
}
override fun getDescriptors(myCharacteristicKey: Long): List<MyGattDescriptorArgs> {
val characteristicKey = myCharacteristicKey.toInt()
val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic
val descriptors = characteristic.descriptors
return descriptors.map { descriptor ->
val descriptorKey = descriptor.hashCode()
if (this.descriptors[descriptorKey] == null) {
this.descriptors[descriptorKey] = descriptor
}
return@map descriptor.toMyArgs()
}
}
override fun readCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, callback: (Result<ByteArray>) -> Unit) {
try {
val deviceKey = myPeripheralKey.toInt()
val characteristicKey = myCharacteristicKey.toInt()
val unfinishedCallback = readCharacteristicCallbacks[characteristicKey]
if (unfinishedCallback != null) {
throw IllegalStateException()
}
val gatt = gatts[deviceKey] as BluetoothGatt
val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic
val reading = gatt.readCharacteristic(characteristic)
if (!reading) {
throw IllegalStateException()
}
readCharacteristicCallbacks[characteristicKey] = callback
} catch (e: Throwable) {
callback(Result.failure(e))
}
}
override fun writeCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, value: ByteArray, myTypeNumber: Long, callback: (Result<Unit>) -> Unit) {
try {
val deviceKey = myPeripheralKey.toInt()
val characteristicKey = myCharacteristicKey.toInt()
val unfinishedCallback = writeCharacteristicCallbacks[characteristicKey]
if (unfinishedCallback != null) {
throw IllegalStateException()
}
val gatt = gatts[deviceKey] as BluetoothGatt
val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic
val myTypeArgs = myTypeNumber.toMyGattCharacteristicTypeArgs()
val writeType = myTypeArgs.toType()
characteristic.value = value
characteristic.writeType = writeType
val writing = gatt.writeCharacteristic(characteristic)
if (!writing) {
throw IllegalStateException()
}
writeCharacteristicCallbacks[characteristicKey] = callback
} catch (e: Throwable) {
callback(Result.failure(e))
}
}
override fun notifyCharacteristic(myPeripheralKey: Long, myCharacteristicKey: Long, state: Boolean, callback: (Result<Unit>) -> Unit) {
try {
val deviceKey = myPeripheralKey.toInt()
val characteristicKey = myCharacteristicKey.toInt()
val gatt = gatts[deviceKey] as BluetoothGatt
val characteristic = characteristics[characteristicKey] as BluetoothGattCharacteristic
val notifying = gatt.setCharacteristicNotification(characteristic, state)
if (!notifying) {
throw IllegalStateException()
}
// TODO: Seems the docs is not correct, this operation is necessary for all characteristics.
// https://developer.android.com/guide/topics/connectivity/bluetooth/transfer-ble-data#notification
// This is specific to Heart Rate Measurement.
// if (characteristic.uuid == UUID_HEART_RATE_MEASUREMENT) {
val descriptor = characteristic.getDescriptor(UUID_CLIENT_CHARACTERISTIC_CONFIG)
val descriptorKey = descriptor.hashCode()
val unfinishedCallback = writeDescriptorCallbacks[descriptorKey]
if (unfinishedCallback != null) {
throw IllegalStateException()
}
val value = if (state) BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
else BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE
descriptor.value = value
val writing = gatt.writeDescriptor(descriptor)
if (!writing) {
throw IllegalStateException()
}
writeDescriptorCallbacks[descriptorKey] = callback
// } else {
// callback(Result.success(Unit))
// }
} catch (e: Throwable) {
callback(Result.failure(e))
}
}
override fun readDescriptor(myPeripheralKey: Long, myDescriptorKey: Long, callback: (Result<ByteArray>) -> Unit) {
try {
val deviceKey = myPeripheralKey.toInt()
val descriptorKey = myDescriptorKey.toInt()
val unfinishedCallback = readDescriptorCallbacks[descriptorKey]
if (unfinishedCallback != null) {
throw IllegalStateException()
}
val gatt = gatts[deviceKey] as BluetoothGatt
val descriptor = descriptors[descriptorKey] as BluetoothGattDescriptor
val reading = gatt.readDescriptor(descriptor)
if (!reading) {
throw IllegalStateException()
}
readDescriptorCallbacks[descriptorKey] = callback
} catch (e: Throwable) {
callback(Result.failure(e))
}
}
override fun writeDescriptor(myPeripheralKey: Long, myDescriptorKey: Long, value: ByteArray, callback: (Result<Unit>) -> Unit) {
try {
val deviceKey = myPeripheralKey.toInt()
val descriptorKey = myDescriptorKey.toInt()
val unfinishedCallback = writeDescriptorCallbacks[descriptorKey]
if (unfinishedCallback != null) {
throw IllegalStateException()
}
val gatt = gatts[deviceKey] as BluetoothGatt
val descriptor = descriptors[descriptorKey] as BluetoothGattDescriptor
descriptor.value = value
val writing = gatt.writeDescriptor(descriptor)
if (!writing) {
throw IllegalStateException()
}
writeDescriptorCallbacks[descriptorKey] = callback
} catch (e: Throwable) {
callback(Result.failure(e))
}
}
fun onAttachedToActivity(binding: ActivityPluginBinding) {
binding.addRequestPermissionsResultListener(myRequestPermissionResultListener)
this.binding = binding
}
fun onDetachedFromActivity() {
binding.removeRequestPermissionsResultListener(myRequestPermissionResultListener)
}
fun onRequestPermissionsResult(requestCode: Int, results: IntArray): Boolean {
if (requestCode != REQUEST_CODE) {
return false
}
val callback = setUpCallback ?: return false
val isGranted = results.all { r -> r == PackageManager.PERMISSION_GRANTED }
if (isGranted) {
register()
}
val myStateArgs = if (isGranted) adapter.myStateArgs
else MyCentralStateArgs.UNAUTHORIZED
val myStateNumber = myStateArgs.raw.toLong()
val myArgs = MyCentralControllerArgs(myStateNumber)
callback(Result.success(myArgs))
return true
}
fun onReceive(intent: Intent) {
val action = intent.action
if (action != BluetoothAdapter.ACTION_STATE_CHANGED) {
return
}
// val previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, BluetoothAdapter.STATE_OFF)
val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF)
// val myPreviousStateArgs = previousState.toMyCentralStateArgs()
val myStateArgs = state.toMyCentralStateArgs()
// if (myStateArgs == myPreviousStateArgs) {
// return
// }
val myStateNumber = myStateArgs.raw.toLong()
myApi.onStateChanged(myStateNumber) {}
}
fun onScanFailed(errorCode: Int) {
val callback = startDiscoveryCallback ?: return
startDiscoveryCallback = null
val error = IllegalStateException("Start discovery failed with error code: $errorCode")
callback(Result.failure(error))
}
fun onScanResult(result: ScanResult) {
val device = result.device
val deviceKey = device.hashCode()
if (devices[deviceKey] == null) {
devices[deviceKey] = device
}
val myPeripheralArgs = device.toMyArgs()
val rssi = result.rssi.toLong()
val myAdvertisementArgs = result.myAdvertisementArgs
myApi.onDiscovered(myPeripheralArgs, rssi, myAdvertisementArgs) {}
}
fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
val device = gatt.device
val deviceKey = device.hashCode()
val myPeripheralKey = deviceKey.toLong()
if (newState != BluetoothProfile.STATE_CONNECTED) {
gatt.close()
gatts.remove(deviceKey)
val error = IllegalStateException("GATT is disconnected with status: $status")
val discoverGattCallback = discoverGattCallbacks.remove(deviceKey)
if (discoverGattCallback != null) {
discoverGattCallback(Result.failure(error))
}
for (service in gatt.services) {
for (characteristic in service.characteristics) {
val characteristicKey = characteristic.hashCode()
val readCharacteristicCallback = readCharacteristicCallbacks.remove(characteristicKey)
val writeCharacteristicCallback = writeCharacteristicCallbacks.remove(characteristicKey)
if (readCharacteristicCallback != null) {
readCharacteristicCallback(Result.failure(error))
}
if (writeCharacteristicCallback != null) {
writeCharacteristicCallback(Result.failure(error))
}
for (descriptor in characteristic.descriptors) {
val descriptorKey = descriptor.hashCode()
val readDescriptorCallback = readDescriptorCallbacks.remove(descriptorKey)
val writeDescriptorCallback = writeDescriptorCallbacks.remove(descriptorKey)
if (readDescriptorCallback != null) {
readDescriptorCallback(Result.failure(error))
}
if (writeDescriptorCallback != null) {
writeDescriptorCallback(Result.failure(error))
}
}
}
}
}
val connectCallback = connectCallbacks.remove(deviceKey)
val disconnectCallback = disconnectCallbacks.remove(deviceKey)
if (connectCallback == null && disconnectCallback == null) {
// State changed.
val state = newState == BluetoothProfile.STATE_CONNECTED
myApi.onPeripheralStateChanged(myPeripheralKey, state) {}
} else {
if (connectCallback != null) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// Connect succeed.
connectCallback(Result.success(Unit))
myApi.onPeripheralStateChanged(myPeripheralKey, true) {}
} else {
// Connect failed.
val error = IllegalStateException("Connect failed with status: $status")
connectCallback(Result.failure(error))
}
}
if (disconnectCallback != null) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// Disconnect succeed.
disconnectCallback(Result.success(Unit))
myApi.onPeripheralStateChanged(myPeripheralKey, false) {}
} else {
// Disconnect failed.
val error = IllegalStateException("Connect failed with status: $status")
disconnectCallback(Result.failure(error))
}
}
}
}
fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
val device = gatt.device
val deviceKey = device.hashCode()
val callback = discoverGattCallbacks.remove(deviceKey) ?: return
if (status == BluetoothGatt.GATT_SUCCESS) {
callback(Result.success(Unit))
} else {
val error = IllegalStateException("Discover GATT failed with status: $status")
callback(Result.failure(error))
}
}
fun onCharacteristicRead(characteristic: BluetoothGattCharacteristic, status: Int) {
val characteristicKey = characteristic.hashCode()
val callback = readCharacteristicCallbacks.remove(characteristicKey) ?: return
if (status == BluetoothGatt.GATT_SUCCESS) {
val value = characteristic.value
callback(Result.success(value))
} else {
val error = IllegalStateException("Read characteristic failed with status: $status.")
callback(Result.failure(error))
}
}
fun onCharacteristicWrite(characteristic: BluetoothGattCharacteristic, status: Int) {
val characteristicKey = characteristic.hashCode()
val callback = writeCharacteristicCallbacks.remove(characteristicKey) ?: return
if (status == BluetoothGatt.GATT_SUCCESS) {
callback(Result.success(Unit))
} else {
val error = IllegalStateException("Write characteristic failed with status: $status.")
callback(Result.failure(error))
}
}
fun onCharacteristicChanged(characteristic: BluetoothGattCharacteristic) {
val characteristicKey = characteristic.hashCode()
val myCharacteristicKey = characteristicKey.toLong()
val value = characteristic.value
myApi.onCharacteristicValueChanged(myCharacteristicKey, value) {}
}
fun onDescriptorRead(descriptor: BluetoothGattDescriptor, status: Int) {
val descriptorKey = descriptor.hashCode()
val callback = readDescriptorCallbacks.remove(descriptorKey) ?: return
if (status == BluetoothGatt.GATT_SUCCESS) {
val value = descriptor.value
callback(Result.success(value))
} else {
val error = IllegalStateException("Read descriptor failed with status: $status.")
callback(Result.failure(error))
}
}
fun onDescriptorWrite(descriptor: BluetoothGattDescriptor, status: Int) {
val descriptorKey = descriptor.hashCode()
val callback = writeDescriptorCallbacks.remove(descriptorKey) ?: return
if (status == BluetoothGatt.GATT_SUCCESS) {
callback(Result.success(Unit))
} else {
val error = IllegalStateException("Write descriptor failed with status: $status.")
callback(Result.failure(error))
}
}
}
private val BluetoothAdapter.myStateArgs: MyCentralStateArgs
get() = state.toMyCentralStateArgs()
private fun Int.toMyCentralStateArgs(): MyCentralStateArgs {
return when (this) {
BluetoothAdapter.STATE_ON -> MyCentralStateArgs.POWEREDON
else -> MyCentralStateArgs.POWEREDOFF
}
}
private fun BluetoothDevice.toMyArgs(): MyPeripheralArgs {
val key = hashCode().toLong()
val uuid = this.uuid.toString()
return MyPeripheralArgs(key, uuid)
}
private val BluetoothDevice.uuid: UUID
get() {
val node = address.filter { char -> char != ':' }
// We don't know the timestamp of the bluetooth device, use nil UUID as prefix.
return UUID.fromString("00000000-0000-0000-0000-$node")
}
private val ScanResult.myAdvertisementArgs: MyAdvertisementArgs
get() {
val record = scanRecord
return if (record == null) {
val name = null
val manufacturerSpecificData = emptyMap<Long?, ByteArray?>()
val serviceUUIDs = emptyList<String?>()
val serviceData = emptyMap<String?, ByteArray>()
MyAdvertisementArgs(name, manufacturerSpecificData, serviceUUIDs, serviceData)
} else {
val name = record.deviceName
val manufacturerSpecificData = record.manufacturerSpecificData.toMyArgs()
val serviceUUIDs = record.serviceUuids?.map { uuid -> uuid.toString() } ?: emptyList()
val pairs = record.serviceData.entries.map { (uuid, value) ->
val key = uuid.toString()
return@map Pair(key, value)
}.toTypedArray()
val serviceData = mapOf<String?, ByteArray?>(*pairs)
MyAdvertisementArgs(name, manufacturerSpecificData, serviceUUIDs, serviceData)
}
}
private fun SparseArray<ByteArray>.toMyArgs(): Map<Long?, ByteArray?> {
var index = 0
val size = size()
val values = mutableMapOf<Long?, ByteArray>()
while (index < size) {
val key = keyAt(index).toLong()
val value = valueAt(index)
values[key] = value
index++
}
return values
}
//private val ScanRecord.rawValues: Map<Byte, ByteArray>
// get() {
// val rawValues = mutableMapOf<Byte, ByteArray>()
// var index = 0
// val size = bytes.size
// while (index < size) {
// val length = bytes[index++].toInt() and 0xff
// if (length == 0) {
// break
// }
// val end = index + length
// val type = bytes[index++]
// val value = bytes.slice(index until end).toByteArray()
// rawValues[type] = value
// index = end
// }
// return rawValues.toMap()
// }
private fun BluetoothGattService.toMyArgs(): MyGattServiceArgs {
val key = hashCode().toLong()
val uuid = this.uuid.toString()
return MyGattServiceArgs(key, uuid)
}
private fun BluetoothGattCharacteristic.toMyArgs(): MyGattCharacteristicArgs {
val key = hashCode().toLong()
val uuid = this.uuid.toString()
return MyGattCharacteristicArgs(key, uuid, myPropertyNumbers)
}
private val BluetoothGattCharacteristic.myPropertyNumbers: List<Long>
get() {
val numbers = mutableListOf<Long>()
if (properties and BluetoothGattCharacteristic.PROPERTY_READ != 0) {
val number = MyGattCharacteristicPropertyArgs.READ.raw.toLong()
numbers.add(number)
}
if (properties and BluetoothGattCharacteristic.PROPERTY_WRITE != 0) {
val number = MyGattCharacteristicPropertyArgs.WRITE.raw.toLong()
numbers.add(number)
}
if (properties and BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE != 0) {
val number = MyGattCharacteristicPropertyArgs.WRITEWITHOUTRESPONSE.raw.toLong()
numbers.add(number)
}
if (properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0) {
val number = MyGattCharacteristicPropertyArgs.NOTIFY.raw.toLong()
numbers.add(number)
}
if (properties and BluetoothGattCharacteristic.PROPERTY_INDICATE != 0) {
val number = MyGattCharacteristicPropertyArgs.INDICATE.raw.toLong()
numbers.add(number)
}
return numbers
}
private fun BluetoothGattDescriptor.toMyArgs(): MyGattDescriptorArgs {
val key = hashCode().toLong()
val uuid = this.uuid.toString()
return MyGattDescriptorArgs(key, uuid)
}
private fun Long.toMyGattCharacteristicTypeArgs(): MyGattCharacteristicWriteTypeArgs {
val raw = toInt()
return MyGattCharacteristicWriteTypeArgs.ofRaw(raw) ?: throw IllegalArgumentException()
}
private fun MyGattCharacteristicWriteTypeArgs.toType(): Int {
return when (this) {
MyGattCharacteristicWriteTypeArgs.WITHRESPONSE -> BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
MyGattCharacteristicWriteTypeArgs.WITHOUTRESPONSE -> BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
}
}

View File

@ -0,0 +1,9 @@
package dev.yanshouwang.bluetooth_low_energy
import io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener
class MyRequestPermissionResultListener(private val myCentralController: MyCentralController) : RequestPermissionsResultListener {
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, results: IntArray): Boolean {
return myCentralController.onRequestPermissionsResult(requestCode, results)
}
}

View File

@ -0,0 +1,14 @@
package dev.yanshouwang.bluetooth_low_energy
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanResult
class MyScanCallback(private val myCentralController: MyCentralController) : ScanCallback() {
override fun onScanFailed(errorCode: Int) {
myCentralController.onScanFailed(errorCode)
}
override fun onScanResult(callbackType: Int, result: ScanResult) {
myCentralController.onScanResult(result)
}
}

View File

@ -0,0 +1,27 @@
package dev.yanshouwang.bluetooth_low_energy
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import kotlin.test.Test
import org.mockito.Mockito
/*
* This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation.
*
* Once you have built the plugin's example app, you can run these tests from the command
* line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or
* you can run them directly from IDEs that support JUnit such as Android Studio.
*/
internal class BluetoothLowEnergyPluginTest {
@Test
fun onMethodCall_getPlatformVersion_returnsExpectedValue() {
val plugin = BluetoothLowEnergyAndroid()
val call = MethodCall("getPlatformVersion", null)
val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java)
plugin.onMethodCall(call, mockResult)
Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE)
}
}

View File

@ -0,0 +1,9 @@
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'src/my_central_controller.dart';
abstract class BluetoothLowEnergyAndroid {
static void registerWith() {
CentralController.instance = MyCentralController();
}
}

View File

@ -0,0 +1,736 @@
// Autogenerated from Pigeon (v10.1.6), do not edit directly.
// See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
import 'dart:async';
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
import 'package:flutter/services.dart';
enum MyCentralStateArgs {
unknown,
unsupported,
unauthorized,
poweredOff,
poweredOn,
}
enum MyGattCharacteristicPropertyArgs {
read,
write,
writeWithoutResponse,
notify,
indicate,
}
enum MyGattCharacteristicWriteTypeArgs {
withResponse,
withoutResponse,
}
class MyCentralControllerArgs {
MyCentralControllerArgs({
required this.myStateNumber,
});
int myStateNumber;
Object encode() {
return <Object?>[
myStateNumber,
];
}
static MyCentralControllerArgs decode(Object result) {
result as List<Object?>;
return MyCentralControllerArgs(
myStateNumber: result[0]! as int,
);
}
}
class MyPeripheralArgs {
MyPeripheralArgs({
required this.key,
required this.uuid,
});
int key;
String uuid;
Object encode() {
return <Object?>[
key,
uuid,
];
}
static MyPeripheralArgs decode(Object result) {
result as List<Object?>;
return MyPeripheralArgs(
key: result[0]! as int,
uuid: result[1]! as String,
);
}
}
class MyAdvertisementArgs {
MyAdvertisementArgs({
this.name,
required this.manufacturerSpecificData,
required this.serviceUUIDs,
required this.serviceData,
});
String? name;
Map<int?, Uint8List?> manufacturerSpecificData;
List<String?> serviceUUIDs;
Map<String?, Uint8List?> serviceData;
Object encode() {
return <Object?>[
name,
manufacturerSpecificData,
serviceUUIDs,
serviceData,
];
}
static MyAdvertisementArgs decode(Object result) {
result as List<Object?>;
return MyAdvertisementArgs(
name: result[0] as String?,
manufacturerSpecificData: (result[1] as Map<Object?, Object?>?)!.cast<int?, Uint8List?>(),
serviceUUIDs: (result[2] as List<Object?>?)!.cast<String?>(),
serviceData: (result[3] as Map<Object?, Object?>?)!.cast<String?, Uint8List?>(),
);
}
}
class MyGattServiceArgs {
MyGattServiceArgs({
required this.key,
required this.uuid,
});
int key;
String uuid;
Object encode() {
return <Object?>[
key,
uuid,
];
}
static MyGattServiceArgs decode(Object result) {
result as List<Object?>;
return MyGattServiceArgs(
key: result[0]! as int,
uuid: result[1]! as String,
);
}
}
class MyGattCharacteristicArgs {
MyGattCharacteristicArgs({
required this.key,
required this.uuid,
required this.myPropertyNumbers,
});
int key;
String uuid;
List<int?> myPropertyNumbers;
Object encode() {
return <Object?>[
key,
uuid,
myPropertyNumbers,
];
}
static MyGattCharacteristicArgs decode(Object result) {
result as List<Object?>;
return MyGattCharacteristicArgs(
key: result[0]! as int,
uuid: result[1]! as String,
myPropertyNumbers: (result[2] as List<Object?>?)!.cast<int?>(),
);
}
}
class MyGattDescriptorArgs {
MyGattDescriptorArgs({
required this.key,
required this.uuid,
});
int key;
String uuid;
Object encode() {
return <Object?>[
key,
uuid,
];
}
static MyGattDescriptorArgs decode(Object result) {
result as List<Object?>;
return MyGattDescriptorArgs(
key: result[0]! as int,
uuid: result[1]! as String,
);
}
}
class _MyCentralControllerHostApiCodec extends StandardMessageCodec {
const _MyCentralControllerHostApiCodec();
@override
void writeValue(WriteBuffer buffer, Object? value) {
if (value is MyCentralControllerArgs) {
buffer.putUint8(128);
writeValue(buffer, value.encode());
} else if (value is MyGattCharacteristicArgs) {
buffer.putUint8(129);
writeValue(buffer, value.encode());
} else if (value is MyGattDescriptorArgs) {
buffer.putUint8(130);
writeValue(buffer, value.encode());
} else if (value is MyGattServiceArgs) {
buffer.putUint8(131);
writeValue(buffer, value.encode());
} else {
super.writeValue(buffer, value);
}
}
@override
Object? readValueOfType(int type, ReadBuffer buffer) {
switch (type) {
case 128:
return MyCentralControllerArgs.decode(readValue(buffer)!);
case 129:
return MyGattCharacteristicArgs.decode(readValue(buffer)!);
case 130:
return MyGattDescriptorArgs.decode(readValue(buffer)!);
case 131:
return MyGattServiceArgs.decode(readValue(buffer)!);
default:
return super.readValueOfType(type, buffer);
}
}
}
class MyCentralControllerHostApi {
/// Constructor for [MyCentralControllerHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
MyCentralControllerHostApi({BinaryMessenger? binaryMessenger})
: _binaryMessenger = binaryMessenger;
final BinaryMessenger? _binaryMessenger;
static const MessageCodec<Object?> codec = _MyCentralControllerHostApiCodec();
Future<MyCentralControllerArgs> setUp() async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.setUp', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(null) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else if (replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
return (replyList[0] as MyCentralControllerArgs?)!;
}
}
Future<void> tearDown() async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.tearDown', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(null) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else {
return;
}
}
Future<void> startDiscovery() async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.startDiscovery', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(null) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else {
return;
}
}
Future<void> stopDiscovery() async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.stopDiscovery', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(null) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else {
return;
}
}
Future<void> connect(int arg_myPeripheralKey) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.connect', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else {
return;
}
}
Future<void> disconnect(int arg_myPeripheralKey) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.disconnect', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else {
return;
}
}
Future<void> discoverGATT(int arg_myPeripheralKey) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.discoverGATT', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else {
return;
}
}
Future<List<MyGattServiceArgs?>> getServices(int arg_myPeripheralKey) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.getServices', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else if (replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
return (replyList[0] as List<Object?>?)!.cast<MyGattServiceArgs?>();
}
}
Future<List<MyGattCharacteristicArgs?>> getCharacteristics(int arg_myServiceKey) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.getCharacteristics', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_myServiceKey]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else if (replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
return (replyList[0] as List<Object?>?)!.cast<MyGattCharacteristicArgs?>();
}
}
Future<List<MyGattDescriptorArgs?>> getDescriptors(int arg_myCharacteristicKey) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.getDescriptors', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_myCharacteristicKey]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else if (replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
return (replyList[0] as List<Object?>?)!.cast<MyGattDescriptorArgs?>();
}
}
Future<Uint8List> readCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.readCharacteristic', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else if (replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
return (replyList[0] as Uint8List?)!;
}
}
Future<void> writeCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey, Uint8List arg_value, int arg_myTypeNumber) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.writeCharacteristic', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey, arg_value, arg_myTypeNumber]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else {
return;
}
}
Future<void> notifyCharacteristic(int arg_myPeripheralKey, int arg_myCharacteristicKey, bool arg_state) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.notifyCharacteristic', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myCharacteristicKey, arg_state]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else {
return;
}
}
Future<Uint8List> readDescriptor(int arg_myPeripheralKey, int arg_myDescriptorKey) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.readDescriptor', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myDescriptorKey]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else if (replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
return (replyList[0] as Uint8List?)!;
}
}
Future<void> writeDescriptor(int arg_myPeripheralKey, int arg_myDescriptorKey, Uint8List arg_value) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerHostApi.writeDescriptor', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_myPeripheralKey, arg_myDescriptorKey, arg_value]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else {
return;
}
}
}
class _MyCentralControllerFlutterApiCodec extends StandardMessageCodec {
const _MyCentralControllerFlutterApiCodec();
@override
void writeValue(WriteBuffer buffer, Object? value) {
if (value is MyAdvertisementArgs) {
buffer.putUint8(128);
writeValue(buffer, value.encode());
} else if (value is MyPeripheralArgs) {
buffer.putUint8(129);
writeValue(buffer, value.encode());
} else {
super.writeValue(buffer, value);
}
}
@override
Object? readValueOfType(int type, ReadBuffer buffer) {
switch (type) {
case 128:
return MyAdvertisementArgs.decode(readValue(buffer)!);
case 129:
return MyPeripheralArgs.decode(readValue(buffer)!);
default:
return super.readValueOfType(type, buffer);
}
}
}
abstract class MyCentralControllerFlutterApi {
static const MessageCodec<Object?> codec = _MyCentralControllerFlutterApiCodec();
void onStateChanged(int myStateNumber);
void onDiscovered(MyPeripheralArgs myPeripheralArgs, int rssi, MyAdvertisementArgs myAdvertisementArgs);
void onPeripheralStateChanged(int myPeripheralKey, bool state);
void onCharacteristicValueChanged(int myCharacteristicKey, Uint8List value);
static void setup(MyCentralControllerFlutterApi? api, {BinaryMessenger? binaryMessenger}) {
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onStateChanged', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
channel.setMessageHandler(null);
} else {
channel.setMessageHandler((Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onStateChanged was null.');
final List<Object?> args = (message as List<Object?>?)!;
final int? arg_myStateNumber = (args[0] as int?);
assert(arg_myStateNumber != null,
'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onStateChanged was null, expected non-null int.');
api.onStateChanged(arg_myStateNumber!);
return;
});
}
}
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onDiscovered', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
channel.setMessageHandler(null);
} else {
channel.setMessageHandler((Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onDiscovered was null.');
final List<Object?> args = (message as List<Object?>?)!;
final MyPeripheralArgs? arg_myPeripheralArgs = (args[0] as MyPeripheralArgs?);
assert(arg_myPeripheralArgs != null,
'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onDiscovered was null, expected non-null MyPeripheralArgs.');
final int? arg_rssi = (args[1] as int?);
assert(arg_rssi != null,
'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onDiscovered was null, expected non-null int.');
final MyAdvertisementArgs? arg_myAdvertisementArgs = (args[2] as MyAdvertisementArgs?);
assert(arg_myAdvertisementArgs != null,
'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onDiscovered was null, expected non-null MyAdvertisementArgs.');
api.onDiscovered(arg_myPeripheralArgs!, arg_rssi!, arg_myAdvertisementArgs!);
return;
});
}
}
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onPeripheralStateChanged', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
channel.setMessageHandler(null);
} else {
channel.setMessageHandler((Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onPeripheralStateChanged was null.');
final List<Object?> args = (message as List<Object?>?)!;
final int? arg_myPeripheralKey = (args[0] as int?);
assert(arg_myPeripheralKey != null,
'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onPeripheralStateChanged was null, expected non-null int.');
final bool? arg_state = (args[1] as bool?);
assert(arg_state != null,
'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onPeripheralStateChanged was null, expected non-null bool.');
api.onPeripheralStateChanged(arg_myPeripheralKey!, arg_state!);
return;
});
}
}
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onCharacteristicValueChanged', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
channel.setMessageHandler(null);
} else {
channel.setMessageHandler((Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onCharacteristicValueChanged was null.');
final List<Object?> args = (message as List<Object?>?)!;
final int? arg_myCharacteristicKey = (args[0] as int?);
assert(arg_myCharacteristicKey != null,
'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onCharacteristicValueChanged was null, expected non-null int.');
final Uint8List? arg_value = (args[1] as Uint8List?);
assert(arg_value != null,
'Argument for dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralControllerFlutterApi.onCharacteristicValueChanged was null, expected non-null Uint8List.');
api.onCharacteristicValueChanged(arg_myCharacteristicKey!, arg_value!);
return;
});
}
}
}
}

View File

@ -0,0 +1,356 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_api.g.dart';
import 'my_gatt_characteristic.dart';
import 'my_gatt_descriptor.dart';
import 'my_gatt_service.dart';
import 'my_peripheral.dart';
class MyCentralController extends CentralController
implements MyCentralControllerFlutterApi {
MyCentralController()
: _myApi = MyCentralControllerHostApi(),
_stateChangedController = StreamController.broadcast(),
_discoveredController = StreamController.broadcast(),
_peripheralStateChangedController = StreamController.broadcast(),
_characteristicValueChangedController = StreamController.broadcast(),
_myPeripherals = {},
_myServices = {},
_myCharacteristics = {},
_myDescriptors = {},
_state = CentralState.unknown;
final MyCentralControllerHostApi _myApi;
final StreamController<CentralStateChangedEventArgs> _stateChangedController;
final StreamController<CentralDiscoveredEventArgs> _discoveredController;
final StreamController<PeripheralStateChangedEventArgs>
_peripheralStateChangedController;
final StreamController<GattCharacteristicValueChangedEventArgs>
_characteristicValueChangedController;
final Map<int, MyPeripheral> _myPeripherals;
final Map<int, MyGattService> _myServices;
final Map<int, MyGattCharacteristic> _myCharacteristics;
final Map<int, MyGattDescriptor> _myDescriptors;
CentralState _state;
@override
CentralState get state => _state;
@override
Stream<CentralStateChangedEventArgs> get stateChanged =>
_stateChangedController.stream;
@override
Stream<CentralDiscoveredEventArgs> get discovered =>
_discoveredController.stream;
@override
Stream<PeripheralStateChangedEventArgs> get peripheralStateChanged =>
_peripheralStateChangedController.stream;
@override
Stream<GattCharacteristicValueChangedEventArgs>
get characteristicValueChanged =>
_characteristicValueChangedController.stream;
Future<void> _throwWithState(CentralState state) async {
if (this.state == state) {
throw BluetoothLowEnergyError('$state is unexpected.');
}
}
Future<void> _throwWithoutState(CentralState state) async {
if (this.state != state) {
throw BluetoothLowEnergyError(
'$state is expected, but current state is ${this.state}.',
);
}
}
@override
Future<void> setUp() async {
await _throwWithoutState(CentralState.unknown);
final args = await _myApi.setUp();
final myStateArgs = MyCentralStateArgs.values[args.myStateNumber];
_state = myStateArgs.toState();
MyCentralControllerFlutterApi.setup(this);
}
@override
Future<void> tearDown() async {
await _throwWithState(CentralState.unknown);
await _myApi.tearDown();
MyCentralControllerFlutterApi.setup(null);
_myPeripherals.clear();
_myServices.clear();
_myCharacteristics.clear();
_myDescriptors.clear();
_state = CentralState.unknown;
}
@override
Future<void> startDiscovery() async {
await _throwWithoutState(CentralState.poweredOn);
await _myApi.startDiscovery();
}
@override
Future<void> stopDiscovery() async {
await _throwWithoutState(CentralState.poweredOn);
await _myApi.stopDiscovery();
}
@override
Future<void> connect(Peripheral peripheral) async {
await _throwWithoutState(CentralState.poweredOn);
final myPeripheral = peripheral as MyPeripheral;
await _myApi.connect(myPeripheral.hashCode);
}
@override
Future<void> disconnect(Peripheral peripheral) async {
await _throwWithoutState(CentralState.poweredOn);
final myPeripheral = peripheral as MyPeripheral;
await _myApi.disconnect(myPeripheral.hashCode);
}
@override
Future<void> discoverGATT(Peripheral peripheral) async {
await _throwWithoutState(CentralState.poweredOn);
final myPeripheral = peripheral as MyPeripheral;
await _myApi.discoverGATT(myPeripheral.hashCode);
}
@override
Future<List<GattService>> getServices(Peripheral peripheral) async {
await _throwWithoutState(CentralState.poweredOn);
final myPeripheral = peripheral as MyPeripheral;
final myServiceArgses = await _myApi.getServices(myPeripheral.hashCode);
return myServiceArgses
.cast<MyGattServiceArgs>()
.map(
(myServiceArgs) => _myServices.putIfAbsent(
myServiceArgs.key,
() => MyGattService.fromMyArgs(
myPeripheral,
myServiceArgs,
),
),
)
.toList();
}
@override
Future<List<GattCharacteristic>> getCharacteristics(
GattService service,
) async {
await _throwWithoutState(CentralState.poweredOn);
final myService = service as MyGattService;
final myCharactersiticArgses = await _myApi.getCharacteristics(
myService.hashCode,
);
return myCharactersiticArgses
.cast<MyGattCharacteristicArgs>()
.map(
(myCharacteristicArgs) => _myCharacteristics.putIfAbsent(
myCharacteristicArgs.key,
() => MyGattCharacteristic.fromMyArgs(
myService,
myCharacteristicArgs,
),
),
)
.toList();
}
@override
Future<List<GattDescriptor>> getDescriptors(
GattCharacteristic characteristic,
) async {
await _throwWithoutState(CentralState.poweredOn);
final myCharacteristic = characteristic as MyGattCharacteristic;
final myDescriptorArgses = await _myApi.getDescriptors(
myCharacteristic.hashCode,
);
return myDescriptorArgses
.cast<MyGattDescriptorArgs>()
.map(
(myDescriptorArgs) => _myDescriptors.putIfAbsent(
myDescriptorArgs.key,
() => MyGattDescriptor.fromMyArgs(
myCharacteristic,
myDescriptorArgs,
),
),
)
.toList();
}
@override
Future<Uint8List> readCharacteristic(
GattCharacteristic characteristic) async {
await _throwWithoutState(CentralState.poweredOn);
final myCharacteristic = characteristic as MyGattCharacteristic;
final myService = myCharacteristic.myService;
final myPeripheral = myService.myPeripheral;
final value = await _myApi.readCharacteristic(
myPeripheral.hashCode,
myCharacteristic.hashCode,
);
return value;
}
@override
Future<void> writeCharacteristic(
GattCharacteristic characteristic, {
required Uint8List value,
required GattCharacteristicWriteType type,
}) async {
await _throwWithoutState(CentralState.poweredOn);
final myCharacteristic = characteristic as MyGattCharacteristic;
final myService = myCharacteristic.myService;
final myPeripheral = myService.myPeripheral;
final typeArgs = type.toMyArgs();
final typeNumber = typeArgs.index;
await _myApi.writeCharacteristic(
myPeripheral.hashCode,
myCharacteristic.hashCode,
value,
typeNumber,
);
}
@override
Future<void> notifyCharacteristic(
GattCharacteristic characteristic, {
required bool state,
}) async {
await _throwWithoutState(CentralState.poweredOn);
final myCharacteristic = characteristic as MyGattCharacteristic;
final myService = myCharacteristic.myService;
final myPeripheral = myService.myPeripheral;
await _myApi.notifyCharacteristic(
myPeripheral.hashCode,
myCharacteristic.hashCode,
state,
);
}
@override
Future<Uint8List> readDescriptor(GattDescriptor descriptor) async {
await _throwWithoutState(CentralState.poweredOn);
final myDescriptor = descriptor as MyGattDescriptor;
final myCharacteristic = myDescriptor.myCharacteristic;
final myService = myCharacteristic.myService;
final myPeripheral = myService.myPeripheral;
final value = await _myApi.readDescriptor(
myPeripheral.hashCode,
myDescriptor.hashCode,
);
return value;
}
@override
Future<void> writeDescriptor(
GattDescriptor descriptor, {
required Uint8List value,
}) async {
await _throwWithoutState(CentralState.poweredOn);
final myDescriptor = descriptor as MyGattDescriptor;
final myCharacteristic = myDescriptor.myCharacteristic;
final myService = myCharacteristic.myService;
final myPeripheral = myService.myPeripheral;
await _myApi.writeDescriptor(
myPeripheral.hashCode,
myDescriptor.hashCode,
value,
);
}
@override
void onStateChanged(int myStateNumber) {
final myStateArgs = MyCentralStateArgs.values[myStateNumber];
final state = myStateArgs.toState();
if (_state == state) {
return;
}
_state = state;
final eventArgs = CentralStateChangedEventArgs(state);
_stateChangedController.add(eventArgs);
}
@override
void onDiscovered(
MyPeripheralArgs myPeripheralArgs,
int rssi,
MyAdvertisementArgs myAdvertisementArgs,
) {
final myPeripheral = _myPeripherals.putIfAbsent(
myPeripheralArgs.key,
() => MyPeripheral.fromMyArgs(myPeripheralArgs),
);
final advertisement = myAdvertisementArgs.toAdvertisement();
final eventArgs = CentralDiscoveredEventArgs(
myPeripheral,
rssi,
advertisement,
);
_discoveredController.add(eventArgs);
}
@override
void onPeripheralStateChanged(int myPeripheralKey, bool state) {
final myPeripheral = _myPeripherals[myPeripheralKey];
if (myPeripheral == null) {
return;
}
final eventArgs = PeripheralStateChangedEventArgs(myPeripheral, state);
_peripheralStateChangedController.add(eventArgs);
}
@override
void onCharacteristicValueChanged(int myCharacteristicKey, Uint8List value) {
final myCharacteristic =
_myCharacteristics[myCharacteristicKey] as MyGattCharacteristic;
final eventArgs = GattCharacteristicValueChangedEventArgs(
myCharacteristic,
value,
);
_characteristicValueChangedController.add(eventArgs);
}
}
extension on MyAdvertisementArgs {
Advertisement toAdvertisement() {
final serviceUUIDs = this
.serviceUUIDs
.cast<String>()
.map((uuid) => UUID.fromString(uuid))
.toList();
final serviceData = this.serviceData.cast<String, Uint8List>().map(
(uuid, data) {
final key = UUID.fromString(uuid);
final value = data;
return MapEntry(key, value);
},
);
return Advertisement(
name: name,
manufacturerSpecificData: manufacturerSpecificData.cast<int, Uint8List>(),
serviceUUIDs: serviceUUIDs,
serviceData: serviceData,
);
}
}
extension on MyCentralStateArgs {
CentralState toState() {
return CentralState.values[index];
}
}
extension on GattCharacteristicWriteType {
MyGattCharacteristicWriteTypeArgs toMyArgs() {
return MyGattCharacteristicWriteTypeArgs.values[index];
}
}

View File

@ -0,0 +1,42 @@
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_api.g.dart';
import 'my_gatt_service.dart';
import 'my_object.dart';
class MyGattCharacteristic extends MyObject implements GattCharacteristic {
final MyGattService myService;
@override
final UUID uuid;
@override
final List<GattCharacteristicProperty> properties;
MyGattCharacteristic(
super.hashCode,
this.myService,
this.uuid,
this.properties,
);
factory MyGattCharacteristic.fromMyArgs(
MyGattService myService,
MyGattCharacteristicArgs myArgs,
) {
final hashCode = myArgs.key;
final uuid = UUID.fromString(myArgs.uuid);
final properties = myArgs.myPropertyNumbers.cast<int>().map(
(myPropertyNumber) {
final myPropertyArgs =
MyGattCharacteristicPropertyArgs.values[myPropertyNumber];
return myPropertyArgs.toProperty();
},
).toList();
return MyGattCharacteristic(hashCode, myService, uuid, properties);
}
}
extension on MyGattCharacteristicPropertyArgs {
GattCharacteristicProperty toProperty() {
return GattCharacteristicProperty.values[index];
}
}

View File

@ -0,0 +1,22 @@
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_api.g.dart';
import 'my_gatt_characteristic.dart';
import 'my_object.dart';
class MyGattDescriptor extends MyObject implements GattDescriptor {
final MyGattCharacteristic myCharacteristic;
@override
final UUID uuid;
MyGattDescriptor(super.hashCode, this.myCharacteristic, this.uuid);
factory MyGattDescriptor.fromMyArgs(
MyGattCharacteristic myCharacteristic,
MyGattDescriptorArgs myArgs,
) {
final hashCode = myArgs.key;
final uuid = UUID.fromString(myArgs.uuid);
return MyGattDescriptor(hashCode, myCharacteristic, uuid);
}
}

View File

@ -0,0 +1,22 @@
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_api.g.dart';
import 'my_object.dart';
import 'my_peripheral.dart';
class MyGattService extends MyObject implements GattService {
final MyPeripheral myPeripheral;
@override
final UUID uuid;
MyGattService(super.hashCode, this.myPeripheral, this.uuid);
factory MyGattService.fromMyArgs(
MyPeripheral myPeripheral,
MyGattServiceArgs myArgs,
) {
final hashCode = myArgs.key;
final uuid = UUID.fromString(myArgs.uuid);
return MyGattService(hashCode, myPeripheral, uuid);
}
}

View File

@ -0,0 +1,11 @@
abstract class MyObject {
@override
final int hashCode;
MyObject(this.hashCode);
@override
bool operator ==(Object other) {
return other is MyObject && other.hashCode == hashCode;
}
}

View File

@ -0,0 +1,17 @@
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
import 'my_api.g.dart';
import 'my_object.dart';
class MyPeripheral extends MyObject implements Peripheral {
@override
final UUID uuid;
MyPeripheral(super.hashCode, this.uuid);
factory MyPeripheral.fromMyArgs(MyPeripheralArgs myArgs) {
final hashCode = myArgs.key;
final uuid = UUID.fromString(myArgs.uuid);
return MyPeripheral(hashCode, uuid);
}
}

View File

@ -0,0 +1,144 @@
import 'package:pigeon/pigeon.dart';
@ConfigurePigeon(
PigeonOptions(
dartOut: 'lib/src/my_api.g.dart',
dartOptions: DartOptions(),
kotlinOut:
'android/src/main/kotlin/dev/yanshouwang/bluetooth_low_energy/MyApi.g.kt',
kotlinOptions: KotlinOptions(
package: 'dev.yanshouwang.bluetooth_low_energy',
),
),
)
@HostApi()
abstract class MyCentralControllerHostApi {
@async
MyCentralControllerArgs setUp();
void tearDown();
@async
void startDiscovery();
void stopDiscovery();
@async
void connect(int myPeripheralKey);
@async
void disconnect(int myPeripheralKey);
@async
void discoverGATT(int myPeripheralKey);
List<MyGattServiceArgs> getServices(int myPeripheralKey);
List<MyGattCharacteristicArgs> getCharacteristics(int myServiceKey);
List<MyGattDescriptorArgs> getDescriptors(int myCharacteristicKey);
@async
Uint8List readCharacteristic(int myPeripheralKey, int myCharacteristicKey);
@async
void writeCharacteristic(
int myPeripheralKey,
int myCharacteristicKey,
Uint8List value,
int myTypeNumber,
);
@async
void notifyCharacteristic(
int myPeripheralKey,
int myCharacteristicKey,
bool state,
);
@async
Uint8List readDescriptor(int myPeripheralKey, int myDescriptorKey);
@async
void writeDescriptor(
int myPeripheralKey,
int myDescriptorKey,
Uint8List value,
);
}
@FlutterApi()
abstract class MyCentralControllerFlutterApi {
void onStateChanged(int myStateNumber);
void onDiscovered(
MyPeripheralArgs myPeripheralArgs,
int rssi,
MyAdvertisementArgs myAdvertisementArgs,
);
void onPeripheralStateChanged(int myPeripheralKey, bool state);
void onCharacteristicValueChanged(int myCharacteristicKey, Uint8List value);
}
class MyCentralControllerArgs {
final int myStateNumber;
MyCentralControllerArgs(this.myStateNumber);
}
class MyPeripheralArgs {
final int key;
final String uuid;
MyPeripheralArgs(this.key, this.uuid);
}
class MyAdvertisementArgs {
final String? name;
final Map<int?, Uint8List?> manufacturerSpecificData;
final List<String?> serviceUUIDs;
final Map<String?, Uint8List?> serviceData;
MyAdvertisementArgs(
this.name,
this.manufacturerSpecificData,
this.serviceUUIDs,
this.serviceData,
);
}
class MyGattServiceArgs {
final int key;
final String uuid;
MyGattServiceArgs(this.key, this.uuid);
}
class MyGattCharacteristicArgs {
final int key;
final String uuid;
final List<int?> myPropertyNumbers;
MyGattCharacteristicArgs(
this.key,
this.uuid,
this.myPropertyNumbers,
);
}
class MyGattDescriptorArgs {
final int key;
final String uuid;
MyGattDescriptorArgs(this.key, this.uuid);
}
enum MyCentralStateArgs {
unknown,
unsupported,
unauthorized,
poweredOff,
poweredOn,
}
enum MyGattCharacteristicPropertyArgs {
read,
write,
writeWithoutResponse,
notify,
indicate,
}
enum MyGattCharacteristicWriteTypeArgs {
// Write with response
withResponse,
// Write without response
withoutResponse,
// Write with response and waiting for confirmation
// reliable,
}

View File

@ -0,0 +1,29 @@
name: bluetooth_low_energy_android
description: Android implementation of the bluetooth_low_energy plugin.
version: 2.0.0
homepage: https://github.com/yanshouwang/bluetooth_low_energy
environment:
sdk: ">=3.0.0 <4.0.0"
flutter: ">=3.3.0"
dependencies:
flutter:
sdk: flutter
bluetooth_low_energy_platform_interface:
path: ../bluetooth_low_energy_platform_interface
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
pigeon: ^10.1.6
flutter:
plugin:
implements: bluetooth_low_energy
platforms:
android:
package: dev.yanshouwang.bluetooth_low_energy
pluginClass: BluetoothLowEnergyAndroid
dartPluginClass: BluetoothLowEnergyAndroid