MIUI还挺好用的,除了广告比较多,其他都很适合国内的用户使用。但是有一个功能MIUI死活不肯加进去,就是状态栏的时钟死活不加入显秒的设置。当然,目前很多第三方固件支持显秒,或者支持安装Xposed之后安装显秒模块。然而,迁移到第三方固件的一个问题就是数据比较难保持一致,而且可能不太稳定。安装Xposed更不用看了,MIUI原生跟它有仇,而且安装Xposed之后必然导致系统卡顿、耗电增加。所以最好的方法就是使用Magisk模块Systemless地增加时钟显秒。
此教程以小米6X稳定版为例,制作Magisk模块。要注意的是,不同设备不同系统之间模块不通用,也就是说,我制作了MI6X的这样一个模块,MI8是不能用的。我在MI6X的稳定版做了这个模块,MI6X的开发板也不能用。每部设备的每个版本的系统都需要单独制作,这也是为什么我选择发制作教程而不是直接发模块。
手机与设备使用数据线连接,并且手机已经开启USB调试。
使用adb把相关文件和目录拉到工作目录:
/system/framework/arm64
目录 adb pull /system/framework/arm64
这时候工作目录下面应该有一个arm64
的文件夹了。
/system/priv-app/MiuiSystemUI/oat/arm64
目录,也是放到arm64
文件夹: adb pull /system/priv-app/MiuiSystemUI/oat/arm64
这时候arm64
文件夹应该多了两个文件。
adb pull /system/priv-app/MiuiSystemUI/MiuiSystemUI.apk
adb pull /system/framework/framework-ext-res/framework-ext-res.apk
adb pull /system/framework/framework-res.apk
adb pull /system/app/miui/miui.apk
adb pull /system/app/miuisystem/miuisystem.apk
拉完文件之后,进入arm64
目录,把MiuiSystemUI
进行deodex化:
arm64
目录 cd arm64
baksmali
进行deodex。(假设baksmali文件名为baksmali.jar
,并且在上一一级目录,也就是工作目录上) java -jar ../baksmali.jar de MiuiSystemUI.odex -o MiuiSystemUI
这样之后会生成MiuiSystemUI
目录。
然后转成dex文件:
java -jar ../smali.jar ass MiuiSystemUI -o ../classes.dex
这样之后在工作目录就生成了一个classes.dex
文件了。回到工作目录:
cd ..
用解压软件打开MiuiSystemUI.apk
,把classes.dex
放进去。
使用apktool
反汇编MiuiSystemUI.apk
。
假设apktool
文件名为apktool.jar
并且在当前目录。
java -jar apktool.jar if framework-res.apk
java -jar apktool.jar if framework-ext-res.apk
java -jar apktool.jar if miui.apk
java -jar apktool.jar if miuisystem.apk
java -jar apktool.jar d MiuiSystemUI.apk -o MiuiSystemUI
这时候生成了一个MiuiSystemUI
目录。
修复pip_dismiss_scrim.9.png
文件。
这个文件是Android O里面的一个通有问题,会导致apktool
不能重新封包。提示错误:
W: ERROR: 9-patch image pip_dismiss_scrim.9.png malformed.
W: No marked region found along edge.
W: Found along left edge.
W: ERROR: Failure processing PNG image pip_dismiss_scrim.9.png
修复res
的目录结构
由于apktool
的一些问题,这时候解包出来的res
目录结构跟原apk不一样。比如:原来用解压软件打开MiuiSystemUI.apk
里面有res/drawable
, res/drawable-v21
和res/drawable-v23
目录。但是解包出来之后一个res/drawable
目录了,后面两个目录的文件都跑到第一个文件里面了。这时候我们需要修复目录结构。主要修复分为以下几种:
drawable-ldrtl-xxhdpi-v4
变成了drawable-ldrtl-xxhdpi
。这需要在对应目录后面加上版本号。drawable-v21
和drawable-v23
目录合并到drawable
里面了。这时候需要创建drawable-v21
和drawable-v23
两个目录,并对照着原apk
文件,把跑到drawable
里面的文件剪贴回drawable-v21
和drawable-v23
里面。qs_tile_expand_indicator.png.png
文件(不知道是不是小米工程师改错名了),在解包之后变成了qs_tile_expand_indicator.png
,需要把.png
加回去。修改完成之后,res
里面除了values
开头的目录,其余均和原apk
文件里面的目录名、目录里面文件一致。
mkdir color-v11 color-v23 drawable-v21 drawable-v23 layout-v11 layout-v21 layout-v26
mv drawable-440dpi drawable-440dpi-v4
mv drawable-hdpi drawable-hdpi-v4
mv drawable-land-440dpi drawable-land-440dpi-v4
mv drawable-land-xxhdpi drawable-land-xxhdpi-v4
mv drawable-ldrtl-xxhdpi drawable-ldrtl-xxhdpi-v4
mv drawable-mdpi drawable-mdpi-v4
mv drawable-nodpi drawable-nodpi-v4
mv drawable-xhdpi drawable-xhdpi-v4
mv drawable-xxhdpi drawable-xxhdpi-v4
mv drawable-xxxhdpi drawable-xxxhdpi-v4
mv layout-television layout-television-v8
mv layout-watch layout-watch-v8
mv mipmap-hdpi mipmap-hdpi-v4
mv mipmap-mdpi mipmap-mdpi-v4
mv mipmap-xhdpi mipmap-xhdpi-v4
mv raw-440dpi raw-440dpi-v4
mv raw-xxhdpi raw-xxhdpi-v4
mv color/abc_background_cache_hint_selector_material_dark.xml color/abc_background_cache_hint_selector_material_light.xml color-v11
mv color/abc_btn_colored_borderless_text_material.xml color/abc_btn_colored_text_material.xml color/abc_color_highlight_material.xml color/abc_tint_btn_checkable.xml color/abc_tint_default.xml color/abc_tint_edittext.xml color/abc_tint_seek_thumb.xml color/abc_tint_spinner.xml color/abc_tint_switch_track.xml color-v23
mv drawable/abc_action_bar_item_background_material.xml drawable/abc_btn_colored_material.xml drawable/abc_edit_text_material.xml drawable/preference_list_divider_material.xml drawable-v21
mv drawable/abc_control_background_material.xml drawable-v23
mv layout/preference.xml layout/preference_dropdown.xml layout-v11
mv layout/preference_category_material.xml layout/preference_dropdown_material.xml layout/preference_information_material.xml layout/preference_material.xml layout-v21
mv layout/abc_screen_toolbar.xml layout-v26
mv drawable-440dpi-v4/qs_tile_expand_indicator.png drawable-440dpi-v4/qs_tile_expand_indicator.png.png
修改res/layout/status_bar.xml
文件。
用文本编辑器打开res/layout/status_bar.xml
,搜索关键字com.android.systemui.statusbar.policy.Clock
,然后把:
<com.android.systemui.statusbar.policy.Clock android:textAppearance="@style/TextAppearance.StatusBar.Clock" android:gravity="center_vertical" android:id="@id/clock" android:layout_width="wrap_content" android:layout_height="fill_parent" android:singleLine="true" android:paddingStart="@dimen/status_bar_clock_starting_padding" android:paddingEnd="@dimen/status_bar_clock_end_padding" />
替换为:
<com.android.systemui.statusbar.policy.Clock android:textAppearance="@style/TextAppearance.StatusBar.Clock" android:gravity="center_vertical" android:id="@id/clock" android:layout_width="0.0dip" android:layout_height="fill_parent" android:singleLine="true" android:paddingStart="@dimen/status_bar_clock_starting_padding" android:paddingEnd="@dimen/status_bar_clock_end_padding" />
<com.android.systemui.statusbar.policy.AdvanceClock android:textAppearance="@style/TextAppearance.StatusBar.Clock" android:gravity="center" android:layout_gravity="center" android:id="@id/advance_clock" android:paddingBottom="@dimen/statusbar_text_bottom_padding" android:layout_width="wrap_content" android:layout_height="fill_parent" android:singleLine="true" android:format12Hour="ahh:mm:ss" android:format24Hour="HH:mm:ss" />
保存文件。
修改res/values/ids.xml
文件
用文本编辑器打开res/values/ids.xml
文件,定位到倒数第二行,在其后添加一行(也就是说在</resources>
前添加一行):
<item type="id" name="advance_clock">false</item>
修改res/values/public.xml
文件
用文本编辑器打开res/values/public.xml
,定位到以<public type="id"
开头的最后一行。
在我这里是xml <public type="id" name="zen_radio_buttons_content" id="0x7f0a0323" />
留意这里id
后引号内的内容0x7f0a0323
,加一就是0x7f0a0324
,记录下来。
在该行后添加一行:
<public type="id" name="advance_clock" id="0x7f0a0324" />
留意这里id
后的印号内的内容就是上一行id
内容加一。
搜索status_bar_textColor_darkmode
,得到:
<public type="color" name="status_bar_textColor_darkmode" id="0x7f060175" />
把id
后引号内容0x7f060175
记录下来。
搜索status_bar_textColor
,得到:
<public type="color" name="status_bar_textColor" id="0x7f060174" />
把id
后引号内容0x7f060174
记录下来。
搜索clock
,得到:
<public type="id" name="clock" id="0x7f0a0085" />
把id
后引号内容0x7f0a0085
记录下来。
修改smali/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.smali
文件。
用文本编辑器打开smali/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.smali
。搜索刚才搜clock
时候得到的id
,我这里是0x7f0a0085
,得到:
const v3, 0x7f0a0085
在该行的上一行,添加:
const v3, 0x7f0a0324
invoke-virtual {v2, v3}, Lcom/android/systemui/statusbar/phone/PhoneStatusBarView;->findViewById(I)Landroid/view/View;
move-result-object v2
check-cast v2, Lcom/android/systemui/statusbar/policy/AdvanceClock;
iput-object v2, p0, Lcom/android/systemui/statusbar/phone/CollapsedStatusBarFragment;->mStatusAdvanceClock:Lcom/android/systemui/statusbar/policy/AdvanceClock;
iget-object v2, p0, Lcom/android/systemui/statusbar/phone/CollapsedStatusBarFragment;->mStatusBar:Lcom/android/systemui/statusbar/phone/PhoneStatusBarView;
其中第一行的const v3, 0x7f0a0324
中的0x7f0a0324
就是记住的advance_clock
的id
(那个加一后的id)。注意替换。
搜索.field private mSignalClusterView:Lcom/android/systemui/statusbar/SignalClusterView;
,在该行后添加一行:
.field private mStatusAdvanceClock:Lcom/android/systemui/statusbar/policy/AdvanceClock;
注意前面有一个点。
搜索addDarkReceiver
,在其中一行后加上:
const-class v2, Lcom/android/systemui/statusbar/policy/DarkIconDispatcher;
invoke-static {v2}, Lcom/android/systemui/Dependency;->get(Ljava/lang/Class;)Ljava/lang/Object;
move-result-object v2
check-cast v2, Lcom/android/systemui/statusbar/policy/DarkIconDispatcher;
iget-object v3, p0, Lcom/android/systemui/statusbar/phone/CollapsedStatusBarFragment;->mStatusAdvanceClock:Lcom/android/systemui/statusbar/policy/AdvanceClock;
invoke-interface {v2, v3}, Lcom/android/systemui/statusbar/policy/DarkIconDispatcher;->addDarkReceiver(Lcom/android/systemui/statusbar/policy/DarkIconDispatcher$DarkReceiver;)V
搜索removeDarkReceiver
在其中一行后添加:
const-class v0, Lcom/android/systemui/statusbar/policy/DarkIconDispatcher;
invoke-static {v0}, Lcom/android/systemui/Dependency;->get(Ljava/lang/Class;)Ljava/lang/Object;
move-result-object v0
check-cast v0, Lcom/android/systemui/statusbar/policy/DarkIconDispatcher;
iget-object v1, p0, Lcom/android/systemui/statusbar/phone/CollapsedStatusBarFragment;->mStatusAdvanceClock:Lcom/android/systemui/statusbar/policy/AdvanceClock;
invoke-interface {v0, v1}, Lcom/android/systemui/statusbar/policy/DarkIconDispatcher;->removeDarkReceiver(Lcom/android/systemui/statusbar/policy/DarkIconDispatcher$DarkReceiver;)V
然后保存文件。
添加smali/com/android/systemui/statusbar/policy/AdvanceClock.smali
文件。
创建smali/com/android/systemui/statusbar/policy/AdvanceClock.smali
文件。然后用文本编辑器打开它。内容为:
.class public Lcom/android/systemui/statusbar/policy/AdvanceClock;
.super Landroid/widget/TextClock;
.source "AdvanceClock.java"
# interfaces
.implements Lcom/android/systemui/statusbar/policy/DarkIconDispatcher$DarkReceiver;
# direct methods
.method public constructor <init>(Landroid/content/Context;)V
.locals 0
.param p1, "context" # Landroid/content/Context;
.prologue
.line 10
invoke-direct {p0, p1}, Landroid/widget/TextClock;-><init>(Landroid/content/Context;)V
.line 11
return-void
.end method
.method public constructor <init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
.locals 0
.param p1, "context" # Landroid/content/Context;
.param p2, "attrs" # Landroid/util/AttributeSet;
.prologue
.line 14
invoke-direct {p0, p1, p2}, Landroid/widget/TextClock;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
.line 15
return-void
.end method
.method public constructor <init>(Landroid/content/Context;Landroid/util/AttributeSet;I)V
.locals 0
.param p1, "context" # Landroid/content/Context;
.param p2, "attrs" # Landroid/util/AttributeSet;
.param p3, "defStyleAttr" # I
.prologue
.line 18
invoke-direct {p0, p1, p2, p3}, Landroid/widget/TextClock;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;I)V
.line 19
return-void
.end method
# virtual methods
.method public onDarkChanged(Landroid/graphics/Rect;FI)V
.locals 2
.param p1, "area" # Landroid/graphics/Rect;
.param p2, "darkIntensity" # F
.param p3, "tint" # I
.prologue
.line 133
invoke-virtual {p0}, Landroid/view/View;->getResources()Landroid/content/res/Resources;
move-result-object v1
.line 134
invoke-static {p1, p0, p2}, Lcom/android/systemui/statusbar/policy/DarkIconDispatcherHelper;->inDarkMode(Landroid/graphics/Rect;Landroid/view/View;F)Z
move-result v0
if-eqz v0, :cond_0
.line 135
const v0, 0x7f060175
.line 133
:goto_0
invoke-virtual {v1, v0}, Landroid/content/res/Resources;->getColor(I)I
move-result v0
invoke-virtual {p0, v0}, Landroid/widget/TextView;->setTextColor(I)V
.line 136
return-void
.line 135
:cond_0
const v0, 0x7f060174
goto :goto_0
.end method
注意这里.line 135
后面的一行,const v0, 0x7f060175
中的0x7f060175
来自之前搜索status_bar_textColor_darkmode
时候记录下来的id
。注意替换。
同样.line 135
后面的第二行,const v0, 0x7f060174
中的0x7f060174
来自之前搜索status_bar_textColor
时候记录下来的id
。注意替换。
打包为apk
文件。
java -jar apktool.jar b MiuiSystemUI -o MiuiSystemUI_mod.apk
这时候在工作目录就会生成MiuiSystemUI_mod.apk
文件了。
替换文件
同时用解压软件打开MiuiSystemUI_mod.apk
和MiuiSystemUI.apk
。然后把MiuiSystemUI_mod.apk
里面的resources.arsc
、classes.dex
和res/layout/status_bar.xml
这三个文件替换到MiuiSystemUI.apk
里面。
测试
替换完成之后得到的MiuiSystemUI.apk
,我们需要测试一下。测试很简单,就是再解包一次:
java -jar apktool.jar d MiuiSystemUI.apk -o MiuiSystemUI_test
如果这时候没有出现错误信息,那就证明制作成功了。
如果出现一下错误:
Could not decode file, replacing by FALSE value:
就证明之前的修复res
目录结构没有做好。根据错误提示给出的路径检查是不是某个文件漏了剪贴。
制作Magisk模块。
system/placeholder
文件删掉。然后把MiuiSystemUI.apk
文件放到/system/priv-app/MiuiSystemUI/
下(自行建立文件夹)。module.prop
修改模块的名字、描述和作者等信息。zip
文件。zip
文件检查,应该一打开就能看到module.prop
才可以。把模块放到手机上,然后打开Magisk Manager安装。
这里建议先安装mm再安装模块。如果出现什么问题,可以到twrp中使用mm把模块删掉或者禁用。