get() = _deviceState
22 |
23 | init {
24 | delegate.setListener {event ->
25 | when(event) {
26 | is DeviceEvent.OnDeviceConnected -> {
27 | _deviceState.update { state ->
28 | val updateDevices = state.devices.toMutableMap()
29 | updateDevices[event.macId]?.let {
30 | updateDevices[event.macId] = it.copy(connected = true)
31 | }
32 | state.copy(
33 | devices = HashMap(updateDevices)
34 | )
35 | }
36 | }
37 |
38 | is DeviceEvent.OnDeviceDisconnected -> {
39 | _deviceState.update { state ->
40 | val updateDevices = state.devices.toMutableMap()
41 | updateDevices[event.macId]?.let {
42 | updateDevices[event.macId] = it.copy(connected = false)
43 | }
44 | state.copy(
45 | devices = HashMap(updateDevices)
46 | )
47 | }
48 | }
49 | }
50 | }
51 | blueFalcon.delegates.add(delegate)
52 | CoroutineScope(Dispatchers.IO).launch {
53 | blueFalcon.peripherals.collect { peripherals ->
54 | val uniqueKeys = _deviceState.value.devices.keys.toList()
55 | val filteredPeripheral = peripherals.filter { !uniqueKeys.contains(it.uuid) }
56 | filteredPeripheral.map { peripheral ->
57 | _deviceState.update {
58 | val updateDevices = it.devices.toMutableMap()
59 | updateDevices[peripheral.uuid] = EnhancedBluetoothPeripheral(false, peripheral)
60 | it.copy(
61 | devices = HashMap(updateDevices)
62 | )
63 | }
64 | }
65 | }
66 | }
67 | }
68 |
69 | fun onEvent(event: UiEvent) {
70 | when(event) {
71 | UiEvent.OnScanClick -> {
72 | blueFalcon.scan()
73 | }
74 |
75 | is UiEvent.OnConnectClick -> {
76 | _deviceState.value.devices[event.macId]?.let {
77 | blueFalcon.connect(it.peripheral, false)
78 | }
79 | }
80 |
81 | is UiEvent.OnDisconnectClick -> {
82 | _deviceState.value.devices[event.macId]?.let {
83 | blueFalcon.disconnect(it.peripheral)
84 | }
85 | }
86 |
87 | is UiEvent.OnReadCharacteristic -> {
88 | _deviceState.value.devices[event.macId]?.let {
89 | blueFalcon.readCharacteristic(it.peripheral, event.characteristic)
90 | }
91 | }
92 | is UiEvent.OnWriteCharacteristic -> {
93 | _deviceState.value.devices[event.macId]?.let {
94 | blueFalcon.writeCharacteristic(it.peripheral, event.characteristic, event.value, null)
95 | }
96 | }
97 | }
98 | }
99 | }
--------------------------------------------------------------------------------
/examples/JS-Example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Javascript External Script
6 |
7 |
8 |
9 |
10 |
11 |
12 |
58 |
59 | Blue Falcon JS Example
60 |
61 | Enter a bluetooth service uuid and press the scan button, for example: 000000ee-0000-1000-8000-00805f9b34fb
62 |
63 |
64 |
65 |
66 |
67 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/library/src/commonMain/kotlin/dev/bluefalcon/BlueFalcon.kt:
--------------------------------------------------------------------------------
1 | package dev.bluefalcon
2 |
3 | import kotlinx.coroutines.CoroutineScope
4 | import kotlinx.coroutines.flow.MutableStateFlow
5 | import kotlinx.coroutines.flow.StateFlow
6 |
7 | expect class BlueFalcon(
8 | log: Logger? = PrintLnLogger,
9 | context: ApplicationContext,
10 | autoDiscoverAllServicesAndCharacteristics: Boolean = true
11 | ) {
12 |
13 | val scope: CoroutineScope
14 |
15 | val delegates: MutableSet
16 | var isScanning: Boolean
17 |
18 | val managerState: StateFlow
19 |
20 | internal val _peripherals: MutableStateFlow>
21 | val peripherals: NativeFlow>
22 |
23 | fun connect(bluetoothPeripheral: BluetoothPeripheral, autoConnect: Boolean = false)
24 | fun disconnect(bluetoothPeripheral: BluetoothPeripheral)
25 |
26 | /**
27 | * Retrieves a peripheral by its platform-specific identifier.
28 | *
29 | * @param identifier The platform-specific identifier:
30 | * - **Android**: MAC address format (e.g., "00:11:22:33:44:55")
31 | * - **iOS/Native**: UUID format (e.g., "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
32 | * @return The BluetoothPeripheral if found, null otherwise
33 | */
34 | fun retrievePeripheral(identifier: String): BluetoothPeripheral?
35 |
36 | fun requestConnectionPriority(bluetoothPeripheral: BluetoothPeripheral, connectionPriority: ConnectionPriority)
37 |
38 | fun connectionState(bluetoothPeripheral: BluetoothPeripheral): BluetoothPeripheralState
39 |
40 | @Throws(
41 | BluetoothUnknownException::class,
42 | BluetoothResettingException::class,
43 | BluetoothUnsupportedException::class,
44 | BluetoothPermissionException::class,
45 | BluetoothNotEnabledException::class
46 | )
47 | fun scan(filters: List = emptyList())
48 |
49 | fun clearPeripherals()
50 |
51 | fun stopScanning()
52 |
53 | fun discoverServices(bluetoothPeripheral: BluetoothPeripheral, serviceUUIDs: List = emptyList())
54 |
55 | fun discoverCharacteristics(
56 | bluetoothPeripheral: BluetoothPeripheral,
57 | bluetoothService: BluetoothService,
58 | characteristicUUIDs: List = emptyList()
59 | )
60 |
61 | fun readCharacteristic(
62 | bluetoothPeripheral: BluetoothPeripheral,
63 | bluetoothCharacteristic: BluetoothCharacteristic
64 | )
65 |
66 | fun notifyCharacteristic(
67 | bluetoothPeripheral: BluetoothPeripheral,
68 | bluetoothCharacteristic: BluetoothCharacteristic,
69 | notify: Boolean
70 | )
71 |
72 | fun indicateCharacteristic(
73 | bluetoothPeripheral: BluetoothPeripheral,
74 | bluetoothCharacteristic: BluetoothCharacteristic,
75 | indicate: Boolean
76 | )
77 |
78 | fun notifyAndIndicateCharacteristic(
79 | bluetoothPeripheral: BluetoothPeripheral,
80 | bluetoothCharacteristic: BluetoothCharacteristic,
81 | enable: Boolean
82 | )
83 |
84 | fun writeCharacteristic(
85 | bluetoothPeripheral: BluetoothPeripheral,
86 | bluetoothCharacteristic: BluetoothCharacteristic,
87 | value: String,
88 | writeType: Int?
89 | )
90 |
91 | fun writeCharacteristic(
92 | bluetoothPeripheral: BluetoothPeripheral,
93 | bluetoothCharacteristic: BluetoothCharacteristic,
94 | value: ByteArray,
95 | writeType: Int?
96 | )
97 |
98 | fun writeCharacteristicWithoutEncoding(
99 | bluetoothPeripheral: BluetoothPeripheral,
100 | bluetoothCharacteristic: BluetoothCharacteristic,
101 | value: ByteArray,
102 | writeType: Int?
103 | )
104 |
105 | fun readDescriptor(
106 | bluetoothPeripheral: BluetoothPeripheral,
107 | bluetoothCharacteristic: BluetoothCharacteristic,
108 | bluetoothCharacteristicDescriptor: BluetoothCharacteristicDescriptor
109 | )
110 |
111 | fun writeDescriptor(
112 | bluetoothPeripheral: BluetoothPeripheral,
113 | bluetoothCharacteristicDescriptor: BluetoothCharacteristicDescriptor,
114 | value: ByteArray
115 | )
116 |
117 | fun changeMTU(bluetoothPeripheral: BluetoothPeripheral, mtuSize: Int)
118 |
119 | }
120 |
121 | enum class BluetoothManagerState {
122 | Ready, NotReady
123 | }
124 |
--------------------------------------------------------------------------------
/library/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import java.util.*
2 | import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
3 |
4 | plugins {
5 | kotlin("multiplatform") version "2.0.20"
6 | id("com.android.library")
7 | id("com.vanniktech.maven.publish") version "0.34.0"
8 | id("signing")
9 | }
10 |
11 | repositories {
12 | google()
13 | mavenCentral()
14 | google()
15 | maven("https://jitpack.io")
16 | mavenLocal()
17 | }
18 |
19 | val local = Properties()
20 | val localProperties: File = rootProject.file("local.properties")
21 | if (localProperties.exists()) {
22 | localProperties.inputStream().use { local.load(it) }
23 | }
24 | val projectGithubUrl: String by project
25 | val projectGithubSCM: String by project
26 | val projectGithubSCMSSL: String by project
27 | val projectDescription: String by project
28 |
29 | val developerId: String by project
30 | val developerName: String by project
31 | val developerEmail: String by project
32 | val group: String by project
33 | val libraryName: String by project
34 | val version: String by project
35 |
36 | val kotlinx_coroutines_version: String by project
37 |
38 | android {
39 | compileSdk = 33
40 | sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
41 | namespace = "dev.bluefalcon.blueFalcon"
42 | defaultConfig {
43 | minSdk = 24
44 | targetSdk = 33
45 | }
46 | lint {
47 | disable += "MissingPermission"
48 | }
49 | }
50 |
51 | val frameworkName = "BlueFalcon"
52 |
53 | kotlin.sourceSets.all {
54 | languageSettings.optIn("kotlin.uuid.ExperimentalUuidApi")
55 | }
56 |
57 | kotlin {
58 | jvmToolchain(17)
59 | androidTarget {
60 | publishAllLibraryVariants()
61 | }
62 | // jvm("rpi") {
63 | // compilations.all {
64 | // kotlinOptions.jvmTarget = "1.8"
65 | // }
66 | // }
67 | js {
68 | browser {
69 | binaries.executable()
70 | }
71 | }
72 | iosSimulatorArm64()
73 | iosX64()
74 | iosArm64()
75 | macosArm64()
76 | macosX64()
77 |
78 | sourceSets {
79 | val commonMain by getting {
80 | dependencies {
81 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinx_coroutines_version")
82 | }
83 | }
84 | val commonTest by getting {
85 | dependencies {
86 | implementation(kotlin("test-common"))
87 | implementation(kotlin("test-annotations-common"))
88 | }
89 | }
90 | val androidMain by getting
91 | // val rpiMain by getting {
92 | // dependencies {
93 | // implementation("com.github.weliem:blessed-bluez:0.38")
94 | // }
95 | // }
96 | val jsMain by getting
97 | }
98 | }
99 |
100 | mavenPublishing {
101 | publishToMavenCentral(automaticRelease = true)
102 | signAllPublications()
103 |
104 | coordinates(
105 | groupId = group,
106 | artifactId = libraryName,
107 | version = version
108 | )
109 |
110 | pom {
111 | name.set(group)
112 | description.set(projectDescription)
113 | url.set(projectGithubUrl)
114 |
115 | licenses {
116 | license {
117 | name.set("MIT License")
118 | url.set("http://opensource.org/licenses/MIT")
119 | }
120 | }
121 |
122 | developers {
123 | developer {
124 | id.set(developerId)
125 | name.set(developerName)
126 | email.set(developerEmail)
127 | }
128 | }
129 |
130 | scm {
131 | url.set(projectGithubUrl)
132 | connection.set(projectGithubSCM)
133 | developerConnection.set(projectGithubSCMSSL)
134 | }
135 | }
136 | }
137 |
138 | val javadocJar by tasks.creating(Jar::class) {
139 | archiveClassifier.value("javadoc")
140 | }
141 |
142 | signing {
143 | setRequired {
144 | !gradle.taskGraph.allTasks.any { it is PublishToMavenLocal }
145 | }
146 | val key = local.getProperty("signingKey") ?: System.getenv("SIGNING_KEY")
147 | val password = local.getProperty("signingPassword") ?: System.getenv("SIGNING_PASSWORD")
148 | if (key != null && password != null) {
149 | useInMemoryPgpKeys(key, password)
150 | sign(publishing.publications) // This ensures all created publications are signed
151 | } else {
152 | // Optional: Log a warning if keys are missing for a release build
153 | logger.warn("Signing key or password not found. Publication will not be signed.")
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/library/src/nativeMain/kotlin/dev/bluefalcon/PeripheralDelegate.kt:
--------------------------------------------------------------------------------
1 | package dev.bluefalcon
2 |
3 | import kotlinx.cinterop.ObjCSignatureOverride
4 | import platform.CoreBluetooth.*
5 | import platform.Foundation.NSError
6 | import platform.darwin.NSObject
7 |
8 | class PeripheralDelegate constructor(
9 | private val log: Logger?,
10 | private val blueFalcon: BlueFalcon
11 | ) : NSObject(), CBPeripheralDelegateProtocol {
12 |
13 | override fun peripheral(peripheral: CBPeripheral, didDiscoverServices: NSError?) {
14 | if (didDiscoverServices != null) {
15 | log?.error("Error with service discovery ${didDiscoverServices}")
16 | } else {
17 | log?.info("didDiscoverServices")
18 | val device = BluetoothPeripheral(peripheral, rssiValue = null)
19 | blueFalcon.delegates.forEach {
20 | it.didDiscoverServices(device)
21 | }
22 | if (blueFalcon.autoDiscoverAllServicesAndCharacteristics) {
23 | peripheral.services
24 | ?.mapNotNull { it as? CBService }
25 | ?.forEach {
26 | peripheral.discoverCharacteristics(null, it)
27 | }
28 | }
29 | }
30 | }
31 |
32 | override fun peripheral(
33 | peripheral: CBPeripheral,
34 | didDiscoverCharacteristicsForService: CBService,
35 | error: NSError?
36 | ) {
37 | if (error != null) {
38 | log?.error("Error with characteristic discovery ${didDiscoverCharacteristicsForService}")
39 | }
40 | log?.info("didDiscoverCharacteristicsForService")
41 | val device = BluetoothPeripheral(peripheral, rssiValue = null)
42 | blueFalcon.delegates.forEach {
43 | it.didDiscoverCharacteristics(device)
44 | }
45 | BluetoothService(didDiscoverCharacteristicsForService).characteristics.forEach {
46 | peripheral.discoverDescriptorsForCharacteristic(it.characteristic)
47 | }
48 | }
49 |
50 | @ObjCSignatureOverride
51 | override fun peripheral(
52 | peripheral: CBPeripheral,
53 | didWriteValueForCharacteristic: CBCharacteristic,
54 | error: NSError?
55 | ) {
56 | if (error != null) {
57 | log?.error("Error with characteristic write $error")
58 | }
59 | val device = BluetoothPeripheral(peripheral, rssiValue = null)
60 | val characteristic = BluetoothCharacteristic(didWriteValueForCharacteristic)
61 | blueFalcon.delegates.forEach {
62 | it.didWriteCharacteristic(
63 | device,
64 | characteristic,
65 | error != null,
66 | )
67 | }
68 | }
69 |
70 | @ObjCSignatureOverride
71 | override fun peripheral(
72 | peripheral: CBPeripheral,
73 | didUpdateValueForCharacteristic: CBCharacteristic,
74 | error: NSError?
75 | ) {
76 | if (error != null) {
77 | log?.error("Error with characteristic update ${error}")
78 | }
79 | val device = BluetoothPeripheral(peripheral, rssiValue = null)
80 | val characteristic = BluetoothCharacteristic(didUpdateValueForCharacteristic)
81 | blueFalcon.delegates.forEach {
82 | it.didCharacteristcValueChanged(
83 | device,
84 | characteristic
85 | )
86 | }
87 | }
88 | override fun peripheral(
89 | peripheral: CBPeripheral,
90 | didWriteValueForDescriptor: CBDescriptor,
91 | error: NSError?
92 | ) {
93 | if (error != null) {
94 | log?.error("Error during characteristic write $error")
95 | }
96 |
97 | log?.info("didWriteValueForCharacteristic")
98 | val device = BluetoothPeripheral(peripheral, rssiValue = null)
99 | didWriteValueForDescriptor.characteristic?.let { characteristic ->
100 | val characteristic = BluetoothCharacteristic(characteristic)
101 | blueFalcon.delegates.forEach {
102 | it.didWriteCharacteristic(
103 | device,
104 | characteristic,
105 | error == null
106 | )
107 | }
108 | }
109 | }
110 |
111 | @ObjCSignatureOverride
112 | override fun peripheral(
113 | peripheral: CBPeripheral,
114 | didDiscoverDescriptorsForCharacteristic: CBCharacteristic,
115 | error: NSError?
116 | ) {
117 | if (error != null) {
118 | log?.error("Error discovering descriptors for characteristic ${didDiscoverDescriptorsForCharacteristic.UUID}: $error")
119 | } else {
120 | log?.info("didDiscoverDescriptorsForCharacteristic ${didDiscoverDescriptorsForCharacteristic.UUID}")
121 | }
122 | // Descriptors are discovered automatically by BlueFalcon
123 | // This method is required by iOS to avoid API misuse warnings
124 | }
125 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | captures
3 | .gradle
4 | .idea
5 | bin
6 | gen
7 | out
8 | *.iml
9 | .directory
10 | node_modules
11 | local.properties
12 | android/mobile/release/*
13 | ios.xcworkspace/
14 |
15 | *.hprof
16 |
17 | .DS_Store
18 | .externalNativeBuild
19 |
20 | ## Build generated
21 | build/
22 | DerivedData
23 | build.xcarchive
24 |
25 | ## Various settings
26 | *.pbxuser
27 | !default.pbxuser
28 | *.mode1v3
29 | !default.mode1v3
30 | *.mode2v3
31 | !default.mode2v3
32 | *.perspectivev3
33 | !default.perspectivev3
34 | xcuserdata
35 |
36 | ## Other
37 | *.xccheckout
38 | *.moved-aside
39 | *.xcuserstate
40 | *.xcscmblueprint
41 |
42 | ## Obj-C/Swift specific
43 | *.hmap
44 | *.ipa
45 |
46 | # CocoaPods
47 | Pods/
48 |
49 | # Carthage
50 | Carthage/Checkouts
51 | Carthage/Build
52 |
53 | apps/epax-ios/DerivedData/
54 | */DerivedData/
55 | */Carthage/Checkouts
56 | */Carthage/Build
57 | */Pods/
58 |
59 |
60 | # Xcode
61 | #
62 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
63 |
64 | ## User settings
65 | xcuserdata/
66 |
67 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
68 | *.xcscmblueprint
69 | *.xccheckout
70 |
71 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
72 | build/
73 | DerivedData/
74 | *.moved-aside
75 | *.pbxuser
76 | !default.pbxuser
77 | *.mode1v3
78 | !default.mode1v3
79 | *.mode2v3
80 | !default.mode2v3
81 | *.perspectivev3
82 | !default.perspectivev3
83 |
84 | ## Obj-C/Swift specific
85 | *.hmap
86 |
87 | ## App packaging
88 | *.ipa
89 | *.dSYM.zip
90 | *.dSYM
91 |
92 | ## Playgrounds
93 | timeline.xctimeline
94 | playground.xcworkspace
95 |
96 | # Swift Package Manager
97 | #
98 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
99 | # Packages/
100 | # Package.pins
101 | # Package.resolved
102 | # *.xcodeproj
103 | #
104 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
105 | # hence it is not needed unless you have added a package configuration file to your project
106 | # .swiftpm
107 |
108 | .build/
109 |
110 | # CocoaPods
111 | #
112 | # We recommend against adding the Pods directory to your .gitignore. However
113 | # you should judge for yourself, the pros and cons are mentioned at:
114 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
115 | #
116 | # Pods/
117 | #
118 | # Add this line if you want to avoid checking in source code from the Xcode workspace
119 | # *.xcworkspace
120 |
121 | # Carthage
122 | #
123 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
124 | # Carthage/Checkouts
125 |
126 | Carthage/Build/
127 |
128 | # Accio dependency management
129 | Dependencies/
130 | .accio/
131 |
132 | # fastlane
133 | #
134 | # It is recommended to not store the screenshots in the git repo.
135 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
136 | # For more information about the recommended setup visit:
137 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
138 |
139 | fastlane/report.xml
140 | fastlane/Preview.html
141 | fastlane/screenshots/**/*.png
142 | fastlane/test_output
143 |
144 | # Code Injection
145 | #
146 | # After new code Injection tools there's a generated folder /iOSInjectionProject
147 | # https://github.com/johnno1962/injectionforxcode
148 |
149 | iOSInjectionProject/
150 |
151 | # Built application files
152 | *.apk
153 | *.ap_
154 | *.aab
155 |
156 | # Files for the ART/Dalvik VM
157 | *.dex
158 |
159 | # Java class files
160 | *.class
161 |
162 | # Generated files
163 | bin/
164 | gen/
165 | out/
166 | release/
167 |
168 | # Gradle files
169 | .gradle/
170 | build/
171 |
172 | # Local configuration file (sdk path, etc)
173 | local.properties
174 |
175 | # Proguard folder generated by Eclipse
176 | proguard/
177 |
178 | # Log Files
179 | *.log
180 |
181 | # Android Studio Navigation editor temp files
182 | .navigation/
183 |
184 | # Android Studio captures folder
185 | captures/
186 |
187 | # IntelliJ
188 | *.iml
189 | .idea/workspace.xml
190 | .idea/tasks.xml
191 | .idea/gradle.xml
192 | .idea/assetWizardSettings.xml
193 | .idea/dictionaries
194 | .idea/libraries
195 | # Android Studio 3 in .gitignore file.
196 | .idea/caches
197 | .idea/modules.xml
198 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
199 | .idea/navEditor.xml
200 |
201 | # Keystore files
202 | # Uncomment the following lines if you do not want to check your keystore files in.
203 | #*.jks
204 | #*.keystore
205 |
206 | # External native build folder generated in Android Studio 2.2 and later
207 | .externalNativeBuild
208 |
209 | # Google Services (e.g. APIs or Firebase)
210 | # google-services.json
211 |
212 | # Freeline
213 | freeline.py
214 | freeline/
215 | freeline_project_description.json
216 |
217 | # fastlane
218 | fastlane/report.xml
219 | fastlane/Preview.html
220 | fastlane/screenshots
221 | fastlane/test_output
222 | fastlane/readme.md
223 |
224 | # Version control
225 | vcs.xml
226 |
227 | # lint
228 | lint/intermediates/
229 | lint/generated/
230 | lint/outputs/
231 | lint/tmp/
232 | # lint/reports/
233 |
234 | .shared-*
235 | .kotlin
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #  Blue-Falcon  [](http://kotlinlang.org) ![badge][badge-android] ![badge][badge-native] ![badge][badge-mac] ![badge][badge-rpi] ![badge][badge-js]
2 |
3 | A Bluetooth BLE "Cross Platform" Kotlin Multiplatform library for iOS, Android, MacOS, Raspberry Pi and Javascript.
4 |
5 | BLE in general has the same functionality for all platforms, e.g. connect to device, fetch services, fetch characteristics.
6 |
7 | This library is the glue that brings those together so that mobile developers can use one common api to perform the BLE actions.
8 |
9 | The idea is to have a common api for BLE devices as the principle of BLE is the same but each platform ios and android has different apis which means you have to duplicate the logic for each platform.
10 |
11 | What this library isn't? It is not a cross platform library, this is a multiplatform library. The difference? each platform is compiled down to the native code, so when you use the library in iOS, you are consuming an obj-c library and same principle for Android and so on.
12 |
13 | ## Basic Usage
14 |
15 | Include the library in your own KMP project as a dependency on your common target.
16 |
17 | ```
18 | commonMain.dependencies {
19 | implementation("dev.bluefalcon:blue-falcon:2.0.0")
20 | }
21 | ```
22 |
23 | Once you have included it then you will need to create an instance of BlueFalcon and pass in an application context.
24 |
25 | The Android sdk requires an Application context, we do this by passing in on the BlueFalcon constructor, in this example we are calling the code from an activity(this).
26 |
27 | By passing in a string uuid of the service uuid, you can filter to scan for only devices that have that service.
28 |
29 | ```kotlin
30 | try {
31 | val blueFalcon = BlueFalcon(log = null, ApplicationContext())
32 | blueFalcon.scan()
33 | } catch (exception: PermissionException) {
34 | //request the ACCESS_COARSE_LOCATION permission
35 | }
36 | ```
37 |
38 | ### Javascript
39 |
40 | #### Install
41 |
42 | Simply copy the compiled javascript file (blue-falcon.js) to your web directory.
43 |
44 | See the JS-Example for details on how to use.
45 |
46 | ### BlueFalcon API
47 |
48 | The basic functionality of the api is listed below, this should be a simplistic as possible and is the same in any platform.
49 |
50 | ```kotlin
51 | fun connect(bluetoothPeripheral: BluetoothPeripheral, autoConnect: Boolean)
52 | fun disconnect(bluetoothPeripheral: BluetoothPeripheral)
53 | fun scan()
54 | fun stopScanning()
55 | fun readCharacteristic(
56 | bluetoothPeripheral: BluetoothPeripheral,
57 | bluetoothCharacteristic: BluetoothCharacteristic
58 | )
59 | fun notifyCharacteristic(
60 | bluetoothPeripheral: BluetoothPeripheral,
61 | bluetoothCharacteristic: BluetoothCharacteristic,
62 | notify: Boolean
63 | )
64 | fun writeCharacteristic(
65 | bluetoothPeripheral: BluetoothPeripheral,
66 | bluetoothCharacteristic: BluetoothCharacteristic,
67 | value: String
68 | )
69 | fun readDescriptor(
70 | bluetoothPeripheral: BluetoothPeripheral,
71 | bluetoothCharacteristic: BluetoothCharacteristic,
72 | bluetoothCharacteristicDescriptor: BluetoothCharacteristicDescriptor
73 | )
74 | fun changeMTU(bluetoothPeripheral: BluetoothPeripheral, mtuSize: Int)
75 | ```
76 |
77 | ## Examples
78 |
79 | This repo contains examples for kotlin MP, ios and android in the examples folder, install their dependencies, and run it locally:
80 |
81 | ### Compose Multiplatform
82 |
83 | This example demonstrates using Kotlin Multiplatform Compose and Blue Falcon to scan for bluetooth devices and rendering using Multiplatform Compose
84 |
85 | ### Kotlin MP
86 |
87 | This example demonstrates how to integrate Blue Falcon in your own project as a dependency on your library/project.
88 |
89 | ### Raspberry Pi
90 |
91 | This example can only be ran on a Raspberry pi, it will crash otherwise.
92 |
93 | ### Javascript
94 |
95 | Open the index.html file in a web browser.
96 |
97 | ## Logger
98 |
99 | BlueFalcon has a constructor that takes a Logger, you can implement your own logger, to handle and reduce or add to the noise generated.
100 |
101 | Look at the PrintLnLogger object of an example of how to do this.
102 |
103 | ## Support
104 |
105 | For a **bug, feature request, or cool idea**, please [file a Github issue](https://github.com/Reedyuk/blue-falcon/issues/new).
106 |
107 | ### Two big little things
108 |
109 | Keep in mind that Blue-Falcon is maintained by volunteers. Please be patient if you don’t immediately get an answer to your question; we all have jobs, families, obligations, and lives beyond this project.
110 |
111 | Many thanks to everyone so far who has contributed to the project, it really means alot.
112 |
113 |
114 | [badge-android]: http://img.shields.io/badge/platform-android-brightgreen.svg?style=flat
115 | [badge-native]: http://img.shields.io/badge/platform-native-lightgrey.svg?style=flat
116 | [badge-js]: http://img.shields.io/badge/platform-js-yellow.svg?style=flat
117 | [badge-mac]: http://img.shields.io/badge/platform-macos-lightgrey.svg?style=flat
118 | [badge-rpi]: http://img.shields.io/badge/platform-rpi-lightgrey.svg?style=flat
119 |
--------------------------------------------------------------------------------