制作Magisk模块使MIUI状态栏时钟显示秒数

发表于 2018-11-04   |   分类于 默认分类   |   访问: 32,344 次

Preface

MIUI还挺好用的,除了广告比较多,其他都很适合国内的用户使用。但是有一个功能MIUI死活不肯加进去,就是状态栏的时钟死活不加入显秒的设置。当然,目前很多第三方固件支持显秒,或者支持安装Xposed之后安装显秒模块。然而,迁移到第三方固件的一个问题就是数据比较难保持一致,而且可能不太稳定。安装Xposed更不用看了,MIUI原生跟它有仇,而且安装Xposed之后必然导致系统卡顿、耗电增加。所以最好的方法就是使用Magisk模块Systemless地增加时钟显秒。

此教程以小米6X稳定版为例,制作Magisk模块。要注意的是,不同设备不同系统之间模块不通用,也就是说,我制作了MI6X的这样一个模块,MI8是不能用的。我在MI6X的稳定版做了这个模块,MI6X的开发板也不能用。每部设备的每个版本的系统都需要单独制作,这也是为什么我选择发制作教程而不是直接发模块。

Requirement

  • 本教程以Linux为例,需要读者有一定Linux基础;
  • 已经安装好Java环境;
  • 已经安装并了解apktool
  • 已经安装并了解baksmali;
  • 已经安装并了解platform-tools(adb);
  • 手机已经使用Magisk进行了Root。

步骤

  1. 手机与设备使用数据线连接,并且手机已经开启USB调试

  2. 使用adb把相关文件和目录拉到工作目录

    1. 首先是/system/framework/arm64目录
       adb pull /system/framework/arm64

      这时候工作目录下面应该有一个arm64的文件夹了。

    2. 然后是/system/priv-app/MiuiSystemUI/oat/arm64目录,也是放到arm64文件夹:
       adb pull /system/priv-app/MiuiSystemUI/oat/arm64

      这时候arm64文件夹应该多了两个文件。

    3. 还有其他的文件:
       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
  3. 拉完文件之后,进入arm64目录,把MiuiSystemUI进行deodex化:

    1. 进入arm64目录
       cd arm64
    2. 使用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 ..
  4. 用解压软件打开MiuiSystemUI.apk,把classes.dex放进去。

  5. 使用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目录。

  6. 修复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

    我们需要替换这个文件才能成功打包。替换成这个文件。(原帖, issue)

  7. 修复res的目录结构
    由于apktool的一些问题,这时候解包出来的res目录结构跟原apk不一样。比如:原来用解压软件打开MiuiSystemUI.apk里面有res/drawable, res/drawable-v21res/drawable-v23目录。但是解包出来之后一个res/drawable目录了,后面两个目录的文件都跑到第一个文件里面了。这时候我们需要修复目录结构。主要修复分为以下几种:

    • 目录名版本信息没了。比如:drawable-ldrtl-xxhdpi-v4变成了drawable-ldrtl-xxhdpi。这需要在对应目录后面加上版本号。
    • 多个目录合并成一个目录。比如drawable-v21drawable-v23目录合并到drawable里面了。这时候需要创建drawable-v21drawable-v23两个目录,并对照着原apk文件,把跑到drawable里面的文件剪贴回drawable-v21drawable-v23里面。
    • 还有一个很奇葩的问题。在MI6X稳定版的包里,有一个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
  8. 修改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" />

    保存文件。

  9. 修改res/values/ids.xml文件
    用文本编辑器打开res/values/ids.xml文件,定位到倒数第二行,在其后添加一行(也就是说在</resources>前添加一行):

     <item type="id" name="advance_clock">false</item>
  10. 修改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记录下来。

  11. 修改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_clockid(那个加一后的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
    

    然后保存文件。

  12. 添加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。注意替换。

  13. 打包为apk文件。

     java -jar apktool.jar b MiuiSystemUI -o MiuiSystemUI_mod.apk

    这时候在工作目录就会生成MiuiSystemUI_mod.apk文件了。

  14. 替换文件
    同时用解压软件打开MiuiSystemUI_mod.apkMiuiSystemUI.apk。然后把MiuiSystemUI_mod.apk里面的resources.arscclasses.dexres/layout/status_bar.xml这三个文件替换到MiuiSystemUI.apk里面。

  15. 测试
    替换完成之后得到的MiuiSystemUI.apk,我们需要测试一下。测试很简单,就是再解包一次:

     java -jar apktool.jar d MiuiSystemUI.apk -o MiuiSystemUI_test

    如果这时候没有出现错误信息,那就证明制作成功了。
    如果出现一下错误:

     Could not decode file, replacing by FALSE value: 

    就证明之前的修复res目录结构没有做好。根据错误提示给出的路径检查是不是某个文件漏了剪贴。

  16. 制作Magisk模块。

    1. 下载Magisk模块模板。(点击clone or download然后点击download zip,下载之后解压。)
    2. 把模板里面的system/placeholder文件删掉。然后把MiuiSystemUI.apk文件放到/system/priv-app/MiuiSystemUI/下(自行建立文件夹)。
    3. 修改module.prop修改模块的名字、描述和作者等信息。
    4. 把模板里面的所有文件打包成一个zip文件。
    5. 打开zip文件检查,应该一打开就能看到module.prop才可以。
  17. 把模块放到手机上,然后打开Magisk Manager安装。
    这里建议先安装mm再安装模块。如果出现什么问题,可以到twrp中使用mm把模块删掉或者禁用。

© 2024 Powered by Typecho & Theme Quark
粤ICP备2024321271号-1 粤公网安备44030002005029号