工控 APP 打包与预置:签名、系统应用、预装到 system/app 分区方法
工控 APP 打包与预置:签名、系统应用、预装到 system/app 分区方法
你的工控APP装在/data分区,用户一个"恢复出厂"就没了——要想永生,就得住进system分区。
一、APK签名机制
1.1 为什么需要签名
Android系统安装APK时会校验签名,两个作用:
- 完整性验证:确保APK没有被篡改
- 身份识别:相同签名的APP可以共享数据(sharedUserId依赖签名一致性)
没有签名的APK,Android拒绝安装。
1.2 v1/v2/v3签名区别
| 签名方案 | 引入版本 | 签名位置 | 特点 |
|---|---|---|---|
| v1 (JAR签名) | Android 1.0 | META-INF/ 目录 | 基于JAR,可被增量更新覆盖 |
| v2 (APK签名) | Android 7.0 | APK文件末尾额外块 | 全文件校验,防篡改更强 |
| v3 (APK签名v3) | Android 9.0 | APK文件末尾额外块 | 支持密钥轮转(签名密钥可更换) |
工控建议:固件预装APK用v1+v2双签名,兼容所有Android版本。Android 11+ 默认强制v2/v3,但工控设备ROM版本跨度大(从4.4到12都有),双签名是安全选择。
1.3 生成keystore
keytool-genkeypair-v\-keystoreindustrial.keystore\-aliasindustrial\-keyalgRSA\-keysize2048\-validity10000\-sigalgSHA256withRSA参数说明:
-validity 10000:有效期10000天(约27年),工控设备不能让签名过期-keysize 2048:密钥长度,2048位是安全底线
用此keystore在Gradle中签名:
android{signingConfigs{release{storeFilefile("industrial.keystore")storePassword"your_password"keyAlias"industrial"keyPassword"your_password"}}buildTypes{release{signingConfig signingConfigs.release}}}二、普通应用 vs 系统应用
2.1 核心区别
| 维度 | 普通应用(/data/app) | 系统应用(/system/app) |
|---|---|---|
| 安装位置 | /data/app/ | /system/app/ 或 /system/priv-app/ |
| 卸载 | 可卸载 | 无法通过常规方式卸载 |
| 权限等级 | 普通权限+危险权限(需动态申请) | 可获得系统级权限(signature |
| 更新方式 | 应用商店/adb install | 只能通过固件升级或adb push覆盖 |
| 恢复出厂 | 会被清除 | 保留(system分区不受影响) |
| sharedUserId | 不生效(除非系统签名) | 可用android.uid.system获得系统权限 |
工控核心诉求:系统应用不会被"恢复出厂设置"清除,且拥有更高权限。工控APP绝大多数场景都需要以系统应用身份运行。
2.2 priv-app——特权应用
Android 4.4+ 引入/system/priv-app/目录,放入此目录的APP不仅能获得系统签名权限,还能获得privileged级别权限(如WRITE_SETTINGS、SET_DEBUG_APP等普通系统应用也拿不到的权限)。
/system/app/ → 系统应用(普通系统权限) /system/priv-app/ → 特权系统应用(最高权限等级)三、系统签名获取方式
3.1 方式一:平台密钥签名
最正统的方式——用设备厂商提供的平台密钥对APK签名:
# 用signapk.jar签名(Android源码中的签名工具)java-jarsignapk.jar\platform.x509.pem\platform.pk8\app-release-unsigned.apk\app-release-signed.apkplatform.pk8和platform.x509.pem是设备厂商的平台私钥和证书,不同厂商密钥不同,同一厂商不同产品线也可能不同。
签名后配合android:sharedUserId="android.uid.system",APP就运行在系统进程空间,拥有全部系统权限。
3.2 方式二:将keystore转换为平台密钥格式
如果你有platform.pk8和platform.x509.pem,可以转换为Android Studio可用的keystore:
# pk8转pem私钥openssl pkcs8-inplatform.pk8-informDER-outformPEM\-outplatform.pem-nocrypt# 生成pkcs12格式keystoreopenssl pkcs12-export-inplatform.x509.pem\-inkeyplatform.pem\-outplatform.p12-nameplatform# pkcs12转jks keystorekeytool-importkeystore-deststorepassandroid\-destkeystoreplatform.keystore\-srckeystoreplatform.p12\-srcstorepassandroid-aliasplatform生成的platform.keystore可直接在Gradle中使用。
3.3 方式三:预装到system分区(无需系统签名)
不声明sharedUserId,仅通过push到/system/app/目录使APP成为系统应用。这种方式APP只能获得普通系统权限,不能获得signature级权限。
适用场景:APP不需要系统级特权,只需要"恢复出厂不被清除"。
四、预装到system/app分区——三种方法
4.1 方式一:打包到固件(推荐,量产方案)
将APK放入Android源码树,编译进system.img:
步骤1:创建预置目录
Android源码根目录/packages/apps/MyIndustrialApp/ ├── Android.mk ├── MyIndustrialApp.apk步骤2:编写Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := MyIndustrialApp LOCAL_MODULE_CLASS := APPS LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) LOCAL_SRC_FILES := MyIndustrialApp.apk LOCAL_CERTIFICATE := platform # 用平台密钥签名 # LOCAL_CERTIFICATE := PRESIGNED # 如果APK已自行签名 include $(BUILD_PREBUILT)LOCAL_CERTIFICATE := platform表示编译系统会用平台密钥重新签名APK。
步骤3:配置产品mk文件
在设备的device/<vendor>/<product>/<product>.mk中添加:
PRODUCT_PACKAGES += MyIndustrialApp步骤4:编译固件
makesystemimage-j8APK会自动编译进system.img,烧录固件后APP就在/system/app/MyIndustrialApp/目录中。
4.2 方式二:adb手动推送(调试/小批量方案)
# 1. 获取root权限并remountadb root adb remount# 2. 推送APK到system分区adb push MyIndustrialApp.apk /system/app/MyIndustrialApp/# 3. 创建目录方式(推荐,更规范)adb shellmkdir/system/app/MyIndustrialApp adb push MyIndustrialApp.apk /system/app/MyIndustrialApp/MyIndustrialApp.apk# 4. 重启让系统识别adbreboot注意:
adb remount需要root权限。部分设备的system分区是只读的,需要先adb shell mount -o rw,remount /system。
陷阱:Android 9+ 的system分区可能采用A/B分区设计,直接push修改的是当前活跃分区,下次OTA更新可能被覆盖。量产必须走方式一。
4.3 方式三:通过recovery刷入
适用于无法adb remount的场景(如系统分区锁死):
步骤1:创建刷机包结构
update.zip/ ├── META-INF/ │ └── com/ │ └── google/ │ └── android/ │ ├── update-binary │ └── updater-script ├── system/ │ └── app/ │ └── MyIndustrialApp/ │ └── MyIndustrialApp.apk步骤2:编写updater-script
ui_print("Installing MyIndustrialApp...");mount("ext4","EMMC","/dev/block/bootdevice/by-name/system","/system");package_extract_dir("system","/system");set_perm(0,0, 0644,"/system/app/MyIndustrialApp/MyIndustrialApp.apk");unmount("/system");ui_print("Done!");步骤3:签名zip并刷入
# 签名刷机包java-jarsignapk.jar testkey.x509.pem testkey.pk8 update.zip update-signed.zip# 进入recovery模式刷入adbrebootrecovery# 或通过fastbootfastboot update update-signed.zip五、APK预置注意事项
5.1 so库适配
预装APK的native库(.so)架构必须与设备CPU架构匹配:
# 查看设备架构adb shell getprop ro.product.cpu.abi# 常见结果:arm64-v8a, armeabi-v7aAPK中的so库需要放在正确目录:
/system/app/MyIndustrialApp/lib/arm64/ → arm64-v8a的so库 /system/app/MyIndustrialApp/lib/arm/ → armeabi-v7a的so库5.2 odex优化
系统预装APP会在启动时进行dex优化生成odex文件,加快首次启动速度。如果固件编译时已生成odex(LOCAL_DEX_PREOPT := true),则无需二次优化。
调试阶段推送的APK首次启动会较慢,系统在做dex2oat优化,等一会儿就好。
5.3 权限预配置
系统预装APP的权限默认全部授权(无需用户确认),但部分危险权限在Android 6.0+仍需要运行时申请。预装到system分区可以绕过部分限制,但priv-app白名单机制(/system/etc/permissions/privapp-permissions.xml)可能拒绝某些特权:
<!-- /system/etc/permissions/privapp-permissions-myapp.xml --><permissions><privapp-permissionspackage="com.example.industrial"><permissionname="android.permission.WRITE_SETTINGS"/><permissionname="android.permission.SYSTEM_ALERT_WINDOW"/></privapp-permissions></permissions>六、预装应用更新与卸载说明
6.1 更新
系统分区的APP不能通过常规adb install更新(版本号冲突)。更新方式:
- 重新push覆盖:
adb push new.apk /system/app/MyIndustrialApp/MyIndustrialApp.apk,然后adb reboot - 固件升级:新版固件包含新版APP,OTA推送或手动烧录
- 应用商店更新:部分定制ROM允许通过应用商店覆盖更新系统APP(更新装在/data分区,优先级高于/system中的旧版本)
6.2 卸载
# 临时卸载(恢复出厂设置后会恢复)adb shell pm uninstall-k--user0com.example.industrial# 永久卸载(需要root,删除system分区中的文件)adb root adb remount adb shellrm-rf/system/app/MyIndustrialApp adbreboot-k参数保留数据缓存,不加则彻底清除。永久卸载需要删除system分区中的物理文件。
七、完整操作流程速查
| 步骤 | 操作 | 命令 |
|---|---|---|
| 1 | 编译release APK | ./gradlew assembleRelease |
| 2 | 用平台密钥签名 | java -jar signapk.jar platform.x509.pem platform.pk8 app.apk app-signed.apk |
| 3 | adb推送到system | adb push app-signed.apk /system/app/MyIndustrialApp/ |
| 4 | 重启设备 | adb reboot |
| 5 | 验证安装 | adb shell pm list packages | grep industrial |
| 6 | 验证权限 | adb shell dumpsys package com.example.industrial | grep granted=true |
把APP送进system分区,它就跟固件绑定了命——恢复出厂不怕、权限等级拉满、开机自动就位。这是工控APP走向"正式上岗"的必经之路。