1. 安卓15 ROM定制化入门:为什么我们需要修改系统设置菜单?
每次拿到新手机,第一件事就是进设置里关掉那些用不到的功能对吧?作为玩机十年的老手,我深知原生系统设置菜单有多臃肿——运营商定制应用、用不到的连接协议、永远不碰的辅助功能...这些选项不仅占地方,还可能后台耗电。今天要分享的正是如何从系统底层彻底移除这些冗余菜单项。
不同于简单的禁用或隐藏,我们这次要动真格的——直接修改ROM包里的系统框架文件。以安卓15为例,其设置菜单结构主要存储在/system/priv-app/Settings/Settings.apk中,这个APK实际上是个压缩包,内含决定菜单层级关系的XML文件和功能实现的smali代码。通过反编译修改这些文件,我们可以实现:
- 彻底移除"打印服务"等冷门功能入口
- 精简运营商定制菜单(比如国内常见的"服务"选项卡)
- 合并重复的功能选项(Wi-Fi和网络设置经常分散在不同位置)
- 隐藏开发者选项中危险但无用的调试功能
重要提示:修改系统APK前务必做好备份,错误的修改可能导致设置应用崩溃。建议在Magisk模块中操作以便快速回滚。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 工具准备与环境搭建
工欲善其事必先利其器,以下是经过我实测最稳定的工具组合:
2.1 核心工具链
- APK反编译:Apktool 2.7.0(新版对安卓15兼容性更好)
bash复制
java -jar apktool.jar d Settings.apk -o Settings_Decoded - 代码编辑:VS Code + Smalidea插件(比Notepad++更智能的跳转)
- 资源处理:Android Studio 2023.2(处理新版VectorDrawable必备)
- 签名工具:SignApk(AOSP原生签名工具,避免权限问题)
2.2 必须掌握的关键文件
在反编译输出的目录中,重点关注:
code复制res/xml/
- dashboard_categories.xml (主菜单结构)
- dashboard_tile.xml (快捷设置磁贴)
smali_classes2/com/android/settings/
- development/ (开发者选项相关)
- network/ (网络设置相关)
2.3 避坑指南
- 安卓15引入了新的
SettingsIntelligence服务,部分菜单动态加载,修改后需同时处理/system_ext/priv-app/SettingsIntelligence/下的对应文件 - 使用
aapt2编译时添加--enable-sparse-encoding参数避免资源ID冲突 - 遇到
INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED错误时,需在apktool.yml中设置doNotCompress: ["resources.arsc"]
3. 深度解析设置菜单结构
3.1 菜单层级控制机制
安卓15的设置采用"仪表盘"架构,核心逻辑是:
DashboardFragment加载dashboard_categories.xml- 每个
PreferenceCategory对应一个设置分组 Preference标签的android:key属性与后端代码绑定
以移除"数字健康"为例,需要:
- 在xml中找到对应category:
xml复制<PreferenceCategory
android:key="top_level_digital_wellbeing"
android:title="@string/digital_wellbeing_title" />
- 删除该段代码
- 在
smali中注释掉DigitalWellbeingPreferenceController相关调用
3.2 动态菜单的特殊处理
某些菜单(如SIM卡设置)是运行时动态添加的,需修改对应的PreferenceController。例如禁用双卡设置:
smali复制# 在PhonePreferenceController.smali中
.method public isAvailable()Z
.registers 2
const/4 v0, 0x0 # 原为0x1
return v0
.end method
4. 实战:精简运营商定制菜单
国内某品牌ROM的"服务"菜单包含20多项无用功能,按以下步骤清除:
- 定位运营商相关代码:
bash复制grep -r "Carrier" smali_classes3/
- 修改
CarrierSettingsPreferenceController:
smali复制.method public getAvailabilityStatus()I
.registers 2
const/4 v0, 0x2 # DISABLED_FOR_USER
return v0
.end method
-
删除
res/xml/carrier_settings.xml整个文件 -
处理依赖项(关键步骤!):
bash复制# 在AndroidManifest.xml中移除:
<activity android:name=".carrier.CarrierSettingsActivity" />
5. 高级技巧:条件化隐藏菜单
有时我们想根据设备特性动态隐藏菜单(如没有NFC的设备隐藏NFC设置),这需要修改AvailabilityPreferenceController的子类。示例代码:
smali复制# 在NfcPreferenceController.smali中
.method public getAvailabilityStatus()I
.registers 2
# 原代码会检查NFC硬件
# 我们强制返回不可用
const/4 v0, 0x3 # DISABLED_UNSUPPORTED
return v0
.end method
6. 编译与测试注意事项
- 编译时务必使用原始框架资源:
bash复制apktool b Settings_Decoded -o new_Settings.apk --use-aapt2
- 签名必须使用平台密钥(提取自原厂ROM):
bash复制java -jar signapk.jar platform.x509.pem platform.pk8 new_Settings.apk Settings_signed.apk
- 测试阶段建议通过Magisk模块部署,方便快速迭代:
code复制/system/priv-app/Settings/
- Settings.apk (替换文件)
- Settings.odex (如有)
- arm64/ (原生库目录)
7. 常见问题排查
问题1:设置应用无限停止
- 检查
AndroidManifest.xml中所有activity是否都有对应smali代码 - 确认没有误删
Preference的key值
问题2:菜单项消失但功能仍可通过搜索访问
- 需同时修改
SearchIndexableResources.xml - 在对应
Index类中添加@SearchIndexable(forTarget = false)
问题3:OTA更新后修改失效
- 修改
/system/etc/permissions/下的功能配置文件 - 添加
<unavailable-feature name="android.hardware.nfc" />
8. 延伸思考:安全与稳定性的平衡
经过深度修改的ROM虽然简洁,但需要注意:
- 系统签名验证(V3 Scheme)可能触发SafetyNet失败
- 关键服务(如电话)依赖的隐藏设置不要移除
- 建议保留"重置所有设置"的紧急恢复入口
我习惯在/data/adb/modules/下保留修改记录,包含:
- 原始APK备份
- 修改记录文档
- 回滚脚本
这样即使升级系统也能快速重新应用定制。
