预置应用与 GMS:预置 APK 方法、GMS 包集成、权限预授权

做嵌入式 Android 系统,有一件事你肯定绕不开——预置应用。说白了,就是设备出厂时,桌面上那些已经装好的 App。不管是系统自带的计算器、相机,还是客户定制的行业应用,都得通过预置的方式塞进系统里。

我刚开始接触 AOSP 时,以为预置 APK 就是把 apk 文件扔到 system/app 目录下就完事了。结果呢?编译出来的镜像要么启动崩溃,要么应用权限不全。后来踩了不少坑,才摸清楚这里面的门道。

今天咱们就聊聊三件事:预置 APK 的几种方法GMS 包的集成流程、以及权限预授权。这三块搞定了,定制 ROM 的基础能力就算拿下了。

预置 APK 的三种主流方式

预置 APK 不是简单地把文件拷贝进去。Android 系统对预置应用有严格的签名、权限、库依赖要求。我总结下来,常用的方法有三种。

方法一:直接预置到 system/app

这是最传统的方式。把 APK 放到 packages/apps/ 下,然后写一个 Android.mkAndroid.bp 文件。

举个例子,假设你要预置一个叫 MyApp 的应用:

# Android.bp
android_app {
    name: "MyApp",
    srcs: ["src/**/*.java"],
    resource_dirs: ["res"],
    platform_apis: true,
    certificate: "platform", // 使用平台签名
    privileged: true,        // 作为特权应用
}

这里有个关键点——certificate: "platform"。用平台签名意味着你的应用拥有系统级权限。我在项目中遇到过,如果不用平台签名,预置的应用可能无法访问某些系统 API,比如读写短信记录。

注意: 使用平台签名后,应用就绑定了这个 ROM 的签名。如果后续升级 ROM 时签名变了,应用会无法覆盖安装,只能卸载重装。

方法二:预置到 product 分区

从 Android 10 开始,Google 推荐把厂商定制应用放到 product 分区。这样做的好处是,系统 OTA 升级时可以只更新 system 分区,不影响 product 分区里的应用。

目录结构一般是:

device/<vendor>/<product>/apps/MyApp/
├── Android.bp
├── MyApp.apk
└── AndroidManifest.xml

对应的 Android.bp 写法:

android_app_import {
    name: "MyApp",
    apk: "MyApp.apk",
    privileged: true,
    presigned: true, // 使用 APK 自带的签名
    product_specific: true,
}

我个人习惯用 android_app_import 而不是 android_app,因为很多时候客户给的是编译好的 APK,我们不需要重新编译源码。直接导入就行,省事。

方法三:预置到 data/app(可卸载)

有些应用需要预置,但允许用户卸载。这时候可以放到 data/app 目录。不过要注意,这种方式需要额外的配置。

device.mk 中添加:

PRODUCT_PACKAGES += MyApp
# 标记为可卸载
PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST += \
    data/app/MyApp/MyApp.apk

嗯,这里有个坑——如果应用预置在 data 分区,恢复出厂设置时会被清除。所以银行类、支付类的核心应用,千万别用这种方式。

GMS 包集成:Google 服务的正确姿势

GMS(Google Mobile Services)是 Google 官方服务的集合,包括 Play Store、Gmail、地图等。如果你做的是面向海外市场的设备,GMS 几乎是必选项。

但 GMS 不是开源的,也不能随便集成。你需要和 Google 签订 GMS 授权协议,拿到 GMS 包。这个包通常是一个 ZIP 文件,里面包含几十个 APK 和对应的库文件。

集成步骤

拿到 GMS 包后,集成流程大致如下:

  1. 解压 GMS 包,你会看到 apps/etc/framework/ 等目录。
  2. 将 APK 放到对应位置。大部分 GMS 应用需要预置到 system/priv-app 目录,因为它们是特权应用。
  3. 添加权限配置。GMS 应用需要大量权限,比如位置、联系人、电话等。这些权限需要在 system/etc/permissions/ 下声明。
  4. 配置产品 Makefile。在 device.mk 中引用 GMS 包:
# 引用 GMS 包
$(call inherit-product, vendor/google/products/gms.mk)

# 或者手动添加
PRODUCT_PACKAGES += \
    GooglePlayServices \
    GooglePlayStore \
    GoogleServicesFramework \
    ...
小技巧: 我建议把 GMS 包单独放在 vendor/google/ 目录下,不要混入 AOSP 源码。这样方便后续升级 GMS 版本,也符合 Google 的合规要求。

GMS 认证注意事项

集成 GMS 后,设备需要通过 CTS(Compatibility Test Suite)和 GTS(Google Test Suite)认证。我遇到过最头疼的问题是——某些 GMS 应用在预置后无法正常启动,原因是缺少 Google 服务框架的签名。

解决方案是:确保所有 GMS 应用都使用 Google 的 platform 签名,或者使用 GMS 包自带的签名文件。千万不要自己重新签名,否则 Google 服务会拒绝工作。

权限预授权:让应用开箱即用

你有没有遇到过这种情况?设备刚开机,用户打开预置的相机应用,结果弹出一堆权限请求框。用户体验很差,对吧?

权限预授权,就是提前把某些权限授予预置应用,让用户不用手动确认。说白了,就是系统替用户做了决定。

实现方式

在 AOSP 中,权限预授权主要通过 AndroidManifest.xml 中的 <uses-permission> 标签,以及系统级的 permissions.xml 文件来实现。

具体做法是:

  1. 在应用的 AndroidManifest.xml 中声明权限。这是基础,不声明的话系统根本不会授予。
  2. 在系统配置中预授权。修改 frameworks/base/core/res/res/xml/config_perm.xml,或者使用 overlay 机制覆盖。

举个例子,假设你要预授权 MyApp 使用相机和位置权限:

<!-- config_perm.xml -->
<permissions>
    <privapp-permissions package="com.example.myapp">
        <permission name="android.permission.CAMERA"/>
        <permission name="android.permission.ACCESS_FINE_LOCATION"/>
    </privapp-permissions>
</permissions>

然后把这个文件放到 system/etc/permissions/ 目录下。编译时系统会自动读取并授予权限。

核心逻辑: 权限预授权的本质是系统在应用安装时,自动调用 grantRuntimePermission() 方法。所以只要系统配置到位,应用一安装就拥有了指定权限。

避坑指南

我曾经在项目中犯过一个错误——把预授权配置写到了 vendor 分区,但应用预置在 system 分区。结果权限配置没生效,因为系统在解析权限时,是按分区顺序加载的。

正确的做法是:预授权配置文件和预置应用必须在同一个分区。如果应用在 system/priv-app,配置也要放在 system/etc/permissions

另外,Android 11 之后,Google 对权限预授权收紧了。非特权应用(非 priv-app)无法通过 privapp-permissions 标签预授权。所以如果你的应用不是特权应用,预授权会失败。解决办法就是让应用成为特权应用,或者使用 grant-uri-permission 等更细粒度的控制方式。

知识体系总览

下面这张图总结了预置应用与 GMS 集成的核心流程和决策点:

预置应用与 GMS 集成知识体系 预置 APK 方式 GMS 包集成 权限预授权 system/app 预置 product 分区预置 data/app 可卸载 GMS 包解压配置 AndroidManifest 声明 Android.bp / Android.mk product_specific: true PRODUCT_PACKAGES vendor/google/gms.mk config_perm.xml 配置 输出:定制 ROM 镜像(system.img / product.img) 包含预置应用、GMS 服务、预授权权限 图:预置应用与 GMS 集成决策流程

写在最后

预置应用这件事,说简单也简单,说复杂也复杂。简单在于,你只要把 APK 放对位置、写对配置文件,编译出来就能用。复杂在于,签名、分区、权限、GMS 合规,任何一个环节出问题,设备就可能无法正常工作。

我个人建议,刚开始做定制 ROM 时,先从 product 分区预置入手。这种方式最灵活,也最容易调试。等把流程跑通了,再根据需求调整到 systemdata 分区。

至于 GMS,如果你不是做海外市场,可以跳过。但如果要做,一定要走正规授权渠道,别用网上流传的破解包。我见过有人用盗版 GMS 包,结果设备被 Google 远程封禁,用户投诉到崩溃。

权限预授权这块,记住一个原则:只预授权应用真正需要的权限。别图省事把所有权限都给了,那样反而会带来安全风险。


公众号:蓝海资料掘金营,微信deep3321