Я использую Kotlin с целевым API на уровне 34. Я пытаюсь создать приложение для созданного мной базового устройства BLE, прямо сейчас я просто пытаюсь установить одну характеристику, когда нажимаю кнопку на главном экране. активность. Я использую API-интерфейс Companion Device для управления соединением BLE, вот что у меня есть на данный момент:
private const val SELECT_DEVICE_REQUEST_CODE = 0
private val BONDING_SERVICE_UUID = ParcelUuid.fromString("25a5e219-5cf3-41b7-8792-83702c814260")
class MainActivity : ComponentActivity() {
private val deviceManager: CompanionDeviceManager by lazy {
getSystemService(Context.COMPANION_DEVICE_SERVICE) as CompanionDeviceManager
}
val executor: Executor = Executor { it.run() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val filter = ScanFilter.Builder().setServiceUuid(BONDING_SERVICE_UUID).build()
val deviceFilter: BluetoothLeDeviceFilter = BluetoothLeDeviceFilter.Builder()
.setScanFilter(filter)
.build()
val context = this
val connectButton: Button = findViewById(R.id.button_scan)
connectButton.setOnClickListener {
Log.i("ScanCallback","Scan button clicked")
val pairingRequest: AssociationRequest = AssociationRequest.Builder()
.addDeviceFilter(deviceFilter)
.setSingleDevice(true)
.setDeviceProfile(AssociationRequest.DEVICE_PROFILE_WATCH)
.build()
// When the app tries to pair with a Bluetooth device, show the
// corresponding dialog box to the user.
deviceManager.associate(pairingRequest,
executor,
object : CompanionDeviceManager.Callback() {
// Called when a device is found. Launch the IntentSender so the user
// can select the device they want to pair with.
override fun onAssociationPending(intentSender: IntentSender) {
Log.i("ScanCallback","onAssociationPending")
startIntentSenderForResult(intentSender, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0)
}
@SuppressLint("MissingPermission")
override fun onAssociationCreated(associationInfo: AssociationInfo) {
Log.i("ScanCallback","onAssociationCreated")
val scanResult: ScanResult? = associationInfo.associatedDevice?.bleDevice
if(scanResult == null){
val scanResultMessage = "Scan result null"
Log.i("ScanCallback",scanResultMessage)
Toast.makeText(context, scanResultMessage, Toast.LENGTH_SHORT).show()
} else {
with(scanResult.device) {
val scanResultMessage = "Found BLE device! Name: ${name ?: "Unnamed"}, address: $address"
Log.i("ScanCallback", scanResultMessage)
Toast.makeText(context, scanResultMessage, Toast.LENGTH_SHORT).show()
}
}
}
override fun onFailure(errorMessage: CharSequence?) {
Log.i("ScanCallback","onFailure")
// Handle the failure.
}
}
)
}
val buzzButton: Button = findViewById(R.id.button_buzz)
buzzButton.setOnClickListener {
// This is the part I don't know how to do
val watchService = getCompanionDeviceService()
watchService.sendMessageToWatch()
}
}
@SuppressLint("MissingPermission")
@Deprecated("Deprecated in Java")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
SELECT_DEVICE_REQUEST_CODE -> when(resultCode) {
Activity.RESULT_OK -> {
val associationInfo: AssociationInfo? = data?.getParcelableExtra(CompanionDeviceManager.EXTRA_ASSOCIATION, AssociationInfo::class.java)
val bleDevice: BluetoothDevice? = associationInfo?.associatedDevice?.bleDevice?.device
if(bleDevice?.address != null){
deviceManager.startObservingDevicePresence(bleDevice.address)
Toast.makeText(this, "Device connected", Toast.LENGTH_SHORT).show()
}
}
}
else -> super.onActivityResult(requestCode, resultCode, data)
}
}
}
Я могу установить соединение и отправлять/получать данные с устройства, если у меня есть весь код в MainActivity, но я хочу, чтобы соединение Bluetooth автоматически поддерживалось в фоновом режиме. Я нашел CompanionDeviceService, который, похоже, является тем, что я ищу, поскольку он обычно не уничтожается системой, поэтому я создал этот класс:
class WatchService : CompanionDeviceService() {
private val SERVICE_UUID = UUID.fromString("3fd1f78e-6728-468d-a693-c3f2c2c268af")
private val CHARACTERISTIC_UUID = UUID.fromString("1ca721c1-cc5a-40e2-a290-0a316bbea478")
private var bluetoothDevice: BluetoothDevice? = null
private var bluetoothGatt: BluetoothGatt? = null
private var vibrationService: BluetoothGattService? = null
@SuppressLint("MissingPermission")
override fun onDeviceAppeared(associationInfo: AssociationInfo) {
super.onDeviceAppeared(associationInfo)
// Extract the BLE device
bluetoothDevice = associationInfo.associatedDevice?.bleDevice?.device
bluetoothDevice?.connectGatt(this, false, object : BluetoothGattCallback() {
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.d("BLE", "Connected to GATT server")
bluetoothGatt = gatt
gatt.discoverServices()
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.d("BLE", "Disconnected from GATT server")
bluetoothGatt = null
vibrationService = null
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
if (status == BluetoothGatt.GATT_SUCCESS) {
vibrationService = gatt.getService(SERVICE_UUID)
} else {
Log.e("BLE", "Service discovery failed, status: $status")
vibrationService = null
}
}
})
}
override fun onDeviceDisappeared(associationInfo: AssociationInfo) {
super.onDeviceDisappeared(associationInfo)
bluetoothDevice = null
bluetoothGatt = null
vibrationService = null
}
@SuppressLint("MissingPermission")
fun sendMessageToWatch() {
val localVibrationService = vibrationService
if(localVibrationService == null){
} else {
bluetoothGatt?.writeCharacteristic(
localVibrationService.getCharacteristic( CHARACTERISTIC_UUID ), byteArrayOf(0x01), BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
)
}
}
}
Но я не могу найти способ получить ссылку на этот класс WatchService в MainActivity, что заставляет меня думать, что я использую его неправильно. Обычно я могу разобраться в частях кода, но изо всех сил пытаюсь понять, как должно быть структурировано это приложение. Должен ли я иметь отдельную службу, к которой привязаны MainActivity и WatchService?
Я использую Kotlin с целевым API на уровне 34. Я пытаюсь создать приложение для созданного мной базового устройства BLE, прямо сейчас я просто пытаюсь установить одну характеристику, когда нажимаю кнопку на главном экране. активность. Я использую API-интерфейс Companion Device для управления соединением BLE, вот что у меня есть на данный момент: [code]private const val SELECT_DEVICE_REQUEST_CODE = 0 private val BONDING_SERVICE_UUID = ParcelUuid.fromString("25a5e219-5cf3-41b7-8792-83702c814260")
class MainActivity : ComponentActivity() {
private val deviceManager: CompanionDeviceManager by lazy { getSystemService(Context.COMPANION_DEVICE_SERVICE) as CompanionDeviceManager }
val executor: Executor = Executor { it.run() }
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main)
val filter = ScanFilter.Builder().setServiceUuid(BONDING_SERVICE_UUID).build() val deviceFilter: BluetoothLeDeviceFilter = BluetoothLeDeviceFilter.Builder() .setScanFilter(filter) .build()
val context = this
val connectButton: Button = findViewById(R.id.button_scan)
connectButton.setOnClickListener { Log.i("ScanCallback","Scan button clicked") val pairingRequest: AssociationRequest = AssociationRequest.Builder() .addDeviceFilter(deviceFilter) .setSingleDevice(true) .setDeviceProfile(AssociationRequest.DEVICE_PROFILE_WATCH) .build() // When the app tries to pair with a Bluetooth device, show the // corresponding dialog box to the user. deviceManager.associate(pairingRequest, executor, object : CompanionDeviceManager.Callback() { // Called when a device is found. Launch the IntentSender so the user // can select the device they want to pair with. override fun onAssociationPending(intentSender: IntentSender) { Log.i("ScanCallback","onAssociationPending") startIntentSenderForResult(intentSender, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0) }
@SuppressLint("MissingPermission") override fun onAssociationCreated(associationInfo: AssociationInfo) { Log.i("ScanCallback","onAssociationCreated") val scanResult: ScanResult? = associationInfo.associatedDevice?.bleDevice if(scanResult == null){ val scanResultMessage = "Scan result null" Log.i("ScanCallback",scanResultMessage) Toast.makeText(context, scanResultMessage, Toast.LENGTH_SHORT).show() } else { with(scanResult.device) { val scanResultMessage = "Found BLE device! Name: ${name ?: "Unnamed"}, address: $address" Log.i("ScanCallback", scanResultMessage) Toast.makeText(context, scanResultMessage, Toast.LENGTH_SHORT).show() } }
}
override fun onFailure(errorMessage: CharSequence?) { Log.i("ScanCallback","onFailure") // Handle the failure. } } ) }
val buzzButton: Button = findViewById(R.id.button_buzz) buzzButton.setOnClickListener { // This is the part I don't know how to do val watchService = getCompanionDeviceService() watchService.sendMessageToWatch() } }
@SuppressLint("MissingPermission") @Deprecated("Deprecated in Java") override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { when (requestCode) { SELECT_DEVICE_REQUEST_CODE -> when(resultCode) { Activity.RESULT_OK -> {
val associationInfo: AssociationInfo? = data?.getParcelableExtra(CompanionDeviceManager.EXTRA_ASSOCIATION, AssociationInfo::class.java) val bleDevice: BluetoothDevice? = associationInfo?.associatedDevice?.bleDevice?.device
[/code] Я могу установить соединение и отправлять/получать данные с устройства, если у меня есть весь код в MainActivity, но я хочу, чтобы соединение Bluetooth автоматически поддерживалось в фоновом режиме. Я нашел CompanionDeviceService, который, похоже, является тем, что я ищу, поскольку он обычно не уничтожается системой, поэтому я создал этот класс: [code]class WatchService : CompanionDeviceService() { private val SERVICE_UUID = UUID.fromString("3fd1f78e-6728-468d-a693-c3f2c2c268af") private val CHARACTERISTIC_UUID = UUID.fromString("1ca721c1-cc5a-40e2-a290-0a316bbea478")
private var bluetoothDevice: BluetoothDevice? = null private var bluetoothGatt: BluetoothGatt? = null private var vibrationService: BluetoothGattService? = null
@SuppressLint("MissingPermission") override fun onDeviceAppeared(associationInfo: AssociationInfo) { super.onDeviceAppeared(associationInfo)
// Extract the BLE device bluetoothDevice = associationInfo.associatedDevice?.bleDevice?.device
bluetoothDevice?.connectGatt(this, false, object : BluetoothGattCallback() { override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { if (newState == BluetoothProfile.STATE_CONNECTED) { Log.d("BLE", "Connected to GATT server") bluetoothGatt = gatt gatt.discoverServices() } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { Log.d("BLE", "Disconnected from GATT server") bluetoothGatt = null vibrationService = null } }
} } [/code] Но я не могу найти способ получить ссылку на этот класс WatchService в MainActivity, что заставляет меня думать, что я использую его неправильно. Обычно я могу разобраться в частях кода, но изо всех сил пытаюсь понять, как должно быть структурировано это приложение. Должен ли я иметь отдельную службу, к которой привязаны MainActivity и WatchService?
Исходя из опыта разработки iOS, при работе с Bluetooth LE в качестве периферийного устройства вы можете зарегистрировать обратный вызов, когда «центральное» устройство BLE подписывается (включает уведомления) на определенную характеристику.
Я изо...
Исходя из опыта разработки iOS, при работе с Bluetooth LE в качестве периферийного устройства вы можете зарегистрировать обратный вызов, когда «центральное» устройство BLE подписывается (включает уведомления) на определенную характеристику.
Я изо...
Мое приложение действует как периферийное устройство, рекламирующее услугу с характеристикой с заранее заданным значением, а центральное устройство считывает ее и обрабатывает рекламные данные.
но мне сложно установить значение для характеристики в...
Я разрабатываю мобильное приложение на основе Bluetooth с низкой энергией (BLE) в Android Studio для связи с устройством ESP32. ESP32 выступает в качестве сервера BLE (периферийная), а мое приложение для Android действует как клиент (центральный)....