Delphi android : 屏幕关闭时无法扫描蓝牙 LE 设备

Delphi android : Scanning Bluetooth LE devices does not work while screen is off

我有一个扫描 BluetoothLE 设备(温度)的应用程序。该应用程序在电池优化列表中列入白名单,并使用 PARTIAL_WAKE_LOCK.

在 Zebra TC25 Android 7.1.2 中使用线程扫描 BLE 设备每 10 分钟一次,独立于 android 设备状态。

但是,同一应用程序根本无法在三星 galaxy S10+ 上运行 Android10 当屏幕关闭时(它在屏幕打开时运行)。我知道简单的线程方法不会因为打瞌睡模式而起作用。所以我也尝试了这些方法:

setExactAndAllowWhileIdle(TJAlarmManager.JavaClass.RTC_WAKEUP, time,PendingIntent) 和 firebase 云消息传递发送高优先级消息。报警方式有局限性,据我所知fcm没有。

这2种方式也都失败了。收到 fcm 消息并触发警报,运行 下面的 BLEDiscover 过程 运行 蓝牙扫描,但没有发现蓝牙设备。

这是在两种情况下发生的情况。在第一个中,屏幕打开,它始终有效:

12-08 12:39:58.994: D/BluetoothAdapter(30351): STATE_ON
12-08 12:39:58.994: D/BluetoothLeScanner(30351): could not find callback wrapper
12-08 12:39:58.995: D/BluetoothAdapter(30351): STATE_ON
12-08 12:39:58.997: D/BluetoothAdapter(30351): STATE_ON
12-08 12:39:58.997: D/BluetoothLeScanner(30351): Start Scan with callback
12-08 12:39:59.001: D/BluetoothLeScanner(30351): onScannerRegistered() - status=0 scannerId=14 mScannerId=0
12-08 12:39:59.965: I/info(30351): FMX: tags (Nil): 4154326484 - BLEDiscoverLEDevice - device touvé : C_T_801362
12-08 12:39:59.977: I/info(30351): FMX: tags (Nil): 4154326484 - BLEDiscoverLEDevice - TAG touvé : C_T_801362
12-08 12:39:59.977: I/info(30351): FMX: tags (Nil): 4154326484 - Trame 6E2A7207 - T° 19,06
12-08 12:39:59.983: I/info(30351): FMX: alerte (Nil): 4154326484 - BLEAlerte
12-08 12:40:04.928: I/info(30351): FMX: tags (Nil): 4154326484 - BLEDiscoverLEDevice - device touvé : P_T_8038DB
12-08 12:40:04.948: I/info(30351): FMX: tags (Nil): 4154326484 - BLEDiscoverLEDevice - TAG touvé : P_T_8038DB
12-08 12:40:04.948: I/info(30351): FMX: tags (Nil): 4154326484 - Trame 6E2A6C07 - T° 19,00
12-08 12:40:04.955: I/info(30351): FMX: alerte (Nil): 4154326484 - BLEAlerte
12-08 12:40:19.038: D/BluetoothAdapter(30351): STATE_ON
12-08 12:40:19.038: D/BluetoothLeScanner(30351): Stop Scan with callback

一旦屏幕关闭,它永远不会工作:

12-08 12:44:02.094: D/BluetoothAdapter(30351): STATE_ON
12-08 12:44:02.094: D/BluetoothLeScanner(30351): could not find callback wrapper
12-08 12:44:02.096: D/BluetoothAdapter(30351): STATE_ON
12-08 12:44:02.098: D/BluetoothAdapter(30351): STATE_ON
12-08 12:44:02.098: D/BluetoothLeScanner(30351): Start Scan with callback
12-08 12:44:02.101: D/BluetoothLeScanner(30351): onScannerRegistered() - status=0 scannerId=10 mScannerId=0
12-08 12:44:23.110: D/BluetoothAdapter(30351): STATE_ON
12-08 12:44:23.110: D/BluetoothLeScanner(30351): Stop Scan with callback

所以thread、alarm和fcm的结果是一样的,就是熄屏的时候没有发现BLE设备

这是代码:

// Discovering BLE devices
procedure TfData.BLEDiscover();
begin
    FBluetoothManagerLE := TBluetoothLEManager.Current;
    FBluetoothManagerLE.OnDiscoverLEDevice := BLEDiscoverLEDevice;
    FBluetoothManagerLE.StartDiscovery(10000);
end;
 

procedure TfData.BLEDiscoverLEDevice(const Sender: TObject; const ADevice: TBluetoothLEDevice; Rssi: Integer; const ScanResponse: TScanResponse);
var tag, i: Integer;
    vals : TArray<Byte>;
    trame : string;
    temperature : single;
begin
  log('tags', 'BLEDiscoverLEDevice - device touvé : ' + ADevice.DeviceName);
  lockTags.Acquire;
  if ADevice.DeviceName <> '' then begin
    for tag := Low(Tags) to High(Tags) do begin
      if (ADevice.DeviceName = Tags[tag].K_TAG) then begin
          log('tags', 'BLEDiscoverLEDevice - TAG touvé : ' + ADevice.DeviceName);
          trame := '';
          vals := ADevice.AdvertisedData.ExtractPair(TScanResponseKey.ServiceData).Value;
          for i  := 0 to length(vals) - 1 do begin
            trame := trame + IntToHex(vals[i]);
          end;
          temperature:=BLEReadTrame(trame);
          log('tags', 'Trame '+trame + ' - T° '+ formatFloat('0.00',temperature));
          if (temperature <> tagNullTemp) then begin
            Tags[tag].T_LAST := temperature;
            Tags[tag].DtLastTemp := now;
          end;
        end;
        break;
      end;
    end;
  end;
  lockTags.Release;
end;

编辑:请注意我使用 fcm 方法获取实时 gps 位置,因此设备获取 GPS 并将其通过 Internet 发送到服务器,它始终有效,即使屏幕关闭。

Android 10+ 需要ACCESS_BACKGROUND_LOCATION权限才能在后台进行蓝牙扫描。

如果您使用的是 Delphi 10.4.1,请选中“项目选项”的“应用程序”>“使用权限”部分中的“访问后台位置”复选框。对于 Delphi 的早期版本,您可能需要修改 AndroidManifest.template.xml 以添加权限:

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

也可以使用 PermissionsService 在运行时请求权限。

我尝试使用前台服务,得到完全相同的结果:屏幕打开,服务后台,发现工作。屏幕关闭,服务前台,发现根本不起作用,因为永远不会调用回调函数。我猜问题出在三星硬件上,而不是 Android。也许三星在屏幕关闭时禁用了蓝牙扫描。这是愚蠢的,特别是对于蓝牙“LE”。我使用的标签(用于温度测量)和硬币一样大,但有 5 到 15 年的自主权,每 3 秒发送一次蓝牙 trame。因此,即使蓝牙扫描消耗更多能量(不确定),假设您每 5 或 10 分钟扫描一次,它也不会耗尽电池电量。只不过是定位服务。请注意,在法国,我们有一个基于蓝牙的应用程序“Anticovid”...只要这些手机屏幕保持关闭状态,它可能根本不适用于三星手机?

编辑:我找到了使用此 post Android: How to turn screen on and off programmatically?

的解决方法
WakeLock := PowerManager.newWakeLock(TJPowerManager.JavaClass.SCREEN_BRIGHT_WAKE_LOCK or TJPowerManager.JavaClass.ACQUIRE_CAUSES_WAKEUP, StringToJString('myapp'));

在调用蓝牙扫描之前,我调用了这段代码,它打开屏幕几秒钟,足以扫描BLE设备,它工作正常。因此,一种解决方案是检查设备是否能够在屏幕关闭时进行扫描,并仅为无法扫描的设备激活此代码。

不确定这是一个好方法,但在我的情况下这是唯一的方法。