• 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

  • 相关阅读:
    合并排序二
    合并排序
    理解Windows消息循环机制
    直接插入排序
    关于typedef的用法总结
    迭代器的抽象
    C++基础--malloc和new的区别
    C++基础--sizeof和strlen的区别
    C++ VS编译问题--LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
    SSL--Windows下生成OpenSSL自签证书
  • 原文地址:https://www.cnblogs.com/CYCLearning/p/11636420.html
Copyright © 2020-2023  润新知