美文网首页面试储备资料
插件化、组件化?what?

插件化、组件化?what?

作者: 代码界的泥石流 | 来源:发表于2018-04-04 11:16 被阅读13次
    • 组件化?

    组件化想要解决的问题:
    1.实际业务变化非常快,但是工程之前的业务模块耦合度太高,牵一发而动全身.
    2.对工程所做的任何修改都必须要编译整个工程
    3.功能测试和系统测试每次都要进行.
    4.团队协同开发存在较多的冲突.不得不花费更多的时间去沟通和协调,并且在
    5.开发过程中,任何一位成员没办法专注于自己的功能点,影响开发效率.
    6.不能灵活的对工程进行配置和组装.比如今天产品经理说加上这个功能,明天又说去掉,后天在加上.
    (组件化 各个组件之间互相依赖,没办法并发开发)。
    
    
    image.png
    image.png

    挂载到组件总线上的业务组件,都可以实现双向通信.而通信协议和HTTP通信协议类似,即基于URL的方式进行.

    • 插件化?

    Android文件在编译期会通过javac命令编译成.class文件,最后再把所有的.class文件编译成.dex文件放在.apk包里面。那么动态加载就是在运行时把插件apk直接加载到classloader里面的技术。

    关于代码加载,系统提供了DexClassLoader来加载插件代码。开发者可以对每一个插件分配一个DexClassLoader(这是目前最常见的一种方式),也可以动态得把插件加载到当前运行环境的classloader中。

    相对于组件化开发主要要解决的问题:

    • 插件化的解决了什么问题?

      1.宿主和插件分开编译
      2.并发开发
      3.动态更新插件
      4.按需下载模块
      5.方法数或变量数爆棚

    • 实现插件化加载:
      插件化加载 就是加载一个APK,将父类APP(宿主)的界面显示子类APP的界面,类似一个空的Activity给想要显示的其他子App的Activity预留的,实现逻辑:获取界面的所有包含Acivity的方法,并重写,因为子类APP未被安装所以没有Acitivity的引用。(宿主定义规则,子类APP去实现)
      宿主APP重写ClassLoader为DexClassLoader和Resouce(AssestManager)和PackageManager去读取外部APK资源。在跳转一个显示子类APP界面的Activity,反射成Activity对象。然后做其他操作。

    //Activitiy必须重写的规则接口类
    public interface PayInterfaceActivity {
        public void attach(Activity proxyActivity);
    
        /**
         * 生命周期
         * @param savedInstanceState
         */
        public void onCreate(Bundle savedInstanceState);
        public void onStart();
        public void onResume();
        public void onPause();
        public void onStop();
        public void onDestroy();
        public void onSaveInstanceState(Bundle outState);
        public boolean onTouchEvent(MotionEvent event);
        public void onBackPressed();
    }
    

    这个类用来读取外部资源的

    public class PluginManager {
        private PackageInfo packageInfo;
        private Resources resources;
        private Context context;
        private DexClassLoader dexClassLoader;
        private static final PluginManager ourInstance = new PluginManager();
    
        public static PluginManager getInstance() {
            return ourInstance;
        }
    
        private PluginManager() {
        }
    
        public void setContext(Context context) {
            this.context = context;
        }
    
    
        public void loadPath(Context context) {
            //获取APK路径
            File filesDir = context.getDir("plugin", Context.MODE_PRIVATE);
            String name = "pluginb.apk";
            String path = new File(filesDir, name).getAbsolutePath();
            //pakckageInfo是用来获取APK的包的activity
            PackageManager packageManager=context.getPackageManager();
            packageInfo=packageManager.getPackageArchiveInfo(path,PackageManager.GET_ACTIVITIES);
    
    
    //        activity 实例化dexClassLoader  用来加载外部布局的
            File dexOutFile = context.getDir("dex", Context.MODE_PRIVATE);
            dexClassLoader = new DexClassLoader(path, dexOutFile.getAbsolutePath()
                    , null, context.getClassLoader());
    //        resource 用来加载外部资源的
    
            try {
                AssetManager assetManager = AssetManager.class.newInstance();
    
                Method addAssetPath=AssetManager.class.getMethod("addAssetPath", String.class);
                addAssetPath.invoke(assetManager, path);
                resources = new Resources(assetManager, context.getResources().getDisplayMetrics(), context.getResources().getConfiguration());
            } catch ( Exception e) {
                e.printStackTrace();
            }
             }
    
        public Resources getResources() {
            return resources;
        }
    
        public DexClassLoader getDexClassLoader() {
            return dexClassLoader;
        }
    
        public PackageInfo getPackageInfo() {
            return packageInfo;
        }
    }
    

    加载插件的代码

     private void loadPlugin() {
            File filesDir = this.getDir("plugin", Context.MODE_PRIVATE);
            String name = "pluginb.apk";
            String filePath = new File(filesDir, name).getAbsolutePath();
            File file = new File(filePath);
            if (file.exists()) {
                file.delete();
            }
            InputStream is = null;
            FileOutputStream os = null;
            try {
                Log.i(TAG, "加载插件 " + new File(Environment.getExternalStorageDirectory(), name).getAbsolutePath());
                is = new FileInputStream(new File(Environment.getExternalStorageDirectory(), name));
                os = new FileOutputStream(filePath);
                int len = 0;
                byte[] buffer = new byte[1024];
                while ((len = is.read(buffer)) != -1) {
                    os.write(buffer, 0, len);
                }
                File f = new File(filePath);
                if (f.exists()) {
                    Toast.makeText(this, "dex overwrite", Toast.LENGTH_SHORT).show();
                }
                PluginManager.getInstance().loadPath(this);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                try {
                    os.close();
                    is.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    

    子类必须做的事情,将所包含Activity的引用方法,重写成使用父类Activity的引用

    public class BaseActivity  extends Activity implements PayInterfaceActivity {
    
    
        protected  Activity that;
        @Override
        public void attach(Activity proxyActivity) {
            this.that = proxyActivity;
        }
    
    
        @Override
        public void setContentView(View view) {
            if (that != null) {
                that.setContentView(view);
            }else {
                super.setContentView(view);
            }
        }
    
        @Override
        public void setContentView(int layoutResID) {
            that.setContentView(layoutResID);
        }
    
        @Override
        public ComponentName startService(Intent service) {
            Intent m = new Intent();
            m.putExtra("serviceName", service.getComponent().getClassName());
            return that.startService(m);
        }
    
        @Override
        public View findViewById(int id) {
            return that.findViewById(id);
        }
    
        @Override
        public Intent getIntent() {
            if(that!=null){
                return that.getIntent();
            }
            return super.getIntent();
        }
        @Override
        public ClassLoader getClassLoader() {
            return that.getClassLoader();
        }
    
    
        @Override
        public void startActivity(Intent intent) {
    //        ProxyActivity --->className
            Intent m = new Intent();
            m.putExtra("className", intent.getComponent().getClassName());
            that.startActivity(m);
        }
    
        @NonNull
        @Override
        public LayoutInflater getLayoutInflater() {
            return that.getLayoutInflater();
        }
    
        @Override
        public ApplicationInfo getApplicationInfo() {
            return that.getApplicationInfo();
        }
    
    
        @Override
        public Window getWindow() {
            return that.getWindow();
        }
    
    
        @Override
        public WindowManager getWindowManager() {
            return that.getWindowManager();
        }
    
    
    
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
    
        }
    
        @Override
        public void onStart() {
    
        }
    
        @Override
        public void onResume() {
    
        }
    
        @Override
        public void onPause() {
    
        }
    
        @Override
        public void onStop() {
    
        }
    
        @Override
        public void onDestroy() {
    
        }
    
        @Override
        public void onSaveInstanceState(Bundle outState) {
    
        }
    

    接下来就是我们显示子界面的关键代码:

    /**
     * Created by Administrator on 2018/3/28.
     * 举例 这个界面是要显示的插件界面
     */
    
    public class ProxyActivity extends Activity {
        //    需要加载淘票票的  类名
        private String className;
        PayInterfaceActivity payInterfaceActivity;
    
        // com.dongnao.alvin.taopiaopiao.MainActivity
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            className = getIntent().getStringExtra("className");
    //        class 拿到类名  注意这里没办法是通过反射拿到全类名的因为 此插件未被打包至APK中
    //想要加载 必须重写classLoader和getResurce  因为我们想要她能访问外部卡的ClassLoader和resourece不是对内而是对外
            try {
                Class activityClass = getClassLoader().loadClass(className);
                Constructor constructor = activityClass.getConstructor(new Class[]{});
                Object instance = constructor.newInstance(new Object[]{});
    //          可以
                payInterfaceActivity = (PayInterfaceActivity) instance;
    
                payInterfaceActivity.attach(this);
                Bundle bundle = new Bundle();
                payInterfaceActivity.onCreate(bundle);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void startActivity(Intent intent) {
            String className1 = intent.getStringExtra("className");
            Intent intent1 = new Intent(this, ProxyActivity.class);
            intent1.putExtra("className", className1);
            super.startActivity(intent1);
        }
    
        @Override
        public ComponentName startService(Intent service) {
            String serviceName = service.getStringExtra("serviceName");
            Intent intent1 = new Intent(this, ProxyService.class);
            intent1.putExtra("serviceName", serviceName);
            return super.startService(intent1);
        }
    
        @Override
        public ClassLoader getClassLoader() {
            return PluginManager.getInstance().getDexClassLoader();
        }
    
        @Override
        public Resources getResources() {
            return PluginManager.getInstance().getResources();
        }
    
    
        @Override
        protected void onStart() {
            super.onStart();
            payInterfaceActivity.onStart();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            payInterfaceActivity.onDestroy();
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            payInterfaceActivity.onPause();
        }
    

    OK,Demo地址:https://pan.baidu.com/s/1RNufM9C2MmmwhJdoCYgZow 密码:b4ak

    相关文章

      网友评论

        本文标题:插件化、组件化?what?

        本文链接:https://www.haomeiwen.com/subject/bbsthftx.html