zoukankan      html  css  js  c++  java
  • 资源的插件化

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

    1.android资源文件分为两类:

    第一类是res目录下存放的可编译资源文件,编译时,系统会自动在R.java中生成资源文件的十六进制值

    Resources resources = getResources();
    String appName = resources.getString(R.string.app_name);               

    第二类是assets目录下存放的原始资源文件,apk在编译时不会编译assets下的资源文件

    Resources resources = getResources();
    AssetManager am = getResources().getAssets();
    InputStream is = getResources().getAssets().open("filename");

    2.Resources内部各种方法其实都是间接调用AssetManager的内部方法。AssetManager的addAssetPath方法会在app启动的时候把当前apk的路径传进去,就能访问apk的所有资源了。在这里可以把插件apk的资源塞进去

    3.apk打包时会生成一个resource.arsc文件,它就是一个Hash表,存放着每个十六进制值和资源的对应关系

    ***资源的插件化解决方案***

    public class Dynamic implements IDynamic {
    
        @Override
        public String getStringForResId(Context context) {
            return context.getResources().getString(R.string.myplugin1_hello_world);
        }
    }
    <resources>
        <string name="app_name">Plugin1</string>
        <string name="myplugin1_hello_world">myplugin1_hello_world</string>
    </resources>
    public class BaseActivity extends Activity {
    
        private AssetManager mAssetManager;
        private Resources mResources;
        private Resources.Theme mTheme;
        private String dexpath = null;    //apk文件地址
        private File fileRelease = null;  //释放目录
    
        protected DexClassLoader classLoader = null;
    
        private String pluginName = "plugin1.apk";
    
        TextView tv;
    
        @Override
        protected void attachBaseContext(Context newBase) {
            super.attachBaseContext(newBase);
    
            Utils.extractAssets(newBase, pluginName);
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //第三步:加载外部的插件,生成插件对应的ClassLoader
            File extractFile = this.getFileStreamPath(pluginName);
            dexpath = extractFile.getPath();
    
            fileRelease = getDir("dex", 0);
    
            classLoader = new DexClassLoader(dexpath, fileRelease.getAbsolutePath(), null, getClassLoader());
        }
    
        /**
         * 第一步:通过反射,创建AssetManager对象,调用addAssetPath方法,把插件Plugin的路径添加到这个AssetManager对象中
         **/
        protected void loadResources() {
            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();
            superRes.getDisplayMetrics();
            superRes.getConfiguration();
            mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());
            mTheme = mResources.newTheme();
            mTheme.setTo(super.getTheme());
        }
    
        /**
         * 第二步:重写Acitivity的getAsset,getResources和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 MainActivity extends BaseActivity {
        TextView tv;
    
        @SuppressLint("NewApi")
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Button btn_6 = (Button) findViewById(R.id.btn_6);
    
            tv = (TextView)findViewById(R.id.tv);
    
            //带资源文件的调用
            btn_6.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View arg0) {
                    loadResources();
                    Class mLoadClassDynamic = null;
                    try {
                        //第四步:通过反射,获取插件中的类,构造出插件类的对象dynamicObject,然后就可以让插件中的类读取插件中的资源了
                        mLoadClassDynamic = classLoader.loadClass("jianqiang.com.plugin1.Dynamic");
                        Object dynamicObject = mLoadClassDynamic.newInstance();
    
                        IDynamic dynamic = (IDynamic) dynamicObject;
                        String content = dynamic.getStringForResId(MainActivity.this);
                        tv.setText(content);
                        Toast.makeText(getApplicationContext(), content + "", Toast.LENGTH_LONG).show();
                    } catch (Exception e) {
                        Log.e("DEMO", "msg:" + e.getMessage());
                    }
                }
            });
        }
    }

    还有换肤

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

  • 相关阅读:
    如何获得RVA(相对虚地址)的值,从而得到一个程序的入口点
    Prism 问题总结一: 在模块中引用公用程序集出错
    Dapper 操作 ACCESS 数据库问题总结
    我国土地招拍挂制度
    [导入]棋味
    [导入]无语
    [导入]心灯
    [导入]寄托
    [导入]视频资源
    [导入]asp.net实现视频截图
  • 原文地址:https://www.cnblogs.com/anni-qianqian/p/10103110.html
Copyright © 2011-2022 走看看