把 Android App 打包成系统应用(System App)

0 阅读2分钟

一句话结论

只有被平台私钥签名的 APK,放到 /system/priv-app/ 下并设置 android:sharedUserId="android.uid.system",才能成为真正的系统应用,获得 READ_PRIVILEGED_PHONE_STATE、MOUNT_UNMOUNT_FILESYSTEMS 等特权权限。


适用场景

  • 需要预装到定制设备
  • 需要访问普通应用无法申请的特权权限
  • ROM 厂商、ODM/OEM 项目、行业终端调试

01. 拿到 platform key 的三个文件

系统签名的核心就是这三个文件,必须和设备 ROM 对应:

文件作用常见来源
platform.x509.pem公钥证书AOSP 源码 build/target/product/security/
platform.pk8私钥同上,或设备厂商提供的 releasekey
signapk.jarAOSP 签名工具源码路径 build/tools/signapk/

厂商 ROM 的 key 文件名可能是 releasekey.pk8、releasekey.x509.pem 或 vendor_xxxx.pk8,必须和设备实际刷入的 ROM 匹配,否则签名无效。


02. 把 APK 重新签名为 platform 签名

2.1 先用 q5.jks 出 v1-only 的 release APK

在 app/build.gradle 的 release 配置里强制 v1 签名:

android {
    signingConfigs {
        config {
            // q5.jks 配置
            storeFile file("q5.jks")
            storePassword "xxx"
            keyAlias "xxx"
            keyPassword "xxx"
​
            v1SigningEnabled true
            v2SigningEnabled false
        }
    }
​
    buildTypes {
        release {
            signingConfig signingConfigs.config
        }
    }
}

debug 版本必须保持 v1SigningEnabled true 和 v2SigningEnabled true 都开启,否则 adb install 在 7.0+ 设备上会失败。

然后在 Android Studio 里:

Build -> Generate Signed APK -> 选择 q5Release flavor

2.2 用 signapk 重新签名

拿到 app\build\outputs\apk\q5\release\q5_xxx_release.apk 后,执行:

java -jar signapk.jar \
    -w \
    platform.x509.pem \
    platform.pk8 \
    app\build\outputs\apk\q5\release\q5_xxx_release.apk \
    app-system-signed.apk

signapk.jar 默认只生成 v1 签名,正好符合系统应用要求。签完不要再拿 jks 工具二次签名,否则会覆盖 platform 签名。


03. 推送到设备的 /system/priv-app/

adb root
adb remount
​
# 1) 建包名目录(注意用 applicationId,不是 package)
adb shell mkdir -p /system/priv-app/com.qhsoft.q5
​
# 2) 推送 APK
adb push app-system-signed.apk /system/priv-app/com.qhsoft.q5/app.apk
​
# 3) 关键权限设置,这三步很多人漏
adb shell chmod 644 /system/priv-app/com.qhsoft.q5/app.apk
adb shell chown root:root /system/priv-app/com.qhsoft.q5/app.apk
adb shell restorecon /system/priv-app/com.qhsoft.q5/app.apk
​
# 4) 重启生效
adb reboot

chmod 644、chown root:root、restorecon 必须做,否则 SELinux 或文件权限检查会导致系统应用权限不生效。


04. 验证是否真正成为系统应用

4.1 确认是系统应用(userId=1000)

adb shell dumpsys package com.qhsoft.q5 | findstr "userId"

期望输出包含 userId=1000。

4.2 确认从 priv-app 路径安装

adb shell pm path com.qhsoft.q5

期望:

/system/priv-app/com.qhsoft.q5/app.apk

4.3 确认特权权限已授权

adb shell dumpsys package com.qhsoft.q5 | findstr "READ_PRIVILEGED_PHONE_STATE"

期望:

permission grant=true

配套改动清单

AndroidManifest.xml

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.qhsoft.q5"
    android:sharedUserId="android.uid.system">
​
    <application
        android:persistent="true"
        ... />
​
</manifest>

android:sharedUserId="android.uid.system" 是核心,否则即使放到 priv-app 也拿不到系统权限。

app/build.gradle

signingConfigs {
    config {
        storeFile file("q5.jks")
        storePassword "xxx"
        keyAlias "xxx"
        keyPassword "xxx"
​
        v1SigningEnabled true
        v2SigningEnabled false
    }
}

总结

  1. 系统应用必须用设备的 platform 私钥签名。
  2. 签名后的 APK 要放到 /system/priv-app/<applicationId>/app.apk。
  3. 配置目录权限 644、root:root、restorecon 后重启。
  4. AndroidManifest.xml 必须声明 android:sharedUserId="android.uid.system"。

按这套流程走下来,dumpsys package 看到 userId=1000 和 permission grant=true,就说明系统应用模式已经跑通。