• Android笔记(二十三):以插件化APK方式启动带WebView的Activity


    背景

    本文记录插件化学习过程中,如何以插件化apk方式启动带WebView的Activity,分三大步骤完成。

    步骤

    解决插件Activity启动问题

    • 目前有以下三种实现Activity插件化的方案:
      • 通过反射实现,会影响性能。

      • 通过接口实现,dynamic-load-apk的实现原理。

      • 通过Hook技术实现,本文采用此方式实现。

        • 一般Hook技术有两种Hook点选择:
          1. Hook IActivityManager
          2. Hook Instrumentation,本文采用此选择
    1. 在Application onCreate调用以下代码,反射设置ProxyInstrumentation hook系统的Instrumentation
    public class HookUtils {
       
        public static void executeInstrumentationHook(Context context){
       
            try {
       
                Class<?> activityThreadClass=Class.forName("android.app.ActivityThread");
                Field activityThreadField=activityThreadClass.getDeclaredField("sCurrentActivityThread");
                activityThreadField.setAccessible(true);
                //获取ActivityThread对象sCurrentActivityThread
                Object activityThread=activityThreadField.get(null);
    			Field instrumentationField=activityThreadClass.getDeclaredField("mInstrumentation");
                instrumentationField.setAccessible(true);
                //从sCurrentActivityThread中获取成员变量mInstrumentation
                Instrumentation instrumentation= (Instrumentation) instrumentationField.get(activityThread);
                //创建代理对象InstrumentationProxy
                ProxyInstrumentation proxy = new ProxyInstrumentation(instrumentation, context.getPackageManager());
                //将sCurrentActivityThread中成员变量mInstrumentation替换成代理类InstrumentationProxy
                instrumentationField.set(activityThread,proxy);
            } catch (NoSuchFieldException e) {
       
                e.printStackTrace();
            } catch (IllegalAccessException e) {
       
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
       
                e.printStackTrace();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    1. ProxyInstrumentation要做的两件事:先用占坑的Activity去骗AMS;启动运行时,在将目标Activity替换掉占坑的Activity的。
    public class ProxyInstrumentation extends Instrumentation {
       
        private final Instrumentation instrumentation;
        private final PackageManager mPackageManager;
    
        public ProxyInstrumentation(Instrumentation instrumentation, PackageManager mPackageManager){
       
            this.instrumentation = instrumentation;
            this.mPackageManager = mPackageManager;
        }
    
    
        public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,
                                                Intent intent, int requestCode, Bundle options){
       
            List<ResolveInfo> infos = mPackageManager.queryIntentActivities(intent, 0);
            if (infos == null || infos.size() == 0) {
       
            	//Hook成功,执行了startActivity
                intent.putExtra("TARGET_INTENT_NAME",intent.getComponent().getClassName());
                // 将要送去AMS验证的Activity换成占坑的
                intent.setClassName(who,"ProxyActivity完整路径");
            }
                try {
       
                    Method execStartActivity = Instrumentation.class.getDeclaredMethod("execStartActivity", Context.class, IBinder.class, IBinder.class, Activity.class, Intent.class, int.class, Bundle.class);
                    return (ActivityResult) execStartActivity.invoke(instrumentation, who, contextThread, token, target, intent, requestCode, options);
                } catch (Exception e) {
       
                    e.printStackTrace();
                }
    
            return 
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
  • 相关阅读:
    pytorch加载的cifar10数据集,到底有没有经过归一化
    池式结构:对象池(Object Pool)
    学SLAM的女生,很酷
    30天啃透这份Framework 源码手册直接面进大厂
    装饰器模式 —— mybatis
    DP4054H完全兼容替代TP4054 36V 耐压 500mA 线性锂电充电芯片
    ros数据转换
    Redis 6.0 新功能
    [附源码]java毕业设计校园疫情防控管理系统
    SpringMVC_执行流程
  • 原文地址:https://blog.csdn.net/weixin_40855673/article/details/128015348