动态加载APK

宿主程序提供一个代理Activity:

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);
        
        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 = localClass.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});

			//手动执行远程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(mRemoteActivity, 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);
    }
}

远程Activity在宿主程序看来就是一个普通的类,并不具有生命周期,所以需要在ProxyActivity中生命周期方法中手动调用远程Activity的生命周期方法;
另外可以考虑使用Fragment来实现页面,因为ProxyActivity会自动管理Fragment的生命周期,不用手动通过反射去调用;

插件程序实现:
首先创建一个BaseActivity:

public class BaseActivity extends Activity {

    public static final String FROM = "extra.from";
    public static final int FROM_INTERNAL = 1;

    protected Activity mProxyActivity;
    protected int mFrom = FROM_INTERNAL;
 
    public void setProxy(Activity proxyActivity) {
        mProxyActivity = proxyActivity;
    }
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        if (savedInstanceState != null) {
            mFrom = savedInstanceState.getInt(FROM, FROM_INTERNAL);
        }
        if (mFrom == FROM_INTERNAL) {
            super.onCreate(savedInstanceState);
            mProxyActivity = this;
        }
    }
 
    @Override
    public void setContentView(View view) {
        if (mProxyActivity == this) {
            super.setContentView(view);
        } else {
            mProxyActivity.setContentView(view);
        }
    }
 
    @Override
    public void setContentView(View view, LayoutParams params) {
        if (mProxyActivity == this) {
            super.setContentView(view, params);
        } else {
            mProxyActivity.setContentView(view, params);
        }
    }
 
    @Override
    public void addContentView(View view, LayoutParams params) {
        if (mProxyActivity == this) {
            super.addContentView(view, params);
        } else {
            mProxyActivity.addContentView(view, params);
        }
    }
}

创建入口Activity:

public class MainActivity extends BaseActivity {
    private static final String TAG = "Client-MainActivity";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       mProxyActivity.setContentView(new LinearLayout(context));
    }
    
	@Override
    protected void onResume() {
        super.onResume(savedInstanceState);
        Log.e("ClientMainActivity","onResumeTest");
    }
}

然后记得在宿主程序动态申请sd卡权限否则调用不会成功
将这个程序打包成APK放在sd卡根目录下,在宿主程序中执行打开ProxyActivity,发现程序跳转到了插件程序页面

参考:
https://blog.csdn.net/singwhatiwanna/article/details/22597587

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值