Android组件化、插件化详细讲解

2022-07-15 09:44:46
目录
什么是组件化(通俗易懂)反射的写法反射的⽬的关于DEX:插件化原理:动态加载问题⼀:未注册的组件(例如Activity)不能打开问题⼆:资源⽂件⽆法加载插件化有什么用?

什么是组件化(通俗易懂)

通俗易懂来讲就是,拆成多个module开发就是组件化。

App的部分功能模块在打包时并不以传统⽅式打包进apk⽂件中,⽽是以另⼀种形式⼆次封装进apk内部,或者放在⽹络上适时下载,在需要的时候动态对这些功能模块进⾏加载,称之为插件化。这些单独⼆次封装的功能模块apk,就称作插件,初始安装的apk称作宿主。插件化是组件化的更进⼀步推进。

插件化基础之反射:

反射的写法

    try {
            Class utilClass = Class.forName("com.hencoder.demo.hidden.Util");
            Constructor utilConstructor = utilClass.getDeclaredConstructors()[0];
            utilConstructor.setAccessible(true);
            Object util = utilConstructor.newInstance();
            Method shoutMethod = utilClass.getDeclaredMethod("shout");
            shoutMethod.setAccessible(true);
            shoutMethod.invoke(util);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

反射的⽬的

Java既然提供了可⻅性关键字public、private等等,⽤来限制代码之间的可⻅性,为什么⼜要提供反射功能?可⻅性特性的⽀持不是为了代码不被坏⼈使⽤,⽽是为了程序开发的简洁性。安全性的话,可⻅性的⽀持提供的是Safety>

关于DEX:

    class:java编译后的⽂件,每个类对应⼀个class⽂件dex:Dalvik>odex:Optimized DEX针对系统的优化,例如某个⽅法的调⽤指令,会把虚拟的调⽤转换为使⽤具体的index,这样在执⾏的时候就不⽤再查找了oat:Optimized Androidfile Type。使⽤AOT策略对dex预先编译(解释)成本地指令,这样再运⾏阶段就不需再经历⼀次解释过程,程序的运⾏可以更快AOT:Ahead-Of-Time compilation预先编译

    插件化原理:动态加载

    通过⾃定义ClassLoader来加载新的dex⽂件,从⽽让程序员原本没有的类可以被使⽤,这就是插件化的原理。

    例如:把Utils拆到单独的项⽬,打包apk作为插件引⼊:

     File f = new File(getCacheDir() + "/demo-debug.apk");
            if (!f.exists()) {
                try { 
                    InputStream is = getAssets().open("apk/demo-debug.apk");
                    int size = is.available();
                    byte[] buffer = new byte[size];
                    is.read(buffer);
                    is.close();
                    FileOutputStream fos = new FileOutputStream(f);
                    fos.write(buffer);
                    fos.close();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        DexClassLoader classLoader = new DexClassLoader(f.getPath(),
        getCodeCacheDir().getPath(), null, null);
          try {
                Class oldClass = classLoader.loadClass("com.hencoder.demo.hidden.Util");
                Constructor utilConstructor = oldClass.getDeclaredConstructors()[0];
                utilConstructor.setAccessible(true);
                Object util = utilConstructor.newInstance();
                Method shoutMethod = oldClass.getDeclaredMethod("shout");
                shoutMethod.setAccessible(true);
                shoutMethod.invoke(util);
                Class activityClass = classLoader.loadClass("com.hencoder.demo.MainActivity");
                startActivity(new Intent(this, activityClass));
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }

    问题⼀:未注册的组件(例如Activity)不能打开

      解决⽅式⼀:代理Activity解决⽅式⼆:欺骗系统解决⽅式三:重写gradle打包过程,合并AndroiManifest.xml

      问题⼆:资源⽂件⽆法加载

      解决⽅式:⾃定义AssetManager和Resources对象

         private AssetManager createAssetManager (String dexPath) {
              try {
                  AssetManager assetManager = AssetManager.class.newInstance();
                  Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
                  addAssetPath.invoke(assetManager, dexPath);
                  return assetManager;
              } catch (Exception e) {
                  e.printStackTrace();
                  return null;
              }
          }
      private Resources createResources(AssetManager assetManager) {
              Resources superRes = mContext.getResources();
              Resources resources = new Resources(assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());
              return resources;
          }

      插件化有什么用?

        早期:解决dex>懒加载来减少软件启动速度:有可能,实质上未必会快减⼩安装包⼤⼩:可以项⽬结构拆分,依赖完全隔离,⽅便多团队开发和测试,解决了组件化耦合度太⾼的问题:这个使⽤模块化就够了,况且模块化解耦不够的话,插件化也解决不了这个问题动态部署:可以热修复:可以

        到此这篇关于Android组件化、插件化详细讲解的文章就介绍到这了,更多相关Android组件化,插件化内容请搜索易采站长站以前的文章或继续浏览下面的相关文章希望大家以后多多支持易采站长站!