定制 Launcher:SystemUI 修改、默认应用设置、开机向导定制

好,咱们今天聊点真正能让你手里的 ROM 变得「不一样」的东西。Launcher、SystemUI、开机向导——这三个东西,说白了就是用户对一台 Android 设备的第一印象和日常交互的全部。我当年第一次给一款教育平板做定制 ROM 时,甲方就提了一个要求:「开机后不能看到任何 Google 的影子,桌面要像一本翻开的书。」嗯,那会儿我才意识到,光会编译 AOSP 远远不够,你得会「动刀子」。

Launcher 定制:从换图标到改布局

Launcher 就是桌面。AOSP 自带的 Launcher3 其实挺干净的,但你要做定制 ROM,肯定得改。改什么?

  • 默认图标包:替换 res/drawable 下的图标资源
  • 桌面网格:修改 InvariantDeviceProfile.java 中的行列数
  • Dock 栏行为:是否允许添加应用、是否显示搜索框
  • 手势与动画:比如上滑抽屉、下拉通知栏的联动

我个人习惯先把 Launcher3 的源码单独拉出来,放到 packages/apps/ 下,然后直接改。举个例子,你想把默认桌面改成 5x6 的网格:

// InvariantDeviceProfile.java
public static final InvariantDeviceProfile[] DEVICE_PROFILES = {
    new InvariantDeviceProfile("Nexus 5", 5, 6, 4, 4, 3, 2, 2, 480, 800, 320, 2),
    // ...
};

改完重新编译 make Launcher3,刷进去就能看到效果。我在项目中遇到过一个问题:改了网格后,某些小部件显示不全。后来发现是 GridSizeIconSize 没同步调整。你想想看,图标大小不变,格子却变小了,肯定要出问题。

小技巧:修改 Launcher 的 config.xml 中的 grid_size_xgrid_size_y,比直接改 Java 代码更安全,也更容易维护。

SystemUI 修改:状态栏、快捷开关、锁屏

SystemUI 是 Android 系统的「脸面」。状态栏、通知栏、快捷开关、锁屏、音量面板……全在这里。我建议你把它当成一个独立的 App 来理解——它其实就是一个系统级应用,只不过权限高一些。

常见的定制点:

  • 状态栏图标:替换 SystemUI/res/drawable 下的电池、信号、WiFi 图标
  • 快捷开关布局:修改 QuickQSPanel.javaQSPanel.java 中的 tile 数量
  • 锁屏界面:去掉默认的相机快捷方式、修改时钟样式
  • 音量面板:改成垂直布局或加入媒体输出选择

举个例子,你想在状态栏右侧显示实时网速。这个功能在 AOSP 里默认是关闭的,但代码其实已经写好了。你只需要在 SystemUI/res/values/config.xml 里把 config_showNetworkSpeed 改成 true

<bool name="config_showNetworkSpeed">true</bool>

然后重新编译 make SystemUI。嗯,就这么简单。但要注意,有些厂商的 ROM 会把这个功能删掉,你得自己加回去。我曾经在某个项目里找了半天没找到这个配置,最后发现是厂商把整个 NetworkSpeedController 类都移除了……

注意:修改 SystemUI 时,一定要同步更新 SystemUI/res/values/strings.xml 中的字符串资源,否则可能出现英文和中文混排的情况。

默认应用设置:让用户「无脑」使用

定制 ROM 的一大目标就是让用户开机后直接能用,不需要手动设置默认应用。比如:默认浏览器、默认短信、默认桌面、默认拨号器。

这些默认值定义在 frameworks/base/core/res/res/values/config.xml 中:

<string-array name="config_defaultLauncher">
    <item>com.android.launcher3/com.android.launcher3.Launcher</item>
</string-array>

<string-array name="config_defaultBrowser">
    <item>com.android.browser/com.android.browser.BrowserActivity</item>
</string-array>

如果你想把自己的 Launcher 设为默认,就把包名和 Activity 路径填进去。注意,这里填的是 ComponentName 格式,不是单纯的包名。

我遇到过一个问题:明明改了配置,但开机后还是弹出选择对话框。后来发现是 PackageManager 在第一次启动时会扫描所有应用,如果发现多个 Launcher,就会让用户选。解决办法是在 DevicePolicyManager 中设置 setApplicationHidden 把其他 Launcher 隐藏掉,或者干脆只保留一个。

核心思路:默认应用设置的本质是「减少用户选择」。你替用户选好了,他们就不用烦了。但前提是你选的这个应用确实好用,否则用户会骂你。

开机向导定制:让第一次开机变得优雅

开机向导(SetupWizard)是用户拿到设备后看到的第一个界面。AOSP 自带的 SetupWizard 功能很基础:选语言、连 WiFi、登录账号、设置指纹。但定制 ROM 往往需要加入自己的逻辑,比如:

  • 显示隐私协议和用户条款
  • 引导用户注册账号
  • 选择设备使用场景(家庭/办公/教育)
  • 跳过某些步骤(比如不强制登录)

SetupWizard 的源码在 packages/apps/Settings 中,但它的入口是一个单独的 SetupWizardActivity。你可以通过修改 AndroidManifest.xml 中的 intent-filter 来控制它是否作为开机向导启动。

举个例子,你想在开机向导中加入一个「选择主题」的页面:

// ThemeSelectionFragment.java
public class ThemeSelectionFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_theme_selection, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        Button btnLight = view.findViewById(R.id.btn_light);
        Button btnDark = view.findViewById(R.id.btn_dark);
        btnLight.setOnClickListener(v -> {
            // 保存主题设置
            Settings.Global.putInt(getContext().getContentResolver(),
                    "theme_mode", 0);
            // 跳转到下一步
            ((SetupWizardActivity) getActivity()).onNext();
        });
        btnDark.setOnClickListener(v -> {
            Settings.Global.putInt(getContext().getContentResolver(),
                    "theme_mode", 1);
            ((SetupWizardActivity) getActivity()).onNext();
        });
    }
}

然后把这个 Fragment 添加到 SetupWizardActivity 的页面序列中。注意,开机向导的页面跳转逻辑通常是用 ViewPagerFragmentPagerAdapter 实现的,你只需要在 getItem() 方法里返回新的 Fragment 即可。

避坑指南:我曾经在开机向导里加了一个「强制登录」的步骤,结果测试时发现,如果用户不连 WiFi 就无法登录,导致卡在向导页面出不去。后来我加了一个「跳过」按钮,并设置 30 秒后自动跳过。嗯,用户体验很重要。

知识体系总览

下面这张图帮你理清 Launcher、SystemUI、SetupWizard 三者的关系,以及它们在 AOSP 中的位置:

定制 ROM 三大核心模块 Launcher 桌面网格 / 图标包 Dock 栏 / 手势动画 默认桌面设置 SystemUI 状态栏 / 快捷开关 锁屏 / 音量面板 通知栏定制 SetupWizard 语言 / WiFi / 账号 隐私协议 / 场景选择 主题 / 指纹设置 交互联动 状态同步 公共依赖层 SettingsProvider / PackageManager / WindowManager 修改路径:packages/apps/Launcher3 / packages/apps/SystemUI / packages/apps/Settings 编译命令:make Launcher3 / make SystemUI / make Settings 注:三个模块共享 SettingsProvider 中的全局配置

总结一下

定制 Launcher、SystemUI 和开机向导,是嵌入式 Android 系统开发中最常见的三个任务。它们分别对应了用户的「桌面体验」、「系统交互」和「首次启动体验」。说白了,你把这三点做好了,用户就会觉得这个 ROM「很用心」。

我个人建议你从 Launcher 开始练手,因为它相对独立,改坏了也不影响系统稳定性。然后逐步挑战 SystemUI 和 SetupWizard。记住,每次修改后都要做完整的回归测试,尤其是开机向导——它出问题,用户连系统都进不去。

核心原则:定制不是炫技,而是让用户用得更舒服。少即是多,稳即是快。

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