直接放代码

package com.xirtam.hello;

import android.app.Application;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build; import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List; import dalvik.system.PathClassLoader;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage; /**
* @author DX
* 这种方案建议只在开发调试的时候使用,因为这将损耗一些性能(需要额外加载apk文件),调试没问题后,直接修改xposed_init文件为正确的类即可
* 可以实现免重启,由于存在缓存,需要杀死宿主程序以后才能生效
* 这种免重启的方式针对某些特殊情况的hook无效
* 例如我们需要implements IXposedHookZygoteInit,并将自己的一个服务注册为系统服务,这种就必须重启了
* Created by DX on 2017/10/4.
*/ public class HookLoader implements IXposedHookLoadPackage {
//按照实际使用情况修改下面几项的值
/**
* 当前Xposed模块的包名,方便寻找apk文件 TODO 需要配置
*/
private final String modulePackage = "com.xirtam.hello";
/**
* 宿主程序的包名(允许多个),过滤无意义的包名,防止无意义的apk文件加载
*/
private static List<String> hostAppPackages = new ArrayList<>(); static {
// TODO: Add the package name of application your want to hook!
hostAppPackages.add("com.xirtam.hello");
} /**
* 实际hook逻辑处理类 TODO 需要配置
*/
private final String handleHookClass = TestHook2.class.getName();
/**
* 实际hook逻辑处理类的入口方法
*/
private final String handleHookMethod = "handleLoadPackage"; @Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (hostAppPackages.contains(loadPackageParam.packageName)) {
//将loadPackageParam的classloader替换为宿主程序Application的classloader,解决宿主程序存在多个.dex文件时,有时候ClassNotFound的问题
XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Context context = (Context) param.args[0];
loadPackageParam.classLoader = context.getClassLoader();
invokeHandleHookMethod(context, modulePackage, handleHookClass, handleHookMethod, loadPackageParam);
}
});
}
} /**
* 安装app以后,系统会在/data/app/下备份了一份.apk文件,通过动态加载这个apk文件,调用相应的方法
* 这样就可以实现,只需要第一次重启,以后修改hook代码就不用重启了
*
* @param context context参数
* @param modulePackageName 当前模块的packageName
* @param handleHookClass 指定由哪一个类处理相关的hook逻辑
* @param loadPackageParam 传入XC_LoadPackage.LoadPackageParam参数
* @throws Throwable 抛出各种异常,包括具体hook逻辑的异常,寻找apk文件异常,反射加载Class异常等
*/
private void invokeHandleHookMethod(Context context, String modulePackageName, String handleHookClass, String handleHookMethod, XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
// File apkFile = findApkFileBySDK(modulePackageName);//会受其它Xposed模块hook 当前宿主程序的SDK_INT的影响
// File apkFile = findApkFile(modulePackageName);
//原来的两种方式不是很好,改用这种新的方式
File apkFile = findApkFile(context, modulePackageName);
if (apkFile == null) {
throw new RuntimeException("寻找模块apk失败");
}
//加载指定的hook逻辑处理类,并调用它的handleHook方法
PathClassLoader pathClassLoader = new PathClassLoader(apkFile.getAbsolutePath(), ClassLoader.getSystemClassLoader());
Class<?> cls = Class.forName(handleHookClass, true, pathClassLoader);
Object instance = cls.newInstance();
Method method = cls.getDeclaredMethod(handleHookMethod, XC_LoadPackage.LoadPackageParam.class);
method.invoke(instance, loadPackageParam);
} /**
* 根据包名构建目标Context,并调用getPackageCodePath()来定位apk
*
* @param context context参数
* @param modulePackageName 当前模块包名
* @return return apk file
*/
private File findApkFile(Context context, String modulePackageName) {
if (context == null) {
return null;
}
try {
Context moudleContext = context.createPackageContext(modulePackageName, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
String apkPath = moudleContext.getPackageCodePath();
return new File(apkPath);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
} /**
* 寻找这个Android设备上的当前apk文件,不受其它Xposed模块hook SDK_INT的影响
*
* @param modulePackageName 当前模块包名
* @return File 返回apk文件
* @throws FileNotFoundException 在/data/app/下的未找到本模块apk文件,请检查本模块包名配置是否正确.
* 具体检查build.gradle中的applicationId和AndroidManifest.xml中的package
*/
@Deprecated
private File findApkFile(String modulePackageName) throws FileNotFoundException {
File apkFile = null;
try {
apkFile = findApkFileAfterSDK21(modulePackageName);
} catch (Exception e) {
try {
apkFile = findApkFileBeforeSDK21(modulePackageName);
} catch (Exception e2) {
//忽略这个异常
}
}
if (apkFile == null) {
throw new FileNotFoundException("没在/data/app/下找到文件对应的apk文件");
}
return apkFile;
} /**
* 根据当前的SDK_INT寻找这个Android设备上的当前apk文件
*
* @param modulePackageName 当前模块包名
* @return File 返回apk文件
* @throws FileNotFoundException 在/data/app/下的未找到本模块apk文件,请检查本模块包名配置是否正确.
* 具体检查build.gradle中的applicationId和AndroidManifest.xml中的package
*/
@Deprecated
private File findApkFileBySDK(String modulePackageName) throws FileNotFoundException {
File apkFile;
//当前Xposed模块hook了Build.VERSION.SDK_INT不用担心,因为这是发生在hook之前,不会有影响
//但是其它的Xposed模块hook了当前宿主的这个值以后,就会有影响了,所以这里没有使用这个方法
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
apkFile = findApkFileAfterSDK21(modulePackageName);
} else {
apkFile = findApkFileBeforeSDK21(modulePackageName);
}
return apkFile;
} /**
* 寻找apk文件(api_21之后)
* 在Android sdk21以及之后,apk文件的路径发生了变化
*
* @param packageName 当前模块包名
* @return File 返回apk文件
* @throws FileNotFoundException apk文件未找到
*/
@Deprecated
private File findApkFileAfterSDK21(String packageName) throws FileNotFoundException {
File apkFile;
File path = new File(String.format("/data/app/%s-%s", packageName, "1"));
if (!path.exists()) {
path = new File(String.format("/data/app/%s-%s", packageName, "2"));
}
if (!path.exists() || !path.isDirectory()) {
throw new FileNotFoundException(String.format("没找到目录/data/app/%s-%s", packageName, "1/2"));
}
apkFile = new File(path, "base.apk");
if (!apkFile.exists() || apkFile.isDirectory()) {
throw new FileNotFoundException(String.format("没找到文件/data/app/%s-%s/base.apk", packageName, "1/2"));
}
return apkFile;
} /**
* 寻找apk文件(api_21之前)
*
* @param packageName 当前模块包名
* @return File 返回apk文件
* @throws FileNotFoundException apk文件未找到
*/
@Deprecated
private File findApkFileBeforeSDK21(String packageName) throws FileNotFoundException {
File apkFile = new File(String.format("/data/app/%s-%s.apk", packageName, "1"));
if (!apkFile.exists()) {
apkFile = new File(String.format("/data/app/%s-%s.apk", packageName, "2"));
}
if (!apkFile.exists() || apkFile.isDirectory()) {
throw new FileNotFoundException(String.format("没找到文件/data/app/%s-%s.apk", packageName, "1/2"));
}
return apkFile;
}
}

配置一下3处TODO标签的位置,然后把xposed_init文件中的配置改成这个类即可,并不适用于所有情况的免重启,注释写的很明确了,感谢原作者,本文代码有少量修改。

Xposed免重启调试工具类的更多相关文章

  1. tomcat免重启随意更改java代码 提高开发效率

    转载:http://developer.51cto.com/art/201012/241243.htm 做为了一个java开发人员,总是为因为要增加一个类,或是增加删除一个方法,甚至修改一个小处代码而 ...

  2. Eclipse的Tomcat热部署,免重启的方法

    背景与目标: 最好使用MyEclipse部署Web应用,在开发调试时,非常方式.资源文件修改可以自动的同步.修改Java文件,除非改变类的结构定义,也可以实现热部署的效果. 后来使用Eclipse J ...

  3. php简单实用的调试工具类

    <?php /* * 调试类 */ class Common_Debug { //打开错误报告 public static function showError($debug = true) { ...

  4. Node.js中的express框架,修改内容后自动更新(免重启),express热更新

    个人网站 https://iiter.cn 程序员导航站 开业啦,欢迎各位观众姥爷赏脸参观,如有意见或建议希望能够不吝赐教! 以前node中的express框架,每次修改代码之后,都需要重新npm s ...

  5. HDFS免重启挂载新磁盘

    背景 在生产环境中,集群节点磁盘大小不同,其使用率也会不同,HDFS虽有均衡策略,但也会有数据不平衡的情况,有些节点磁盘就会被打满,然后这个节点就不健康了(Unhealthy Nodes),Yarn的 ...

  6. Xposed模块开发基本方法记录

    由于某些课程实验的要求,需要通过xposed框架对某应用进行hook操作,笔者选用了开源且免费的xposed框架进行实现.虽然网上存在一些利用xposed实现特定功能的文章资源,但大多均将xposed ...

  7. Xposed的新打开方式--Xpatch工作流程分析

    1. Xpatch概述 Xpatch是一款利用重打包的方式,使得被处理的Apk启动时自动加载Xposed模块,来实现应用内Hook的工具. 项目地址:https://github.com/WindyS ...

  8. 使用更清晰DebugLog开发和调试工具

    在开发和应用的开发和调试过程中难免会发现故障的过程中.我相信很多做iOS开发程序员Xcode的debug调试功能大加关注. 但在这样做Android开发过程中,却不那么方便,虽然IDE也提供了debu ...

  9. Spring Developer Tools 源码分析:二、类路径监控

    在 Spring Developer Tools 源码分析一中介绍了 devtools 提供的文件监控实现,在第二部分中,我们将会使用第一部分提供的目录监控功能,实现对开发环境中 classpath ...

随机推荐

  1. ActiveMQ依赖JDK版本关系

    1.如何查看官方发布的activeMQ依赖的JDK版本1)以ActiveMQ 5.15.2 Release为例:在下载页面的Change Log处, 2)打开下载号的jar包,以activemq-al ...

  2. Lua 中 pairs 和 ipairs 的区别

    ipairs (t) Returns three values: an iterator function, the table t, and 0, so that the construction ...

  3. $Django 支付宝支付,微信服务号推送消息 (测试需要把应用程序部署到服务器上)

    一 支付宝支付 大概 支付宝支付 正式环境:需要用营业执照去申请商户号,appid 测试环境:沙箱环境:https://openhome.alipay.com/platform/appDaily.ht ...

  4. 【原创】大叔问题定位分享(27)spark中rdd.cache

    spark 2.1.1 spark应用中有一些task非常慢,持续10个小时,有一个task日志如下: 2019-01-24 21:38:56,024 [dispatcher-event-loop-2 ...

  5. iOS 推荐几篇关于Objective-c 动态语言的文章

    http://www.cnblogs.com/Mr-Lin/p/5771969.html https://onevcat.com/2012/04/objective-c-runtime/ 我摘抄几句比 ...

  6. POJ 3104 Drying

    最让HSQ学长头疼的就是洗衣服了.洗完之后,每件衣服都有一定单位水分,在不使用烘干器的情况下,每件衣服每分钟自然流失1个单位水分,但如果使用了烘干机则每分钟流失K个单位水分.令人遗憾是HSQ所在的宿舍 ...

  7. unity setactive的使用

    1.可以用本身移出布局来实现隐藏 2.RawImage的texture的设置生成的一定要及时消除,避免内存泄漏

  8. php获取两个时间戳之间相隔多少天多少小时多少分多少秒

    /** * 返回两个时间的相距时间,*年*月*日*时*分*秒 * @param int $one_time 时间一 * @param int $two_time 时间二 * @param int $r ...

  9. CSS/Xpath 选择器 第几个子节点/父节点/兄弟节点

    0.参考 1.初始化 In [325]: from scrapy import Selector In [326]: text=""" ...: <div> ...

  10. 记录C#常用的代码片段

    时间一久,常用的代码会有点忘记,还是贴在这里方便查找! 1.将信息写入文件中 //将字符串写入到文本中 void writeToText(string msg) { try { msg = DateT ...