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

React Native安卓应用后台可解锁设备 进程被杀时无法解锁如何解决

问题根因

你的猜测是正确的,应用被系统杀死后,收到推送触发Headless JS任务时,进程仅启动了RN的后台执行上下文,此时还没有启动任何Activity实例,DeviceLock.unlock()中获取的activity为空,后续所有对窗口、Activity的操作都无法生效。

改造方案

1. 调整唤醒逻辑执行顺序

先监听AppState切换到前台的事件,等Activity完全启动后再执行解锁操作,修改nativePhoneUI.js的wakeApp方法:

import { AppState } from 'react-native'

export function wakeApp(name) {
    calleeName = name;
    if (deviceWasLocked) {
        // 注册状态监听,App切到前台后再执行解锁
        const appStateListener = AppState.addEventListener('change', (nextAppState) => {
            if (nextAppState === 'active') {
                NativeModules.DeviceLock.unlock();
                deviceWasLocked = false;
                appStateListener.remove();
            }
        })
    }
    RNCallKeep.backToForeground();
}

2. 改造原生DeviceLock模块

增加空指针防护和Activity生命周期监听,应用被杀状态下调用解锁时先标记待执行任务,等Activity启动后自动执行解锁逻辑,修改DeviceLock.java代码如下:

package com.fleeting;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.LifecycleEventListener;
import android.app.Activity;
import android.os.Build;
import android.view.WindowManager;
import android.os.PowerManager;
import android.content.Context;

public class DeviceLock extends ReactContextBaseJavaModule {

    @Override
    public String getName() {
        return "DeviceLock";
    }

    private ReactContext mReactContext;
    private PowerManager.WakeLock sCpuWakeLock;
    private boolean pendingUnlock = false;

    public DeviceLock(ReactApplicationContext reactContext) {
        super(reactContext);
        mReactContext = reactContext;
        // 注册Activity生命周期监听
        mReactContext.addLifecycleEventListener(new LifecycleEventListener() {
            @Override
            public void onHostResume() {
                if (pendingUnlock) {
                    executeUnlock();
                    pendingUnlock = false;
                }
            }
            @Override
            public void onHostPause() {}
            @Override
            public void onHostDestroy() {}
        });
    }

    @ReactMethod
    public void unlock() {
        Activity currentActivity = mReactContext.getCurrentActivity();
        if (currentActivity == null) {
            // Activity未启动,标记待执行解锁
            pendingUnlock = true;
            return;
        }
        executeUnlock();
    }

    private void executeUnlock() {
        Activity activity = mReactContext.getCurrentActivity();
        if (activity == null) return;

        PowerManager pm = (PowerManager) mReactContext.getSystemService(Context.POWER_SERVICE);
        int flags = PowerManager.SCREEN_BRIGHT_WAKE_LOCK 
                | PowerManager.ACQUIRE_CAUSES_WAKEUP 
                | PowerManager.ON_AFTER_RELEASE;
        if (sCpuWakeLock != null && sCpuWakeLock.isHeld()) {
            sCpuWakeLock.release();
        }
        // 增加10分钟超时,避免一直持有锁导致耗电
        sCpuWakeLock = pm.newWakeLock(flags, activity.getClass().getName() + ":unlock");
        sCpuWakeLock.acquire(10*60*1000L);

        activity.runOnUiThread(() -> {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
                activity.setShowWhenLocked(true);
                activity.setTurnScreenOn(true);
            }
            activity.getWindow().addFlags(
                   WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                    | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON 
                    | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                    | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
        });
    }
                    
    @ReactMethod
    public void lock() {
        if (sCpuWakeLock != null && sCpuWakeLock.isHeld()) {
            sCpuWakeLock.release();
        }
        Activity activity = mReactContext.getCurrentActivity();
        if (activity == null) return;

        activity.runOnUiThread(() -> {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
                activity.setShowWhenLocked(false);
                activity.setTurnScreenOn(false);
            }
            activity.getWindow().clearFlags( 
                     WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                    | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON 
                    | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                    | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
        });
    }
}

3. 补充安卓权限配置

在AndroidManifest.xml中添加所需权限:

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.SHOW_WHEN_LOCKED" />
<uses-permission android:name="android.permission.TURN_SCREEN_ON" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

同时需要引导用户在系统设置中给应用开启「后台弹出界面」「显示在其他应用上层」的特殊权限,不同厂商的权限命名可能存在差异。

4. 调整后台消息回调判断逻辑

修改backgroundNotificationHandler.js的判断条件,覆盖锁屏场景:

// 兼容被杀状态下appState为空的情况
if (appState === BACKGROUND || appState === null) {
    registerPhoneAccount();
    displayIncomingCallFromKilled(calleeName, phoneNumber, nativeCallUIUUID);
    setNativeCallUIForegroundService();
    registerNativePhoneUIEvents();
    addNativeCallUIEventListeners(nativeCallUIUUID, true, locked);
    wakeApp(calleeName);
}

内容的提问来源于stack exchange,提问作者Mr. Robot

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 20:30:03