"纸上得来终觉浅,绝知此事要躬行",尤其看代码的时候经常觉得都懂了,自己写得时候全忘了。所以最好的记忆还是自己写个例子。所以学习EdXposed的时候写了个例子把整个流程走一遍。
EdXposed完全Follow Xposed的API,所以整个开发流程完全一致。 从本质上来讲,EdXposed 模块也是一个 Android 程序。但与普通程序不同的是,想要让写出的Android程序成为一个Xposed 模块,要额外多完成以下四个硬性任务:
package com.wq.xposedtargetapp;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.util.concurrent.ExecutionException;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, getIpAddr(), Toast.LENGTH_SHORT).show();
}
});
}
public String getIpAddr() {
return "192.168.180.123";
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wq.xpasedmodule">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!--表示当前app是一个xposedmodule-->
<meta-data
android:name="xposedmodule"
android:value="true" />
<!--当前module的描述-->
<meta-data
android:name="xposeddescription"
android:value="edxposed test" />
<!--edxposed 最低版本-->
<meta-data
android:name="xposedminversion"
android:value="53" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Xposed API build.gradle修改
dependencies {
//指定Xposed API
compileOnly 'de.robv.android.xposed:api:82'
compileOnly 'de.robv.android.xposed:api:82:sources'
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
package com.wq.xpasedmodule;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
public class EdXposedHookTest implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
// 指定Hook目标app
if (loadPackageParam.packageName.equals("com.wq.xposedtargetapp")) {
// 指定Hook的目标类
Class clazz = loadPackageParam.classLoader.loadClass("com.wq.xposedtargetapp.MainActivity");
// 查找Hook的方法
XposedHelpers.findAndHookMethod(clazz, "getIpAddr", new XC_MethodHook() {
// 具体执行逻辑
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// 替换getIpAddr方法的返回值
param.setResult("111.111.111.111");
}
});
}
}
}
com.wq.xpasedmodule.EdXposedHookTest