当屏幕关闭时,前台服务上的 Android 蓝牙 LE 扫描仪立即停止 [英] Android Bluetooth LE scanner on foreground service stops immediately when screen turns off

查看:25
本文介绍了当屏幕关闭时,前台服务上的 Android 蓝牙 LE 扫描仪立即停止的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下 BLE 前台服务实现 -

I have the following BLE foreground service implementation -

public class BluetoothForegroundService extends Service {

    private PowerManager.WakeLock wakeLock;

    @Override
    public void onCreate() {
        super.onCreate();
        PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK , this.getClass().getSimpleName());
        wakeLock.acquire();
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        wakeLock.release();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

        Notification notification = new NotificationCompat.Builder(this, "BLE test")
                .setContentTitle("Bluetooth Service")
                .setContentText("Fetching Bluetooth")
                .setSmallIcon(R.drawable.ic_launcher)
                .setContentIntent(pendingIntent)
                .build();

        startForeground(1, notification);

        BluetoothScanner bluetoothScanner = BluetoothScanner.getInstance(new BluetoothScanner.OnBlePacketBuilderListener() {
            @Override
            public void onBleObjectsCreated(BleBeaconPacketData beaconPacketData, BleHardwarePacketData bleBroadcastPacketData) {
                if (bleBroadcastPacketData == null && beaconPacketData == null) return;
                Log.d("onBleObjectsCreated", "onBleObjectsCreated");
                Intent intent = new Intent("action");
                if (beaconPacketData != null)
                    intent.putExtra("BleBeaconPacketData", beaconPacketData);
                if (bleBroadcastPacketData != null)
                    intent.putExtra("BleHardwarePacketData", bleBroadcastPacketData);
                sendBroadcast(intent);
            }
        });
        bluetoothScanner.startBluetooth();

        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

public class BluetoothScanner implements BluetoothAdapter.LeScanCallback, BlePacketBuilder.BlePacketBuilderListener {

    interface OnBlePacketBuilderListener{
        void onBleObjectsCreated(BleBeaconPacketData beaconPacketData, BleHardwarePacketData bleBroadcastPacketData);
    }

    private final OnBlePacketBuilderListener listener;
    private BluetoothAdapter bluetoothAdapter;
    public static BluetoothScanner instance;

    private BluetoothScanner(OnBlePacketBuilderListener listener) {
        this.listener = listener;
    }

    public static BluetoothScanner getInstance(OnBlePacketBuilderListener listener) {
        if (instance == null)
            instance = new BluetoothScanner(listener);
        return instance;
    }

    public void startBluetooth() {
        BluetoothManager bluetoothManager = MainApplication.getPureTrackApplicationContext().getSystemService(BluetoothManager.class);
        if ((bluetoothManager != null ? bluetoothManager.getAdapter() : null) == null) return;
        bluetoothAdapter = bluetoothManager.getAdapter();
        bluetoothAdapter.startLeScan(this);
    }

    public void stopBluetooth() {
        if (bluetoothAdapter == null) return;
        bluetoothAdapter.stopLeScan(this);
    }

    @Override
    public void onLeScan(BluetoothDevice bluetoothDevice, int rssi, byte[] scanRecord) {
        Log.d("BluetoothScanner", "New BLE - " + Arrays.toString(scanRecord));
        BlePacketBuilder blePacketBuilder = new BlePacketBuilder(this);
        blePacketBuilder.parseResult(bluetoothDevice, rssi, scanRecord);
    }


    @Override
    public void onfinishedToParseResults(BleBeaconPacketData beaconPacketData, BleHardwarePacketData bleBroadcastPacketData) {
        listener.onBleObjectsCreated(beaconPacketData, bleBroadcastPacketData);
    }
}

在我的 MainActivity 上,我收到了广播 -

And on my MainActivity I am receiving the broadcast -

private void getBluetoothDataFromForegroundService() {
        registerReceiver(new BluetoothScannerReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (powerManager == null) return;
                Log.d("onReceiveBle", "onReceiveBle");

                //At this point data is handled both for UI and for network calls 
            }
        }, new IntentFilter("action"));
    }

问题是,即使屏幕永远关闭,我也需要 BLE 来保持采样数据.这是一个内部产品,所以我不关心电池消耗或普通应用程序用户会担心的任何事情.我只需要永远对 BLE 进行采样并通过网络调用相应地处理数据.

The thing is that I need the BLE to keep sampling data even when the screen is off forever. This is an internal product so I do not care about battery consumption or anything that normal applications users would be worried about. I just need to sample the BLE forever and handle the data accordingly with network calls.

我尝试使用 WakeLock,但没有帮助.当屏幕关闭时我不会获取日志,当屏幕重新打开时我不会获取日志.对于 BLE 保持采样,我缺少什么?

I tried to use WakeLock and it did not help. I am not gettings logs when the screen shuts down and gettings the logs back when the screen turns on back. What is it that I am missing for the BLE to keep sampling?

推荐答案

我觉得你缺少一些东西.

I think you are lacking some things.

Android 10 权限
在 Android 10 上,您通常必须获得 ACCESS_BACKGROUND_LOCATION 才能在您的应用不可见时进行信标检测.但是,如果您添加 android:foregroundServiceType=location",则可以仅使用授予的前台位置权限和前台服务进行扫描.到清单中的前台服务声明.详情请见此处.

Android 10 permissions
On Android 10, you generally must have obtained ACCESS_BACKGROUND_LOCATION for beacon detection to work when your app is not visible. However, it is possible to scan with only foreground location permission granted and a foreground service if you add android:foregroundServiceType="location" to your foreground service declaration in the manifest. See here for details.

因此您需要 ACCESS_BACKGROUND_LOCATION 才能在 A10+ 屏幕关闭时获得扫描结果.

So you need ACCESS_BACKGROUND_LOCATION in order to get scanning results when the screen is off in A10+.

另外,在A8中也有介绍,(可以看此处),扫描功能停止前有 10 分钟的限制.因此,我建议您使用 JobSchedulerRunnable 来制作 9 分钟计时器(或 10 分钟)并重置扫描.这样您就可以获得长时间的扫描服务.这是一个例子:

Also, has introduced in A8, (you can see it here), there is a limit of 10 minutes before scan function stops. So I recommend you to use a JobScheduler or a Runnable to make a 9 minutes timer (or 10) and reset the scan. That way you get a long scanning service. This is an example:

 mHandlerUpdate?.removeCallbacksAndMessages(null)

        mHandlerUpdate?.postDelayed(object : Runnable {
            override fun run() {
                Log.d(BleService::class.java.simpleName, "run: in runnable handler")
                scanner.stopScan(mScanCallback)

                scanner.startScan(
                    filters,
                    settings,
                    mScanCallback
                )
                mHandlerUpdate?.postDelayed(this, 60000)
            }
        }, 60000)

上面的处理程序每​​ 60 秒重置一次扫描.只是一个演示代码.您可以根据自己的需要进行修改.完成后记得removeCallbacksAndMessages.

The handler above resets the scanning every 60 seconds. Is just a demo code. You can modify accoriding to your needs. Remember to removeCallbacksAndMessages when you are done with it.

此外,为了获得结果,必须启用定位服务.您可以在此处了解原因.

Also, it is necessary to have Location Services on in order to get results. You can see the why here.

其他一些兴趣链接..

切特谈话

开发者 Android Bt 页面

这篇关于当屏幕关闭时,前台服务上的 Android 蓝牙 LE 扫描仪立即停止的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆