zoukankan      html  css  js  c++  java
  • 换肤-插件化

    --摘自《android插件化开发指南》

    fork了强哥的github代码到自己的github下 https://github.com/king1039/Dynamic3

    将代码跑起来,Plugin1和Plugin2打成apk放到HostApp的assets下

    贴下主要代码

    public class BaseActivity extends Activity {
    
        private AssetManager mAssetManager;
        private Resources mResources;
        private Resources.Theme mTheme;
    
        protected HashMap<String, PluginInfo> plugins = new HashMap<String, PluginInfo>();
    
        @Override
        protected void attachBaseContext(Context newBase) {
            super.attachBaseContext(newBase);
    
            Utils.extractAssets(newBase, "plugin1.apk");
            Utils.extractAssets(newBase, "plugin2.apk");
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            genegatePluginInfo("plugin1.apk");
            genegatePluginInfo("plugin2.apk");
        }
    
        protected void genegatePluginInfo(String pluginName) {
            File extractFile = this.getFileStreamPath(pluginName);
            File fileRelease = getDir("dex", 0);
            String dexpath = extractFile.getPath();
            DexClassLoader classLoader = new DexClassLoader(dexpath, fileRelease.getAbsolutePath(), null, getClassLoader());
    
            plugins.put(pluginName, new PluginInfo(dexpath, classLoader));
        }
    
        protected void loadResources(String dexPath) {
            try {
                AssetManager assetManager = AssetManager.class.newInstance();
                Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
                addAssetPath.invoke(assetManager, dexPath);
                mAssetManager = assetManager;
            } catch (Exception e) {
                e.printStackTrace();
            }
            Resources superRes = super.getResources();
            mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());
            mTheme = mResources.newTheme();
            mTheme.setTo(super.getTheme());
        }
    
        @Override
        public AssetManager getAssets() {
            return mAssetManager == null ? super.getAssets() : mAssetManager;
        }
    
        @Override
        public Resources getResources() {
            return mResources == null ? super.getResources() : mResources;
        }
    
        @Override
        public Resources.Theme getTheme() {
            return mTheme == null ? super.getTheme() : mTheme;
        }
    }
    public class ResourceActivity extends BaseActivity {
    
        /**
         * 需要替换主题的控件
         * 这里就列举三个:TextView,ImageView,LinearLayout
         */
        private TextView textV;
        private ImageView imgV;
        private LinearLayout layout;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_resource);
    
            textV = (TextView) findViewById(R.id.text);
            imgV = (ImageView) findViewById(R.id.imageview);
            layout = (LinearLayout) findViewById(R.id.layout);
    
            findViewById(R.id.btn1).setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View arg0) {
                    PluginInfo pluginInfo = plugins.get("plugin1.apk");
    
                    loadResources(pluginInfo.getDexPath());
    
                    doSomething(pluginInfo.getClassLoader());
                }
            });
    
            findViewById(R.id.btn2).setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    PluginInfo pluginInfo = plugins.get("plugin2.apk");
    
                    loadResources(pluginInfo.getDexPath());
    
                    doSomething(pluginInfo.getClassLoader());
                }
            });
        }
    
        private void doSomething(ClassLoader cl) {
            try {
                Class clazz = cl.loadClass("jianqiang.com.plugin1.UIUtil");
    
                String str = (String) RefInvoke.invokeStaticMethod(clazz, "getTextString", Context.class, this);
                textV.setText(str);
    
                Drawable drawable = (Drawable) RefInvoke.invokeStaticMethod(clazz, "getImageDrawable", Context.class, this);
                imgV.setBackground(drawable);
    
                layout.removeAllViews();
                View view = (View) RefInvoke.invokeStaticMethod(clazz, "getLayout", Context.class, this);
                layout.addView(view);
    
            } catch (Exception e) {
                Log.e("DEMO", "msg:" + e.getMessage());
            }
        }
    }

    简单来说,就是针对不同的apk生成不同的ClassLoader,然后通过反射框架取出相应的资源,最终加载显示

    doSomething还有另外一个种写法,直接访问R.java的内部类drawable/string/layout中的相应字段对应的十六进制值(这个好屌)

    private void doSomething(ClassLoader cl) {
        try {
            Class stringClass = cl.loadClass("jianqiang.com.plugin1.R$string");
            int resId1 = (int) RefInvoke.getStaticFieldObject(stringClass, "hello_message");
            textV.setText(getResources().getString(resId1));
    
    
            Class drawableClass = cl.loadClass("jianqiang.com.plugin1.R$drawable");
            int resId2 = (int) RefInvoke.getStaticFieldObject(drawableClass, "robert");
            imgV.setBackground(getResources().getDrawable(resId2));
    
            Class layoutClazz = cl.loadClass("jianqiang.com.plugin1.R$layout");
            int resId3 = (int) RefInvoke.getStaticFieldObject(layoutClazz, "main_activity");
            View view = (View) LayoutInflater.from(this).inflate(resId3, null);
            layout.removeAllViews();
            layout.addView(view);
    
        } catch (Exception e) {
            Log.e("DEMO", "msg:" + e.getMessage());
        }
    }

    总的来说,资源插件化就是通过反射AssetManager和addAssetPath来加载插件资源

    欢迎关注我的微信公众号:安卓圈

  • 相关阅读:
    android getContext()
    android DB notify
    android 调用系统截图
    调用新浪微博客户端发送图片
    Hadoop 面试 小结
    HADOOP 安装HIVE
    ORACLE ArcSDE Lock request conflicts with an established lock
    OBIEEClusterControler通信的问题
    ORACLE RAC 集群的启动和关闭
    HADOOP 配置Tip 配置hadoop.tmp.dir
  • 原文地址:https://www.cnblogs.com/anni-qianqian/p/10103350.html
Copyright © 2011-2022 走看看