资讯中心

Android 14 SystemUI 定制实战:锁屏、状态栏与QS面板改造指南

📅 2026/9/27 23:13:05
Android 14 SystemUI 定制实战:锁屏、状态栏与QS面板改造指南
Android 14 的 SystemUI 是整套系统里最“显眼”的模块用户每天点亮屏幕第一眼看到的就是它下拉一下、划一下、点一下全是 SystemUI 在响应。也正因为如此它成了定制需求最集中的地方锁屏要改、状态栏要改、快速设置面板要改改完之后还得保证不崩、不卡、不闪。我最近刚在一个 RK3576 的 Android 14 板子上完整走了一遍 SystemUI 定制从锁屏布局到状态栏图标再到 QS 面板的磁贴重排中间踩了不少坑也积累了一些比较实用的经验。这篇文章就把整个改造过程拆开来讲重点放在“为什么这么改”和“改完怎么验证”上而不是只丢一堆代码。适合有一定 Android 系统开发基础、正在做 ROM 定制或设备定制的朋友参考新手也能跟着思路理解 SystemUI 的整体结构。1. 先搞清楚 Android 14 SystemUI 的模块边界动手改之前如果连 SystemUI 里哪个东西归哪个包管都没弄清楚后面基本就是盲人摸象。Android 14 的 SystemUI 相比早期版本模块化程度更高了很多功能被拆成了独立的库和模块不再是以前那种一个大包全塞进去的结构。1.1 SystemUI 的核心组成与代码分布在 AOSP 源码里SystemUI 主要位于frameworks/base/packages/SystemUI。但到了 Android 14你会发现很多实际逻辑已经不在这个目录下了而是被挪到了frameworks/base/packages/SystemUI/shared以及一些独立的 module 里。比如锁屏相关的Keyguard逻辑核心部分在com.android.systemui.keyguard包下但锁屏的界面渲染又和NotificationShade、StatusBar有千丝万缕的联系。我一般会把 SystemUI 分成这么几块来看状态栏StatusBar顶部那条显示时间、电量、信号、通知图标。核心类包括StatusBar、PhoneStatusBarView、CollapsedStatusBarFragment。通知栏与快速设置NotificationShade / QS下拉出来的那一大块上半部分是 QS 磁贴下半部分是通知列表。核心类有NotificationShadeWindowView、NotificationPanelViewController、QSPanelController。锁屏Keyguard包括锁屏界面、密码输入、指纹/人脸提示等。核心类有KeyguardViewMediator、KeyguardSecurityContainer、KeyguardClockSwitch。导航栏NavigationBar底部三大金刚或手势条。Android 14 上手势导航是主流但很多定制设备仍然需要三键导航。这里有个容易混淆的点状态栏和锁屏并不是完全独立的。锁屏界面上的状态栏其实是同一个 StatusBar 实例只是处于不同的状态KEYGUARD状态。所以改状态栏的时候一定要同时看锁屏下的表现否则很容易出现“解锁后正常锁屏上错位”的问题。1.2 定制前必须确认的编译与调试环境在 RK3576 这类板子上做定制和纯 AOSP 模拟器不太一样。RK3576 是瑞芯微的芯片Android 14 的 BSP 通常由芯片原厂或方案商提供SystemUI 的代码可能已经被改过一轮了。所以第一步不是急着改代码而是先确认你手上的代码基线。我一般会做这几件事确认 SystemUI 的编译产物路径在out/target/product/device/system/system_ext/priv-app/SystemUI/下找到SystemUI.apk确认它是不是从你修改的源码编译出来的。确认 overlay 机制Android 14 上很多资源是通过 RRORuntime Resource Overlay覆盖的先检查device/vendor/device/overlay/下有没有已经存在的 SystemUI overlay避免你改了半天被 overlay 覆盖掉。打开调试开关在Settings System Developer options里打开“显示布局边界”和“GPU 渲染模式分析”这两个对后面调布局非常有用。提示RK3576 的 Android 14 BSP 里SystemUI 有时会被预编译成 odex 格式直接 push APK 可能不生效。建议在源码里改完后整编make SystemUI然后重新烧录 system 分区或者至少确保关闭了 dex2oat 的预编译优化。1.3 为什么不能直接改 APK 而要改源码有些人图省事直接反编译 SystemUI.apk 改 smali 或者资源然后重新打包。这种做法在小改动上偶尔能成但在 Android 14 上风险极高。原因有几个一是 Android 14 对系统应用的签名校验更严格重新打包后签名不一致可能导致 SystemUI 无法启动二是 SystemUI 和 framework 之间有大量隐藏 API 调用反编译后很难保证兼容三是 odex/vdex 的存在让直接替换 APK 变得不可靠。所以我的建议很明确只要你能拿到源码就老老实实改源码重新编译。反编译只适合做逆向分析不适合做正式定制。2. 锁屏改造从布局到交互的完整链路锁屏是用户接触最多的界面之一定制需求也最五花八门。有人要改时钟样式有人要加自定义快捷方式有人要去掉某个提示。Android 14 的锁屏结构比之前更复杂因为引入了更多的可配置项和新的时钟布局。2.1 锁屏界面的视图层级拆解要改锁屏先得知道锁屏界面是怎么拼出来的。Android 14 的锁屏主要视图层级大致是这样的KeyguardViewMediator负责整体调度决定什么时候显示锁屏、什么时候隐藏。KeyguardSecurityContainer是锁屏的安全区域容器里面装着密码/图案/指纹的输入界面。KeyguardClockSwitch负责时钟区域的切换Android 14 支持多种时钟样式数字、模拟、自定义。NotificationShadeWindowView是整个下拉窗口的根视图锁屏和通知栏共用这个根视图。这里有个关键点锁屏的时钟区域和通知区域是分开管理的。时钟在KeyguardClockSwitch里通知在NotificationStackScrollLayout里。如果你想改时钟位置改的是KeyguardClockSwitch的布局参数如果你想改通知在锁屏上的显示方式改的是NotificationStackScrollLayout在锁屏状态下的配置。我实际改的时候遇到过一个典型问题把时钟往下移之后通知列表和时钟重叠了。原因是时钟区域的父容器高度没有同步调整导致通知列表的起始位置还是按原来的算。解决办法是同时修改KeyguardClockSwitch的layout_height和NotificationStackScrollLayout的topMargin让两者保持联动。2.2 自定义锁屏时钟样式的实操步骤Android 14 原生支持几种时钟样式但如果你想加一个完全自定义的样式比如带天气信息的时钟就需要自己扩展。下面是我实际操作的步骤在KeyguardClockSwitch的布局文件里增加自定义时钟的 ViewStub。找到keyguard_clock_switch.xml在里面加一个ViewStub指向你自己的布局文件。创建自定义时钟的 Controller。在com.android.systemui.keyguard包下新建一个类继承KeyguardClockController或者实现相应的接口负责更新时钟显示。在KeyguardClockSwitchController里注册你的 Controller。根据当前配置决定是否加载自定义时钟。处理配置变更。锁屏时钟在横竖屏切换、语言切换时都需要重新布局确保你的自定义 View 能正确响应onConfigurationChanged。这里有个坑Android 14 的锁屏时钟样式是可以通过系统设置切换的如果你加的自定义样式没有在设置里注册用户切换样式时你的时钟就会消失。所以要么在设置里加一个入口要么把你的样式设为默认并禁用其他样式。2.3 锁屏快捷方式的添加与移除锁屏底部的快捷方式默认是电话和相机也是定制高频点。Android 14 上这两个快捷方式由KeyguardBottomAreaView管理。要改的话主要涉及两个地方快捷方式的图标和点击事件在KeyguardBottomAreaView里找到mLeftIconView和mRightIconView替换它们的图标资源和OnClickListener。快捷方式的可用性判断有些设备没有相机或者电话功能被禁用这时候需要动态隐藏对应的快捷方式。Android 14 里通过KeyguardBottomAreaView.updateBottomArea()来判断你可以在这里加自己的逻辑。我踩过的一个坑是直接替换图标资源后图标大小不对。原因是KeyguardBottomAreaView对图标有固定的尺寸约束你换的图标如果原始尺寸差太多就会被拉伸或压缩。解决办法是在 drawable 里用inset或者scaleType做适配而不是直接换一张图。2.4 锁屏与 AOD息屏显示的联动注意事项很多定制设备会同时改锁屏和 AOD。Android 14 上AOD 和锁屏共享一部分视图但又有独立的显示逻辑。如果你改了锁屏时钟AOD 上的时钟可能不会自动跟着变因为 AOD 走的是DozingClockView而不是KeyguardClockSwitch。所以改锁屏时钟的时候一定要同步检查 AOD 的时钟显示。我一般的做法是把时钟的绘制逻辑抽成一个独立的工具类锁屏和 AOD 都调用这个工具类这样改一处就能两边生效。虽然前期多花点时间但后期维护省事很多。3. 状态栏定制图标、布局与交互的细节处理状态栏看起来简单就是顶部一条但里面的细节非常多。Android 14 的状态栏在布局上更加灵活支持动态隐藏、图标分组、通知图标数量限制等。定制的时候稍不注意就会出现图标重叠、间距不对、锁屏下错位等问题。3.1 状态栏布局文件的关键节点状态栏的布局主要在status_bar.xml和phone_status_bar.xml里。Android 14 上状态栏的根布局是PhoneStatusBarView里面包含三个主要区域左侧区域通常显示通知图标、运营商信息。中间区域显示时钟。右侧区域显示系统图标信号、WiFi、电量等。这三个区域在布局上是用LinearLayout或者ConstraintLayout组织的。Android 14 默认用的是ConstraintLayout因为要支持不同屏幕尺寸和刘海屏的适配。改布局的时候我建议先搞清楚每个区域的id然后在CollapsedStatusBarFragment里找到对应的findViewById和初始化逻辑。比如你想把时钟从中间移到左边改布局文件只是第一步还得改CollapsedStatusBarFragment里对时钟位置的判断逻辑否则代码里还是会按中间位置来算。3.2 系统图标显示与隐藏的逻辑控制状态栏右侧的系统图标信号、WiFi、电量、蓝牙等是由StatusBarIconController统一管理的。Android 14 上图标的显示和隐藏通过StatusBarIconController.addIcon()和removeIcon()来控制。如果你想定制某个图标的显示条件比如“只在 WiFi 连接时显示 WiFi 图标否则隐藏”需要找到对应的IconManager或者StatusBarSignalPolicy。以 WiFi 为例逻辑在StatusBarSignalPolicy里它会根据WifiManager的回调来更新图标状态。这里有个实际经验不要直接在布局里把某个图标 View 设为GONE。因为状态栏的图标是动态添加和移除的你在布局里隐藏了代码里添加的时候还是会把它显示出来。正确的做法是修改StatusBarIconController里的过滤逻辑或者在IconManager里加判断。3.3 状态栏时钟格式与显示位置调整时钟是状态栏上最常被定制的元素。Android 14 上时钟的显示由Clock类控制它支持多种格式12 小时、24 小时、带秒、不带秒。如果你想改时钟的显示格式可以修改Clock里的getSmallTime()方法。但要注意时钟的显示位置和格式是两回事。位置由布局决定格式由Clock类决定。我见过有人改了Clock的格式但时钟位置没变就以为没生效其实是位置本来就没动。如果你想把时钟放到状态栏左侧除了改布局还要注意左侧区域原本是放通知图标的。时钟移过去之后通知图标可能会被挤掉。这时候需要调整通知图标的显示策略比如限制通知图标的数量或者把通知图标改成只显示一个“有通知”的指示点。3.4 状态栏在锁屏与解锁状态下的差异处理状态栏在锁屏和解锁状态下的表现是不一样的。锁屏状态下状态栏通常会隐藏一些敏感图标比如通知图标只显示时间和系统图标。这个逻辑在StatusBar的updateStatusBarState()里处理。如果你定制了状态栏一定要测试锁屏下的表现。我遇到过一个典型问题解锁状态下状态栏布局正常锁屏状态下时钟和电量图标重叠了。原因是锁屏状态下状态栏的可用宽度计算方式不同导致布局参数失效。解决办法是在updateStatusBarState()里根据当前状态重新设置布局参数而不是只在初始化时设置一次。4. 快速设置面板磁贴重排与自定义磁贴开发快速设置面板QS Panel是 SystemUI 里交互最复杂的部分之一。Android 14 上QS 面板支持分页、磁贴拖拽、自定义磁贴等。定制需求通常集中在磁贴的排列顺序、默认显示的磁贴、以及添加自定义磁贴。4.1 QS 面板的默认磁贴配置Android 14 的默认磁贴配置在config.xml里通过config_defaultQuickSettingsTiles数组定义。这个数组决定了首次开机时 QS 面板上显示哪些磁贴以及它们的顺序。如果你想改默认磁贴直接改这个数组就行。但要注意这个配置只在首次开机时生效。如果设备已经开过机QS 面板的磁贴配置已经保存在数据库里了改config.xml不会影响已保存的配置。测试的时候要么恢复出厂设置要么手动清除Settings.Secure里的sysui_qs_tiles字段。我一般的做法是在开发阶段每次改完默认磁贴配置后用adb shell settings delete secure sysui_qs_tiles清除已保存的配置然后重启 SystemUI这样就能看到新的默认配置了。4.2 自定义 QS 磁贴的完整开发流程添加一个自定义磁贴需要实现QSTile和QSTileView。下面是我实际操作的完整流程创建 Tile 类继承QSTileImpl实现newTile()、handleClick()、handleUpdateState()等方法。创建 TileView 类继承QSTileViewImpl定义磁贴的布局和交互。注册 Tile在QSFactoryImpl里注册你的 Tile这样 QS 面板才能识别它。添加资源在config.xml里添加你的 Tile 的spec名称并确保它在默认磁贴列表里。这里有个关键点Android 14 的 QS 磁贴支持两种模式单目标和双目标。单目标就是点一下切换状态双目标是有个展开箭头点箭头进入详细设置。如果你的磁贴需要双目标实现方式会复杂一些需要额外处理SecondaryTarget。我踩过的一个坑是自定义磁贴的图标没有着色。Android 14 的 QS 磁贴图标默认会跟随系统主题着色如果你的图标是彩色的可能会被强制改成单色。解决办法是在 TileView 里设置setIconTint为Color.TRANSPARENT或者使用Icon的setTint方法手动控制。4.3 磁贴分页与拖拽逻辑的定制Android 14 的 QS 面板支持分页默认是两页。如果你想改分页数量或者禁用分页需要修改QSPanelController里的mPages相关逻辑。拖拽逻辑在QSPanelController和QSTileRevealController里。默认情况下用户可以把磁贴从第二页拖到第一页或者从第一页拖到第二页。如果你想限制某些磁贴不能被拖拽需要在QSTileRevealController里加过滤条件。这里有个实际经验改分页逻辑的时候一定要同时改QSPanelController和QSTileRevealController。只改一个地方会出现“磁贴能拖过去但显示不出来”或者“显示出来了但拖不回来”的问题。4.4 QS 面板展开与收起的动画调优QS 面板的展开和收起动画是由NotificationPanelViewController控制的。Android 14 上动画的时长和曲线在config.xml里有默认值比如config_quickSettingsPanelExpandDuration。如果你觉得默认动画太慢或太快可以改这些配置值。但要注意动画时长改得太短会导致视觉上的卡顿感因为 SystemUI 的渲染和动画是分开的动画太快但渲染没跟上就会看起来一卡一卡的。我一般建议动画时长不要低于 200ms否则在低端设备上体验会很差。5. 定制后的验证与常见问题排查改完 SystemUI 只是第一步验证和排查才是真正花时间的地方。SystemUI 的问题往往不是崩溃而是“看起来不对”——图标错位、动画卡顿、状态不同步。这些问题不会在 logcat 里报错只能靠观察和对比。5.1 编译与烧录后的快速验证清单每次编译完 SystemUI 并烧录后我会按这个清单快速过一遍检查项预期表现常见问题状态栏显示时间、电量、信号正常图标重叠、缺失锁屏显示时钟、快捷方式正常时钟错位、快捷方式不显示QS 面板磁贴排列正确、可拖拽磁贴丢失、拖拽失效锁屏到解锁状态栏过渡自然状态栏闪烁、图标跳变AOD 显示时钟与锁屏一致AOD 时钟不更新这个清单看起来简单但每次改完都过一遍能省掉很多后期调试的时间。5.2 状态栏图标错位的排查思路状态栏图标错位是最常见的问题之一。排查的时候我一般按这个顺序来确认布局文件是否被 overlay 覆盖检查device/vendor/device/overlay/下有没有 SystemUI 的 overlay如果有你的修改可能被覆盖了。确认图标容器的宽度计算状态栏右侧的图标容器通常是LinearLayout如果图标数量变化宽度会动态调整。检查StatusBarIconController里的mIconGroups更新逻辑。确认锁屏状态下的布局参数锁屏状态下状态栏的可用宽度可能不同检查updateStatusBarState()里有没有重新设置布局参数。我遇到过一次图标错位排查了半天发现是 overlay 里有一个旧的status_bar.xml覆盖了我的修改。所以改之前先确认 overlay 情况能省很多时间。5.3 SystemUI 冻结或崩溃后的恢复方法有时候改错了会导致 SystemUI 崩溃或者被系统冻结表现就是状态栏和导航栏都消失了。这时候别慌恢复方法有几种通过 adb 重启 SystemUIadb shell killall com.android.systemui系统会自动重启 SystemUI。通过 adb 清除 SystemUI 数据adb shell pm clear com.android.systemui这会清除 SystemUI 的缓存和配置恢复到默认状态。如果 adb 也连不上进入 recovery 模式重新烧录 system 分区。我一般会在改 SystemUI 之前先用adb shell pm path com.android.systemui确认 APK 路径并备份一份原始的 APK。这样即使改崩了也能快速恢复。5.4 媒体声音与 HDMI 相关的 SystemUI 联动问题在 RK3576 这类板子上插上 HDMI 后媒体声音消失是一个比较常见的问题虽然根因通常在音频路由但 SystemUI 的状态栏图标显示可能会受到影响。比如 HDMI 插入后音频输出设备切换状态栏上的音量图标可能不会及时更新。如果你遇到类似问题可以先确认音频路由是否正常然后再检查 SystemUI 里的音量图标更新逻辑。Android 14 上音量图标由StatusBarIconController管理音频设备切换时会触发AudioManager的回调SystemUI 需要监听这个回调并更新图标。如果 SystemUI 没有正确监听图标就会显示错误的状态。注意这类问题往往不是 SystemUI 单方面的问题而是 SystemUI 和音频服务之间的联动问题。排查的时候要同时看 audio 和 systemui 的 log。6. 一些实际项目中的经验与建议做了几个 SystemUI 定制项目之后我总结了一些比较实用的经验有些是踩坑踩出来的有些是优化过程中发现的。6.1 尽量用 overlay 而不是直接改源码虽然前面说了改源码更可靠但对于一些纯资源的修改比如颜色、尺寸、字符串用 RRO overlay 是更好的选择。overlay 的好处是不用重新编译 SystemUI而且可以针对不同设备做不同的覆盖维护起来更灵活。我一般的策略是逻辑改动改源码资源改动用 overlay。这样既能保证功能正确又能减少编译时间。6.2 保持与原生行为的一致性定制的时候很容易改着改着就偏离了原生行为导致一些隐藏功能失效。比如你改了状态栏的布局可能会影响通知的展开动画你改了锁屏的时钟可能会影响 AOD 的显示。所以我的建议是每次改动都尽量小步走改完一个点就验证一个点不要一次性改一大堆然后一起验证。这样出问题的时候排查范围小定位快。6.3 关注 Android 14 的新特性对定制的影响Android 14 在 SystemUI 上引入了一些新特性比如更灵活的锁屏时钟、QS 面板的分页优化、状态栏图标的动态分组等。这些新特性在定制的时候既是机会也是坑。机会是你可以利用这些新特性做出更好的效果坑是这些新特性的实现方式可能和你的定制逻辑冲突。比如 Android 14 的锁屏时钟支持用户自定义样式如果你加了一个自定义时钟但没有适配这个机制用户切换样式时你的时钟就会消失。所以定制之前先花点时间了解 Android 14 在 SystemUI 上的新变化能避免很多返工。6.4 调试工具与日志的合理使用SystemUI 的调试光靠看界面是不够的还得结合日志。我常用的几个命令# 查看 SystemUI 的日志 adb logcat -s SystemUI # 查看状态栏图标的更新日志 adb logcat -s StatusBarIconController # 查看 QS 面板的日志 adb logcat -s QSPanelController # dump SystemUI 的状态 adb shell dumpsys systemuidumpsys systemui特别有用它会输出当前 SystemUI 的详细状态包括状态栏图标、QS 磁贴、锁屏状态等。排查问题的时候先 dump 一下往往能快速定位到问题所在。6.5 版本管理与回滚策略SystemUI 的定制往往不是一次性的而是随着需求变化不断调整。所以版本管理很重要。我一般会用 git 管理 SystemUI 的修改每次改动都提交一次并写清楚改了什么、为什么改。这样出问题的时候可以快速回滚到上一个稳定版本。另外建议在每次重大改动之前先打一个 tag标记为稳定版本。这样即使改崩了也能快速恢复到稳定状态不至于影响整体进度。最后再分享一个小技巧如果你在改 SystemUI 的时候不确定某个效果是不是自己改出来的可以先把改动还原编译一个原生版本对比一下。很多时候问题不是你的改动引起的而是原生就有的行为只是你之前没注意到。这个对比法帮我省了不少瞎折腾的时间。

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案