package com.zhy.blogcodes.dl; import android.app.Activity; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.content.res.Resources; import android.os.Bundle; import android.os.Environment; import android.text.TextUtils; import android.util.Log; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import dalvik.system.DexClassLoader; public class DLProxyActivity extends Activity { public static final String KEY_APK_PATH = "apk_path"; public static final String KEY_APK_RUNNTIME_ACTIVITY = "activity_class"; private static final String TAG = "DLProxyActivity"; private static final String KEY_FROM_EXTERNAL = "from_external"; private static final int VALUE_FROM_EXTERNAL = 0x110; private String mApkPath; private String mTargetActivityClazz; private DexClassLoader mDexClassLoader; private AssetManager mAssetManager; private Resources mResources; private Resources.Theme mTheme; @Override public Resources.Theme getTheme() { return mTheme == null ? super.getTheme() : mTheme; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mApkPath = getIntent().getStringExtra(KEY_APK_PATH); mTargetActivityClazz = getIntent().getStringExtra(KEY_APK_RUNNTIME_ACTIVITY); checkApkPath(); Log.e(TAG, mApkPath); initAssetAndResources(); if (mTargetActivityClazz == null) { launchTargetActivity(); } else { launchTargetActivity(mTargetActivityClazz); } } private void initAssetAndResources() { try { AssetManager assetManager = AssetManager.class.newInstance(); Method addAssetPath = AssetManager.class.getDeclaredMethod("addAssetPath", String.class); addAssetPath.setAccessible(true); addAssetPath.invoke(assetManager, mApkPath); mAssetManager = assetManager; Resources superRes = super.getResources(); Resources resources = new Resources(mAssetManager, superRes.getDisplayMetrics(), superRes.getConfiguration()); mResources = resources; mTheme = mResources.newTheme(); mTheme.setTo(super.getTheme()); Log.e(TAG, mAssetManager + " ," + mResources); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } private void checkApkPath() { if (TextUtils.isEmpty(mApkPath)) { throw new IllegalArgumentException("apkPath不能为空!"); } String apkPath = Environment.getExternalStorageDirectory() + mApkPath; //String apkPath = "/storage/emulated/legacy" + mApkPath; Log.e(TAG, "apkPath = " + apkPath); File file = new File(apkPath); if (!file.exists()) throw new RuntimeException("apkPath的路径不正确!" + apkPath); mApkPath = apkPath; } private void launchTargetActivity(String activityClazz) { try { ClassLoader localClassLoader = ClassLoader.getSystemClassLoader(); //init dexClassLoader DexClassLoader dexClassLoader = new DexClassLoader(mApkPath, getDir("dexPath", Context.MODE_PRIVATE).getAbsolutePath(), null, localClassLoader); mDexClassLoader = dexClassLoader; Log.e(TAG, "mDexClassloader = " + mDexClassLoader); //get act instance Class<?> actClazz = dexClassLoader.loadClass(activityClazz); Log.e(TAG, "actClazz = " + actClazz); Object activityInstance = actClazz.getConstructor().newInstance(); Log.e(TAG, "activityInstance = " + activityInstance); for (Method m : actClazz.getMethods()) { // Log.e(TAG, m.getName()); } //invoke setActivityProxy method Method methodSetProxy = actClazz.getMethod("setActivityProxy", new Class[]{Activity.class}); Log.e(TAG, "methodSetProxy = " + methodSetProxy); methodSetProxy.setAccessible(true); methodSetProxy.invoke(activityInstance, this); //invoke onCreate Method onCreate = actClazz.getDeclaredMethod("onCreate", new Class[]{Bundle.class}); onCreate.setAccessible(true); Log.e(TAG, "onCreate = " + onCreate); Bundle bundle = new Bundle(); bundle.putInt(KEY_FROM_EXTERNAL, VALUE_FROM_EXTERNAL); onCreate.invoke(activityInstance, new Object[]{bundle}); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } private void launchTargetActivity() { //getPackageManager for activity PackageManager pm = getPackageManager(); PackageInfo packageInfo = pm.getPackageArchiveInfo(mApkPath, PackageManager.GET_ACTIVITIES); ActivityInfo[] activities = packageInfo.activities; if (activities != null && activities.length > 0) { String activityClazz = activities[0].name; Log.e(TAG, "ActivityClazz = " + activityClazz); mTargetActivityClazz = activityClazz; launchTargetActivity(activityClazz); } } @Override public ClassLoader getClassLoader() { return mDexClassLoader; } @Override public AssetManager getAssets() { return mAssetManager == null ? super.getAssets() : mAssetManager; } @Override public Resources getResources() { return mResources == null ? super.getResources() : mResources; } }