package com.bigyu.myapplication; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import dalvik.system.DexClassLoader; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.content.res.AssetManager; import android.content.res.Resources; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; /** * @author bigyu */ public class ProxyActivity extends AppCompatActivity { private static final String TAG = "ProxyActivity"; public static final String FROM = "extra.from"; public static final int FROM_EXTERNAL = 0; public static final int FROM_INTERNAL = 1; public static final String EXTRA_DEX_PATH = "extra.dex.path"; public static final String EXTRA_CLASS = "extra.class"; private String mClass; private String mDexPath; //远程Activity private Activity remoteActivity; //生命周期相关的方法 private Map<String, Method> mActivityLifecircleMethods = new HashMap<>(); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mDexPath = getIntent().getStringExtra(EXTRA_DEX_PATH); mClass = getIntent().getStringExtra(EXTRA_CLASS); File mFile = new File(mDexPath); mLayoutInflater = LayoutInflater.from(this); initAssetManager(mFile); if (mClass != null) { launchTargetActivity(mClass); } } //activity的命名规则是:全包名+类名,例如 com.example.client.MainActivity protected void launchTargetActivity(final String className) { File dexOutputDir = this.getDir("dex", 0); final String dexOutputPath = dexOutputDir.getAbsolutePath(); ClassLoader localClassLoader = ClassLoader.getSystemClassLoader(); DexClassLoader dexClassLoader = new DexClassLoader(mDexPath, dexOutputPath, null, localClassLoader); try { Class<?> remoteClass = dexClassLoader.loadClass(className); Constructor<?> remoteConstructor = remoteClass.getConstructor(new Class[]{}); //创建远程Activity Object instance = remoteConstructor.newInstance(new Object[]{}); remoteActivity = (Activity) instance; //设置远程Activity的代理,即ProxyActivity Method setProxy = remoteClass.getMethod("setProxy", new Class[]{Activity.class}); setProxy.setAccessible(true); setProxy.invoke(instance, new Object[]{this}); Method setResourcesM = remoteClass.getMethod("setResourcesM", new Class[]{AssetManager.class, Resources.class, LayoutInflater.class}); setResourcesM.setAccessible(true); setResourcesM .invoke(instance, new Object[]{mAssetManager, mResources, mLayoutInflater}); //手动执行远程Activity的onCreate方法 Method onCreate = remoteClass.getDeclaredMethod("onCreate", new Class[]{Bundle.class}); onCreate.setAccessible(true); Bundle bundle = new Bundle(); bundle.putInt(FROM, FROM_EXTERNAL); onCreate.invoke(instance, new Object[]{bundle}); } catch (Exception e) { e.printStackTrace(); } } //localClass就是从APK中解析出的Activity的Class对象 //这个方法将这个Activity中的生命周期相关的方法都取出来放进一个Map; protected void bindLifecircleMethods(Class<?> localClass) { String[] methodNames = new String[]{"onRestart", "onStart", "onResume", "onPause", "onStop", "onDestory"}; for (String methodName : methodNames) { Method method = null; try { method = localClass.getDeclaredMethod(methodName, new Class[]{}); method.setAccessible(true); } catch (NoSuchMethodException e) { e.printStackTrace(); } mActivityLifecircleMethods.put(methodName, method); } Method onCreate = null; try { onCreate = localClass.getDeclaredMethod("onCreate", new Class[]{Bundle.class}); onCreate.setAccessible(true); } catch (NoSuchMethodException e) { e.printStackTrace(); } mActivityLifecircleMethods.put("onCreate", onCreate); Method onActivityResult = null; try { onActivityResult = localClass.getDeclaredMethod("onActivityResult", new Class[]{int.class, int.class, Intent.class}); onActivityResult.setAccessible(true); } catch (NoSuchMethodException e) { e.printStackTrace(); } mActivityLifecircleMethods.put("onActivityResult", onActivityResult); } @Override //这里在Proxy执行生命周期相关的方法时调用远程Activity的生命周期方法就可以了 protected void onResume() { super.onResume(); Method onResume = mActivityLifecircleMethods.get("onResume"); if (onResume != null) { try { onResume.invoke(remoteActivity, new Object[]{}); } catch (Exception e) { e.printStackTrace(); } } } public static void launch(Activity activity, String url, String clazz) { Intent intent = new Intent(activity, ProxyActivity.class); intent.putExtra(EXTRA_DEX_PATH, url); intent.putExtra(EXTRA_CLASS, clazz); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activity.startActivity(intent); } AssetManager mAssetManager; Resources mResources; LayoutInflater mLayoutInflater; @SuppressLint("DiscouragedPrivateApi") private void initAssetManager(File apkFile) { try { mAssetManager = AssetManager.class.newInstance(); Method addAssetPathMethod = AssetManager.class .getDeclaredMethod("addAssetPath", String.class); addAssetPathMethod.setAccessible(true); int result = (int) addAssetPathMethod.invoke(mAssetManager, apkFile.getAbsolutePath()); Log.e("TAG", "initAssetManager: addAssetPath " + result); Method ensureStringBlocksMethod = AssetManager.class .getDeclaredMethod("ensureStringBlocks"); ensureStringBlocksMethod.setAccessible(true); ensureStringBlocksMethod.invoke(mAssetManager); mResources = new Resources(mAssetManager, getResources().getDisplayMetrics(), getResources().getConfiguration()); } catch (Exception e) { e.printStackTrace(); } } }