美文网首页面试储备资料
插件化、组件化?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?

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

  • Android:插件化

    插件化组件化 组件化与插件化的区别 组件化是Android自然提供的,例如分成lib,test组件。插件化是热更新...

  • 模块化、组件化与插件化(1)

    模块化、组件化与插件化 组件化 modularization、component 模块化 modularizati...

  • 插件化介绍和原理解析

    什么是插件化 首先我们区分一下组件化和插件化的概念 组件化组件化开发就是将一个app分成多个模块,组件化强调功能拆...

  • Android插件化(一)

    插件化(一) 组件化和插件化的区别: 组件化是将一个app分成多个模块,每个模块都是一个组件(module),开发...

  • 移动架构<第十二篇>:Android组件化架构

    模块化、组件化、插件化是当前Android工程的三大架构,市场上组件化和插件化使用最为广泛。起初,Android工...

  • Android快速迭代设计与实践

    目录 基础建设 基础建设 组件化,插件化,跨平台,壳view组件化:便于修改,提供其它APP使用;插件化:各个业务...

  • Android组件化 - gradle配置(一)

    一、什么是组件化 什么是组件化呢? 组件化、插件化、模块化之间有什么区别呢? 组件化:每个组件都是独立的功能模块,...

  • Android组件化和插件化开发

    Android组件化和插件化开发 什么是组件化和插件化? 组件化开发 就是将一个app分成多个模块,每个模块都是一...

  • Android-第三方开源框架—插件化原理之Activity插件

    前言 四大组件的插件化是插件化技术的核心知识点,而Activity插件化更是重中之重,Activity插件化主要有...

网友评论

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

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