Запустите службу из BroadcastReceiver с помощью BLE и PendingIntent.Android

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Запустите службу из BroadcastReceiver с помощью BLE и PendingIntent.

Сообщение Anonymous »

Существует BluetoothTestFragment, где одна из кнопок вызывает startPendingIntentScan(), чтобы использовать bluetoothAdapter.bluetoothLeScanner.startScan(), и получает обратный вызов BroadcastReceiver через PendingIntent.
Обратный вызов BroadcastReceiver.onReceive() работает. Теперь я хочу запустить службу переднего плана для подключения к найденному устройству. Однако после вызова ContextCompat.startForegroundService() ничего не происходит. Внутри GattClientService не возникает ошибок или точек останова.
  • Может ли BroadcastReceiver запустить службу переднего плана при запуске PendingIntent?
  • Если да, то почему GattClientService не вызывает onStartCommand?
Android 13 (API) 33) - автозапуск включен, оптимизация батареи отключена.
@HiltViewModel
class BluetoothTestViewModel @Inject constructor() : BaseViewModel() {}

@AndroidEntryPoint
@RequiresApi(Build.VERSION_CODES.O)
class BluetoothTestFragment : BaseFragment(R.layout.fragment_bluetooth_test) {

override val viewModel: BluetoothTestViewModel by hiltNavGraphViewModels(R.id.bluetoothTestFragment)

private val bluetoothAdapter: BluetoothAdapter? by lazy {
val manager = requireContext().getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
manager.adapter
}

private val permissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { perms ->
val allGranted = perms.values.all { it }
if (allGranted) log("No perms")
else log("Error: no Bluetooth/Location")
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

binding.btnStartAdvertising.setOnClickListener {
if (checkPermissions()) {
val intent = Intent(requireContext(), GattServerService::class.java)
ContextCompat.startForegroundService(requireContext(), intent)
}
}

binding.btnStartPendingScan.setOnClickListener {
if (checkPermissions()) {
startPendingIntentScan()
}
}

binding.btnStopAll.setOnClickListener {
stopAllServices()
}
}

private fun startPendingIntentScan() {
val scanner = bluetoothAdapter?.bluetoothLeScanner
if (scanner == null) {
return
}

val filter = ScanFilter.Builder()
.setServiceUuid(ParcelUuid(GattService.SERVICE_UUID))
.build()

val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH or ScanSettings.CALLBACK_TYPE_MATCH_LOST)
.setMatchMode(ScanSettings.MATCH_MODE_STICKY)
.build()

val intent = Intent(requireContext(), BlePresenceReceiver::class.java)
intent.action = "com.example.ACTION_BEACON_FOUND"

val pendingIntent = PendingIntent.getBroadcast(
requireContext(),
100,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
)

try {
val result = scanner.startScan(listOf(filter), settings, pendingIntent)
} catch (e: SecurityException) {
}
}

override fun onDestroyView() {
super.onDestroyView()
stopAllServices()
}

private fun stopAllServices() {
requireContext().stopService(Intent(requireContext(), GattServerService::class.java))
requireContext().stopService(Intent(requireContext(), GattClientService::class.java))
stopPendingIntentScan()
}

@SuppressLint("MissingPermission")
private fun stopPendingIntentScan() {
if (!checkPermissions()) return
val scanner = bluetoothAdapter?.bluetoothLeScanner
if (scanner == null) {
return
}

val intent = Intent(requireContext(), BlePresenceReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
requireContext(),
100,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
)

try {
scanner.stopScan(pendingIntent)
} catch (e: Exception) {
log(e.message)
}
}

private fun checkPermissions(): Boolean {
val needed = mutableListOf()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
needed.add(Manifest.permission.BLUETOOTH_SCAN)
needed.add(Manifest.permission.BLUETOOTH_ADVERTISE)
needed.add(Manifest.permission.BLUETOOTH_CONNECT)
} else {
needed.add(Manifest.permission.ACCESS_FINE_LOCATION)
}

val missing = needed.filter {
ActivityCompat.checkSelfPermission(requireContext(), it) != PackageManager.PERMISSION_GRANTED
}

if (missing.isNotEmpty()) {
permissionLauncher.launch(missing.toTypedArray())
return false
}
return true
}

private fun log(msg: String) {
activity?.runOnUiThread {
_binding?.tvLog?.append("\n$msg\n")
}
}

}

@RequiresApi(Build.VERSION_CODES.O)
class BlePresenceReceiver : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {
val errorCode = intent.getIntExtra(BluetoothLeScanner.EXTRA_ERROR_CODE, -1)
if (errorCode != -1) {
return
}

val scanResult = intent.parcelableArrayList(BluetoothLeScanner.EXTRA_LIST_SCAN_RESULT) ?: return
val device = scanResult.firstOrNull()?.device ?: return
val callbackType = intent.getIntExtra(BluetoothLeScanner.EXTRA_CALLBACK_TYPE, -1)
val message = "Device: ${device.address}\nCallbackType: $callbackType"
println(message)

if (callbackType == CALLBACK_TYPE_FIRST_MATCH) {
val serviceIntent = Intent(context, GattClientService::class.java).apply {
putExtra(EXTRA_DEVICE, device)
}
ContextCompat.startForegroundService(context, serviceIntent)
}
}
}

@AndroidEntryPoint
class GattClientService : GattService() {

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// never calls

val device = intent?.parcelable(EXTRA_DEVICE)
if (device != null) {
connectToGattServer(device)
startForegroundCompat(NotificationConfig.BLUETOOTH_FOREGROUND_SERVICE, notificationRepository)
} else {
stopSelf()
}
return START_NOT_STICKY
}

// ...
}

open class GattService: Service() {

@Inject
lateinit var notificationRepository: NotificationRepository

override fun onBind(intent: Intent?): IBinder? {
return null
}

companion object {
val SERVICE_UUID: UUID = UUID.fromString("abc")
val CLIENT_TO_SERVER_CHAR_UUID: UUID = UUID.fromString("cba")
val SERVER_TO_CLIENT_CHAR_UUID: UUID = UUID.fromString("xyz")
}
}
















Подробнее здесь: https://stackoverflow.com/questions/798 ... dingintent
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»