插件化架构介绍
简介:点击按钮,去服务器下载一个功能.apk, 保存到本地。
它没有运行是单独的plugin,我们要把它启动起来,并给它传递参数。
- 启动的插件Activity,是没有在主app中注册的。绕过Manifest的检测。
- 类需要加载,插件的Activity的类是在插件中,
- 资源需要加载,
2.Hook启动流程 startActivity: 动态代理,下钩子函数。
基于动态代理设计模式,基于Activity启动流程。 IActivityManager
MVP,RXJava 都使用了代理。
用一个注册了的ProxyActivity占坑,让ProxyActivity去过安检。真实的Activity不过安检,后面将intent替换回来。
2.1 获取ActivityManagerNative里面的IActivityManagerSingleton( 旧版本gDefault)
2.2 获取IActivityManagerSingleton( 旧版本gDefault) 中的 IActivityManagerSingleton(旧版本mInstance)属性。
2.3 用一个注册了的ProxyActivity占坑,让ProxyActivity去过安检。
2.4 将intent换回来,换成原来的。
- 2.4.1 获取 ActivityThread 实例;
- 2.4.2 获取 ActivityThread中的mH。
- 2.4.3 hook handleLaunchActivity.
@Hide
public abstract class Singleton<T> {
@UnsupportedAppUsage
public Singleton() {
}
@UnsupportedAppUsage
private T mInstance;
protected abstract T create();
@UnsupportedAppUsage
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
// Handler
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) { // mCallback 非空的情况下。
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
public class BaseApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
HookStartActivityUtil hookUtil = new HookStartActivityUtil(this, ProxyActivity.class);
try {
hookUtil.hookStartActivity();
hookUtil.hookLaunchActivity();
} catch(Exception e) {
e.printStackTrace();
}
}
}
// 主app中页面,跳转到 插件化未注册的TestActivity。
public void jumpPage(View view) {
try {
Intent intent = new Intent();
intent.setClass(this, Class.forName("com.tom.hook.TestActivity"));
intent.putExtra("user_name", "zhangSan");
startActivity(intent);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* Added by Tom on 2024/07/09.
* 代理过检测的Activity
*/
public class ProxyActivity extends Activity {
}
package com.tom.hook;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Added by Tom on 2024/07/09.
*/
public class HookStartActivityUtil {
private static final String TAG = "HookStartActivityUtil";
private Context mContext;
private Class<?> mProxyClass; // 用来过安检的类。已经注册过的类。
private final String EXTRA_ORIGIN_INTENT = "EXTRA_ORIGIN_INTENT";
public HookStartActivityUtil(Context context, Class<?> proxyClass) {
this.mContext = context.getApplicationContext();
this.mProxyClass = proxyClass;
}
public void hookStartActivity() throws Exception {
Object singleTon = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
@SuppressLint("PrivateApi")
Class<?> activityManagerClass = Class.forName("android.app.ActivityTaskManager");
Field iActivityManagerSingletonField = activityManagerClass.getDeclaredField("IActivityTaskManagerSingleton");
iActivityManagerSingletonField.setAccessible(true);
singleTon = iActivityManagerSingletonField.get(null);
Log.d(TAG, "singleTon:" + singleTon.toString());
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
/*
* android 26或以上版本的API是一样的
*/
Class<?> activityManagerClass = Class.forName("android.app.ActivityManager");
Field iActivityManagerSingletonField = activityManagerClass.getDeclaredField("IActivityManagerSingleton");
iActivityManagerSingletonField.setAccessible(true);
singleTon = iActivityManagerSingletonField.get(null);
} else {
/*
* android 26或以下版本的API是一个系列
*/
Class<?> activityManagerClass = Class.forName("android.app.ActivityManagerNative");
Field iActivityManagerSingletonField = activityManagerClass.getDeclaredField("gDefault");
iActivityManagerSingletonField.setAccessible(true);
singleTon = iActivityManagerSingletonField.get(null);
// 2.1 获取ActivityManagerNative里面的IActivityManagerSingleton( 旧版本gDefault)
// 2.2 获取属性: IActivityTaskManagerSingleton(旧版本 gDefault)属性。
}
// 2.3 通过gDefault的mInstance属性,获取
// 而实际上AMS在单例Singleton中
Class<?> singletonClazz = Class.forName("android.util.Singleton");
Field mInstanceField = singletonClazz.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
Object iamInstance = mInstanceField.get(singleTon); // AMS
if (iamInstance == null) Log.e(TAG, "iamInstance is null!!!");
Class<?> iActivityManagerClass;
// 因为生成的接口类变了,所以这里我们需要根据版本来代理不同的接口class
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// android10+ 代理IActivityTaskManager
iActivityManagerClass = Class.forName("android.app.IActivityTaskManager");
} else {
// android10- 代理IActivityManager
iActivityManagerClass = Class.forName("android.app.IActivityManager");
}
iamInstance = Proxy.newProxyInstance(HookStartActivityUtil.class.getClassLoader(),
new Class[]{iActivityManagerClass},
// InvocationHandler 执行者,
new StartActivityInvocationHandler(iamInstance));
// 4. 重新设定, 重新设定为我们的代理。
mInstanceField.set(singleTon, iamInstance);
}
// 动态代理
private class StartActivityInvocationHandler implements InvocationHandler {
// 方法真正的执行者。高版本API中,TODO 拿到的这个值为null。可使用腾讯的Shadow 插件化框架。
private Object mObject;
public StartActivityInvocationHandler(Object object) {
this.mObject = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.e(TAG, "method: " + method.getName());
// 替换intent,过AndroidManifest.xml 的检测
if (method.getName().equals("startActivity")) {
// 1.获取原来intent替换,最后启动的时候再替换回来。
Intent originIntent = (Intent) args[2];
// 2.使用安全的intent替换。去安检。
Intent safeIntent = new Intent(mContext, mProxyClass);
args[2] = safeIntent;
// 3.绑定原来的(缓存原来的Activity)
safeIntent.putExtra(EXTRA_ORIGIN_INTENT, originIntent);
}
return method.invoke(mObject, args);
}
}
// hook handler(ActivityManager.mH)
public void hookLaunchActivity() throws Exception {
// 2.4.1 获取 ActivityThread 实例;
Class<?> atClass = Class.forName("android.app.ActivityThread");
Field scatField = atClass.getField("sCurrentActivityThread");
scatField.setAccessible(true);
Object sCurrentActivityThread = scatField.get(null);
// 2.4.2 获取 ActivityThread中的mH。
Field mHField = atClass.getDeclaredField("mH");
mHField.setAccessible(true);
Handler mHandler = (Handler) mHField.get(sCurrentActivityThread);
// 2.4.3 hook handleLaunchActivity.
// 给Handler 设置Callback
Class<?> handlerClass = Class.forName("android.os.Handler");
Field mCallback = handlerClass.getDeclaredField("mCallback");
mCallback.setAccessible(true);
mCallback.set(mHandler, new HandlerCallback());
}
private class HandlerCallback implements Handler.Callback {
@Override
public boolean handleMessage(Message msg) {
// 每发一个消息,都会走handleMessage 方法一次。
if (msg.what == 100) {
handleLaunchActivity(msg);
}
return false;
}
// 开始启动创建Activity 拦截,将intent还回去。
private void handleLaunchActivity(Message msg) {
try {
Object record = msg.obj;
// 1.从record 中拿过安检的intent
Field intentField = record.getClass().getDeclaredField("intent");
intentField.setAccessible(true);
Intent safeIntent = (Intent) intentField.get(record);
// 2.从safeIntent中, 获取原来的originIntent
Intent originIntent = safeIntent.getParcelableExtra(EXTRA_ORIGIN_INTENT);
// 3.重新设置回去intent。
if (originIntent != null) {
intentField.set(record, originIntent);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
网友评论