Xposed免重啟更新模塊


    Xposed模塊在每次更新后都需要重啟才能生效,公司給我的測試機是小米4,非常古董,每次重啟都需要花費大量時間.而且手機系統是我刷的一個原生6.0的系統,總有些小bug,有時候需要重啟很多次才行,等的我黃花菜都涼了.所以有必要把這個搞一搞了.

   簡單總結一下原理:安裝模塊時,Android系統會在data/app/對應包名的目錄下保存原始apk,通過讀取這個原始的apk,然后new一個PathClassLoader,該PathClassLoader用於加載寫有hook邏輯的類,最后通過反射的方式完成hook的具體邏輯.

          工具: XposedBridgeApi-54.jar

        我使用的是一個已root的原生6.0系統的小米4

     方法:1.新建一個HookLoader類,具體代碼如下:

  1 package com.example.xposedhook;
  2 
  3 import android.app.Application;
  4 import android.content.Context;
  5 import android.content.pm.ApplicationInfo;
  6 import android.content.pm.PackageManager;
  7 
  8 import java.io.File;
  9 
 10 import dalvik.system.PathClassLoader;
 11 import de.robv.android.xposed.IXposedHookLoadPackage;
 12 import de.robv.android.xposed.IXposedHookZygoteInit;
 13 import de.robv.android.xposed.XC_MethodHook;
 14 import de.robv.android.xposed.XposedBridge;
 15 import de.robv.android.xposed.XposedHelpers;
 16 import de.robv.android.xposed.callbacks.XC_LoadPackage;
 17 
 18 /**
 19  * @author DX
 20  * 這種方案建議只在開發調試的時候使用,因為這將損耗一些性能(需要額外加載apk文件),調試沒問題后,直接修改xposed_init文件為正確的類即可
 21  * 可以實現免重啟,由於存在緩存,需要殺死宿主程序以后才能生效
 22  * Created by DX on 2017/10/4.
 23  * Modified by chengxuncc on 2019/4/16.
 24  */
 25 
 26 public class HookLoader implements IXposedHookLoadPackage, IXposedHookZygoteInit {
 27     //按照實際使用情況修改下面幾項的值
 28     /**
 29      * 當前Xposed模塊的包名,方便尋找apk文件
 30      */
 31     private final static String modulePackageName = HookLoader.class.getPackage().getName();
 32 
 33     /**
 34      * 實際hook邏輯處理類
 35      */
 36     private final String handleHookClass = HookLogic.class.getName();
 37     /**
 38      * 實際hook邏輯處理類的入口方法
 39      */
 40     private final String handleHookMethod = "handleLoadPackage";
 41 
 42     private final String initMethod = "initZygote";
 43 
 44     private IXposedHookZygoteInit.StartupParam startupparam;
 45 
 46     /**
 47      * 重定向handleLoadPackage函數前會執行initZygote
 48      *
 49      * @param loadPackageParam
 50      * @throws Throwable
 51      */
 52     @Override
 53     public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
 54         // 排除系統應用
 55         if (loadPackageParam.appInfo == null ||
 56                 (loadPackageParam.appInfo.flags & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) == 1) {
 57             return;
 58         }
 59         //將loadPackageParam的classloader替換為宿主程序Application的classloader,解決宿主程序存在多個.dex文件時,有時候ClassNotFound的問題
 60         XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
 61             @Override
 62             protected void afterHookedMethod(MethodHookParam param) throws Throwable {
 63                 Context context = (Context) param.args[0];
 64                 loadPackageParam.classLoader = context.getClassLoader();
 65                 Class<?> cls = getApkClass(context, modulePackageName, handleHookClass);
 66                 Object instance = cls.newInstance();
 67                 try {
 68                     cls.getDeclaredMethod(initMethod, startupparam.getClass()).invoke(instance, startupparam);
 69                 }catch (NoSuchMethodException e){
 70                     // 找不到initZygote方法
 71                 }
 72                 cls.getDeclaredMethod(handleHookMethod, loadPackageParam.getClass()).invoke(instance, loadPackageParam);
 73             }
 74         });
 75     }
 76 
 77     /**
 78      * 實現initZygote,保存啟動參數。
 79      *
 80      * @param startupParam
 81      */
 82     @Override
 83     public void initZygote(IXposedHookZygoteInit.StartupParam startupParam) {
 84         this.startupparam = startupParam;
 85     }
 86 
 87     private Class<?> getApkClass(Context context, String modulePackageName, String handleHookClass) throws Throwable {
 88         File apkFile = findApkFile(context, modulePackageName);
 89         if (apkFile == null) {
 90             throw new RuntimeException("尋找模塊apk失敗");
 91         }
 92         //加載指定的hook邏輯處理類,並調用它的handleHook方法
 93         PathClassLoader pathClassLoader = new PathClassLoader(apkFile.getAbsolutePath(), ClassLoader.getSystemClassLoader());
 94         Class<?> cls = Class.forName(handleHookClass, true, pathClassLoader);
 95         return cls;
 96     }
 97 
 98     /**
 99      * 根據包名構建目標Context,並調用getPackageCodePath()來定位apk
100      *
101      * @param context           context參數
102      * @param modulePackageName 當前模塊包名
103      * @return apk file
104      */
105     private File findApkFile(Context context, String modulePackageName) {
106         if (context == null) {
107             return null;
108         }
109         try {
110             Context moudleContext = context.createPackageContext(modulePackageName, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
111             String apkPath = moudleContext.getPackageCodePath();
112             return new File(apkPath);
113         } catch (PackageManager.NameNotFoundException e) {
114             e.printStackTrace();
115         }
116         return null;
117     }
118 }

       2.將代碼第36行改為你自己寫的hook邏輯的類.class.getName()即可,其它地方基本不用動.比如我寫的hook類名字為XposedUtils,里面是具體的hook邏輯,只需將第36行代碼改成:

            

       3.將xposed_init文件程序入口處改為新建的HookLoader這個類.如:

 

 

    4.大功告成,開始為所欲為.

          注意:有的可能會拋出"尋找apk模塊失敗"的異常,這是因為在findApkFile方法中傳入的modulePackageName可能不是當前模塊的完整包名,可以手動改成app build.gradle中appcationId的值.如:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

     感謝大佬提供的方案.

   原文:https://blog.csdn.net/u011956004/article/details/78612502

   GitHub地址:https://github.com/shuihuadx/XposedHook


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM