You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native应用被杀后Beacon扫描启动却无法检测信标问题

React Native应用被杀后无法检测Beacon的问题

我正在开发一款React Native应用,要求即使应用被杀也能检测Beacon。当前实现下,应用在前台或后台时可正常检测Beacon,但被杀后无任何反应。不过logcat中出现以下日志:

2022-09-15 06:12:48.869 11188-11188/com.package.name I/ScanJob: ScanJob Lifecycle START: org.altbeacon.beacon.service.ScanJob@c368a4
2022-09-15 06:12:48.887 11188-12719/com.package.name I/BeaconManager: BeaconManager started up on pid 11188 named 'com.package.namep' for application package 'com.package.name'.  isMainProcess=true
2022-09-15 06:12:48.899 11188-12719/com.package.name D/BeaconParser: Parsing beacon layout: m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25
2022-09-15 06:12:48.993 11188-12719/com.tipme.app I/CycledLeScanner: Using Android O scanner
2022-09-15 06:12:49.001 11188-12719/com.package.name I/ScanJob: Using immediateScanJobId from manifest: 208352939
2022-09-15 06:12:49.001 11188-12719/com.package.name I/ScanJob: Running periodic scan job: instance is org.altbeacon.beacon.service.ScanJob@c368a4
2022-09-15 06:12:49.001 11188-12719/com.package.name I/ScanJob: scanJob version 2.19.4 is starting up on the main process
2022-09-15 06:12:49.010 11188-12719/com.package.name W/ModelSpecificDistanceCalculator: Cannot find match for this device.  Using default
2022-09-15 06:12:49.011 11188-12719/com.package.name W/ModelSpecificDistanceCalculator: Cannot find match for this device.  Using default
2022-09-15 06:12:49.029 11188-12719/com.package.name I/BluetoothAdapter: BluetoothAdapter() : com.package.name
2022-09-15 06:12:49.030 11188-12719/com.package.name I/BluetoothAdapter: STATE_ON
2022-09-15 06:12:49.034 11188-12719/com.package.name I/BluetoothAdapter: STATE_ON
2022-09-15 06:12:49.035 11188-12719/com.package.name D/BluetoothLeScanner: Stop Scan with callback intent
2022-09-15 06:12:49.056 11188-12719/com.package.name I/BluetoothAdapter: STATE_ON
2022-09-15 06:12:49.057 11188-12720/com.package.name I/BluetoothAdapter: STATE_ON
2022-09-15 06:12:49.058 11188-12720/com.package.name I/BluetoothAdapter: STATE_ON
2022-09-15 06:12:49.060 11188-12720/com.package.name I/BluetoothAdapter: STATE_ON
2022-09-15 06:12:49.060 11188-12719/com.package.name I/ScanJob: Scan job running for 15000 millis
2022-09-15 06:12:49.061 11188-12720/com.package.name D/BluetoothLeScanner: Start Scan with callback
2022-09-15 06:12:49.068 11188-11336/com.package.name D/BluetoothLeScanner: onScannerRegistered() - status=0 scannerId=10 mScannerId=0
2022-09-15 06:12:49.216 11188-11336/com.package.name I/BluetoothAdapter: BluetoothAdapter() : com.package.name
2022-09-15 06:12:49.278 11188-12722/com.package.name I/ScanHelper: Non-distinct packets detected in a single scan.  Restarting scans unecessary.
2022-09-15 06:13:04.062 11188-11188/com.package.name I/ScanJob: Scan job runtime expired: org.altbeacon.beacon.service.ScanJob@c368a4
2022-09-15 06:13:04.062 11188-11188/com.package.name I/BluetoothAdapter: STATE_ON
2022-09-15 06:13:04.065 11188-11188/com.package.name I/BluetoothAdapter: STATE_ON
2022-09-15 06:13:04.066 11188-11188/com.package.name D/BluetoothLeScanner: Stop Scan with callback intent
2022-09-15 06:13:04.071 11188-12720/com.package.name I/BluetoothAdapter: STATE_ON
2022-09-15 06:13:04.071 11188-12720/com.package.name D/BluetoothLeScanner: Stop Scan with callback
2022-09-15 06:13:04.125 11188-11188/com.package.name I/ScanJob: We are inside a beacon region.  We will not scan between cycles.

该日志在应用被杀约30分钟后出现,这是默认行为,说明扫描任务已成功启动,但未检测到信标,也未调用推送通知方法。请问是我的实现存在问题,还是React Native不支持该功能?

public class ListenerModule  extends ReactContextBaseJavaModule   {
    private static final String TAG = "TipmeListener";
    private final ReactApplicationContext mReactContext;
    private BeaconManager beaconManager;
    private static final String BEACON_UUID = "76b08b60-3322-4534-a3bf-2d10adc8ebd2";
    private static final String BEACON_LAYOUT = "m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24";
    private final static String tipmeID  = "some-unique-string";
    private final static String tipmeChannelID  = "some-unique-string-channel";
    private final Region region = new  Region(tipmeID, Identifier.parse(BEACON_UUID), null, null);
    private final HashMap<Integer, LocalDateTime> pastBeacons = new HashMap<>();


    public ListenerModule (ReactApplicationContext context) {
        super(context);
        this.mReactContext = context;
    }

    @Override
    public void initialize() {
        this.beaconManager = BeaconManager.getInstanceForApplication(mReactContext);
        beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout(BEACON_LAYOUT));
        beaconManager.setBackgroundBetweenScanPeriod(0);
        beaconManager.setBackgroundScanPeriod(1100);
    }

    @NonNull
    @Override
    public String getName() {
        return  TAG;
    }



    //    Monitor notifier
    private MonitorNotifier monitorNotifier = new MonitorNotifier() {
        @Override
        public void didEnterRegion(Region region) {
            Log.d(TAG, "didEnterRegion");
            beaconManager.startRangingBeacons(region);
        }

        @Override
        public void didExitRegion(Region region) {
            Log.d(TAG, "didExitRegion");
        }

        @Override
        public void didDetermineStateForRegion(int state, Region region) {
            Log.d(TAG, "didDetermineStateForRegion");
            if (state == MonitorNotifier.INSIDE) {
                beaconManager.startRangingBeacons(region);
            }
        }
    };

    // Ranging notifier
    RangeNotifier rangeNotifier = new RangeNotifier() {
        @Override
        public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
            if (beacons.size() > 0) {
 

                    sendNotification();

                    Log.d(TAG, "didRangeBeaconsInRegion called with beacon count:  "+beaconsToNotify.size());
             

            }
        }
    };



    @ReactMethod
    public void start() {
        try {
            beaconManager.addMonitorNotifier( monitorNotifier);
            beaconManager.addRangeNotifier(rangeNotifier);
            beaconManager.startMonitoring(region);
            beaconManager.startRangingBeacons(region);
            Log.d(TAG, "start called");
        } catch (Exception e) {
            Log.e(TAG, "Error while starting beacon monitoring", e);
        }
    }


    @ReactMethod
    public void stop() {
        try {
            this.beaconManager.stopMonitoring(region);
            this.beaconManager.stopRangingBeacons(region);
        } catch (Exception e) {
            Log.e(TAG, "Error while stopping beacon monitoring", e);
        }
    }

    private void sendNotification() {
        NotificationManager notificationManager =
                (NotificationManager) this.mReactContext.getSystemService(Context.NOTIFICATION_SERVICE);
        Notification.Builder builder;
        NotificationChannel channel = new NotificationChannel(tipmeID,
                tipmeID, NotificationManager.IMPORTANCE_HIGH);
        channel.enableLights(true);
        channel.enableVibration(true);
        channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
        notificationManager.createNotificationChannel(channel);
        builder = new Notification.Builder(this.mReactContext, channel.getId());

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this.mReactContext);
        stackBuilder.addNextIntent(new Intent(this.mReactContext, MainActivity.class));
        PendingIntent resultPendingIntent =
                stackBuilder.getPendingIntent(
                        0,
                        PendingIntent.FLAG_UPDATE_CURRENT
                );
        builder.setSmallIcon(R.drawable.ic_stat_onesignal_default);
        builder.setContentTitle("A new Performance");
        builder.setContentText("There is a new performance nearby, click to see more");
        builder.setContentIntent(resultPendingIntent);
        notificationManager.notify(1, builder.build());
    }


}

问题分析与解决方案

核心问题:应用被杀后监听器未自动注册

从日志能看到AltBeacon的ScanJob确实在应用被杀后启动了,但你的MonitorNotifier和RangeNotifier仅在JS层调用start()方法时才注册。应用被杀后重启(由ScanJob触发),JS层不会自动执行,start()方法不会被调用,导致监听器没有绑定到BeaconManager,自然无法触发回调和通知。

具体修复步骤

1. 模块初始化时自动注册监听器

修改initialize()方法,在模块初始化阶段就完成监听器注册和扫描启动,无需依赖JS层触发:

@Override
public void initialize() {
    this.beaconManager = BeaconManager.getInstanceForApplication(mReactContext);
    beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout(BEACON_LAYOUT));
    beaconManager.setBackgroundBetweenScanPeriod(0);
    beaconManager.setBackgroundScanPeriod(1100);
    
    // 直接注册监听器并启动扫描
    beaconManager.addMonitorNotifier(monitorNotifier);
    beaconManager.addRangeNotifier(rangeNotifier);
    try {
        beaconManager.startMonitoring(region);
        beaconManager.startRangingBeacons(region);
        Log.d(TAG, "Beacon monitoring initialized automatically");
    } catch (Exception e) {
        Log.e(TAG, "Error initializing beacon monitoring", e);
    }
}

2. 修复代码变量错误

你的RangeNotifier中使用了未定义的beaconsToNotify变量,会导致运行时崩溃,修正如下:

RangeNotifier rangeNotifier = new RangeNotifier() {
    @Override
    public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
        if (beacons.size() > 0) {
            sendNotification();
            Log.d(TAG, "didRangeBeaconsInRegion called with beacon count:  "+beacons.size());
        }
    }
};

3. 完善Android权限与服务配置

在AndroidManifest.xml中添加必要权限和AltBeacon服务配置:

<!-- 蓝牙与位置权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

<!-- AltBeacon后台服务配置 -->
<service android:name="org.altbeacon.beacon.service.BeaconService" android:enabled="true"/>
<service android:name="org.altbeacon.beacon.service.ScanJobService" android:permission="android.permission.BIND_JOB_SERVICE" android:enabled="true"/>
<receiver android:name="org.altbeacon.beacon.startup.StartupBroadcastReceiver" android:enabled="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
        <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
        <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
    </intent-filter>
</receiver>

4. 处理Android后台限制

  • Android 8+需确保应用获取后台位置权限,否则后台扫描会被系统限制。
  • 部分国产ROM(小米、华为等)有额外后台管控,需将应用加入后台运行白名单,允许后台持续运行。

结论

React Native本身完全支持后台Beacon检测,问题出在你的实现逻辑上:监听器依赖JS层触发注册,应用被杀后无法自动恢复。通过上述修改,即可实现应用被杀后仍能检测Beacon并发送通知。

内容的提问来源于stack exchange,提问作者Emmanuel Yeboah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 07:40:33