android系统如何防App退出

6 阅读4分钟

重新回到最本源的需求:

  1. 开机自启(10s 内)。
  2. 防退出(无论几十个 Activity 怎么跳转,都不能退到桌面)
  3. 保留原生 Launcher,工程模式鉴权后能正常使用原生桌面。
  4. 稳定、简单、容易落地

其实,Android 系统原生就自带了专门解决这个场景的标准机制,根本不需要改动几百行 Framework 代码。以下为您提供一套极简、稳定、符合 Android 原生设计哲学的极轻量级方案。


极简核心思路:动态角色切换(Launcher 替换法)

核心秘密:Android 系统的“防退出”本质上就是不让用户回到别的桌面。 那么,让“具微遥控 APP”自己变成“系统默认桌面(Launcher)”,问题瞬间全部解决!

  • 当你是桌面时,用户按 Home 键?回到你自己
  • 用户有几十个 Activity,狂按 Back 键把所有页面都 finish 完了?系统自动重新打开桌面(也就是你自己)
  • 根本不需要拦截 Back 键,不需要管有几十个还是几百个 Activity,因为栈空了系统天然就会回到当前桌面
  • 开机自启?Android 开机第一个启动的就是默认桌面,天然秒开,无需任何开机广播
  • 怎么进入原生桌面?代码动态切换默认桌面,一秒搞定。

方案具体实现(只需 3 步,零 Hack)

第一步:在 AndroidManifest.xml 中声明为 Home(桌面)

让具微遥控的 MainActivity 具备 Launcher 属性。

<activity
    android:name=".ui.MainActivity"
    android:exported="true"
    android:launchMode="singleTask">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <!-- 核心:声明自己是桌面 -->
        <category android:name="android.intent.category.HOME" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

效果:系统原生支持多桌面。开机时,系统会直接拉起默认桌面。


第二步:ROM 出厂配置(仅需配置 1 个系统默认项)

因为设备上同时存在“原生 Launcher”和“具微遥控”,系统首次开机需要知道默认选谁。

在 ROM 源码的 frameworks/base/core/res/res/values/config.xml 中(或者通过 Overlay),指定具微遥控为开机首选桌面:

<!-- 将系统默认 Preferred Launcher 指向具微遥控 -->
<string name="config_customResolverActivity" translatable="false">com.remote.control/.ui.MainActivity</string>

(或者更标准的 AOSP 做法:在出厂 settings 数据库 frameworks/base/packages/SettingsProvider/res/values/defaults.xml 中把默认 Home 设置为 com.remote.control)

效果

  1. 开机自启:开机后 SurfaceFlinger 就绪,系统第一个渲染的就是具微遥控,3~5 秒直达
  2. 几十个 Activity 防退出:无论内部 Activity 怎么跳转、怎么崩、按多少次 Back/Home 键,退到最后一定是退回“默认桌面”(即具微遥控主页)。完全不用写任何栈管理代码!

第三步:工程模式退出与还原(极简 API 调用)

具微遥控作为 系统 APP (Priv-App),拥有调用 PackageManager 特权 API 的权限。

1. 密码/证书验证通过 -> 切到原生桌面

当在工程模式中鉴权成功,需要去原生桌面时:一行代码拉起原生 Launcher

fun switchToNativeLauncher(context: Context) {
    // 1. 找到系统原生 Launcher 的包名(例如 AOSP 的 Launcher3)
    val nativeLauncherIntent = Intent(Intent.ACTION_MAIN).apply {
        addCategory(Intent.CATEGORY_HOME)
        setPackage("com.android.launcher3") // 指定原生 Launcher 包名
        addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    }
    
    // 2. 直接启动原生桌面
    context.startActivity(nativeLauncherIntent)
}
2. 从原生桌面返回App

在原生桌面上,点击应用图标,即可随时回到App。


补充:隐藏状态栏/下拉菜单(防误触)

为了防止用户从顶部下拉状态栏去点“系统设置”逃逸,在具微遥控的 BaseActivity 里加上标准的全屏沉浸即可:

// Android 11~16 标准沉浸式全屏,几行搞定
class BaseActivity : AppCompatActivity() {
    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        if (hasFocus) {
            val controller = WindowInsetsControllerCompat(window, window.decorView)
            controller.hide(WindowInsetsCompat.Type.systemBars()) // 隐藏导航栏与状态栏
            controller.systemBarsBehavior = 
                WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
        }
    }
}

新旧方案终极对比

评估维度上一版复杂方案 (Task/Framework/SELinux 改写)本版极简方案 (动态 Launcher 法)
AOSP 源码修改量修改 ATMS、WMS、PWM、SELinux 等几十处代码仅修改 1 行配置(指定默认桌面),不改 Framework 逻辑
多 Activity 支持需写 BaseActivity 拦截、栈拓扑监听、Task 修复天然支持,Android 系统把 App 当桌面,栈空自动回 App 主页
系统稳定性极高风险引入系统级 Bug,阻碍 Android 版本升级零风险,完全运行在 Android 原生设计的标准轨道上
开机启动速度需做 Direct Boot 等复杂调优秒开(Android 优先初始化并拉起默认桌面)
维护成本需专用系统工程师常驻维护普通 Android 开发者 1 天内即可完成交付

结论

“把你做成系统默认 Launcher” 是 Android 工业级终端、车载中控屏、POS 机最经典、最稳定、代码量最少的做法。无需任何复杂黑科技,完全满足您的 PRD 需求。