动态加载第三方activity笔记(1)--加载三方页面

来源:互联网 发布:追英剧用什么软件 编辑:程序博客网 时间:2024/05/21 20:24

最近一直没有写博客,本着罪恶感,写一篇吧。

这个功能最近项目中使用到了,因为代码比较臃肿,不是很方便。所以选择插件话,功能本社类似支付宝里面的共享单车等app加载功能。好处具体不说了,直接说下思路吧。

我的工程是app,想要加载的插件是plugin.apk。安卓机制是想要打开的activity必须进行注册才可以使用,那么怎么能加载第三方apk的activity呢?这里引入一个代理的proxyactivity,在app工程里面进行注册,所以我可直接进行使用proxyactivity,根据dexClassLoader加载class文件和反射机制,将pugin.apk资源文件和class文件都进行获取,值得注意的是plugin.apk的activity是没有生命周期的,所以要进行模拟生命周期,即在proxyactivity的onStart()方法里面同时给这个activity赋予声明周期信息。




好了,说下具体的思路吧,插件apk需要有一个标准接口,这个接口实现了生命周期。

public interface PluginInterface {    public void attach(Activity ProxyActivity);//用来注册上下文    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 {    final String TAG = "PluginManager";    private Context context;    private DexClassLoader dexClassLoader;//加载外置卡class    private static PluginManager instance;    private Resources resources;    public String entryName ;//入口    private PluginManager(Context con){        context = con.getApplicationContext();    }    public static PluginManager getInstance(Context con){        if(instance == null){            instance = new PluginManager(con);        }        return instance;    }    public static PluginManager getInstance(){        if(instance == null){             throw new RuntimeException("实例化需要包含参数");        }        return instance;    }    public DexClassLoader getDexClassLoader() {        return dexClassLoader;    }    public Resources getResources() {        return resources;    }    //加载apk的路径    //获得dexClassLoader和resources    public void setPath(String path){        File dexOutFile = context.getDir("dex",Context.MODE_PRIVATE);//缓存路径        dexClassLoader = new DexClassLoader(path,dexOutFile.getAbsolutePath(),                null,context.getClassLoader());        PackageManager packageManager = context.getPackageManager();        PackageInfo packageInfo = packageManager.getPackageArchiveInfo(path,PackageManager.GET_ACTIVITIES);        entryName = packageInfo.activities[0].name;        try {            AssetManager assetManager = AssetManager.class.newInstance();            //反射给assetManager路径,参数是string类型            Method addAssetPath = AssetManager.class.getMethod("addAssetPath",String.class);            addAssetPath.invoke(assetManager,path);            resources = new Resources(assetManager,                    context.getResources().getDisplayMetrics(),context.getResources().getConfiguration());        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (NoSuchMethodException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        }    }    public String getEntryName(){        Log.i(TAG, "getEntryName: "+entryName);        return  entryName;    }}

配置信息完成后,插件需要实现接口信息,这里用BaseAcitivity,还需要重写setContentView,
findViewById,getClassLoader,getResources,getLayoutInflater,getWindow,getWindowManager等包含上下文的内容并且进行
置换。这个过程就不进行描述了。
接下来进行proxyactivity的实现。
这里需要重写getResources和getClassLoader方法,获得PluginManager 的即可。这里要赋给插件生命周期,这里是重点注意的地方。
public class ProxyActivity extends Activity {    //替换插件app里面activity类名    String className;    PluginInterface pluginInterface;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Intent intent = getIntent();        className = intent.getStringExtra("className");        launchAcitivity();    }    @Override    protected void onStart() {        super.onStart();        pluginInterface.onStart();    }    @Override    protected void onResume() {        super.onResume();        pluginInterface.onResume();    }    @Override    protected void onPause() {        super.onPause();        pluginInterface.onPause();    }    @Override    protected void onDestroy() {        super.onDestroy();        pluginInterface.onDestroy();    }    @Override    protected void onStop() {        super.onStop();        pluginInterface.onStop();    }    @Override    public ClassLoader getClassLoader() {       return PluginManager.getInstance().getDexClassLoader();      //  return super.getClassLoader();    }    //通过反射加载外置apk class文件    private void launchAcitivity() {        try {            Class<?> loadClass = PluginManager.getInstance().getDexClassLoader().loadClass(className);            Constructor constructor = loadClass.getConstructor(new Class[]{});            Object instance = constructor.newInstance(new Class[]{});            pluginInterface = (PluginInterface) instance;            pluginInterface.attach(this);            Bundle bundle = new Bundle();            //用来传递信息            pluginInterface.onCreate(bundle);            /*            * 定义标准            *            * 实现生命周期            * */        } 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();        }    }    @Override    public Resources getResources() {        return PluginManager.getInstance().getResources();    }}

即将完成了,写一个测试按钮,实现加载class和资源
public void addAcitivity(View view){    Log.i(TAG, "addAcitivity: ");    File file  = new File(Environment.getExternalStorageDirectory(),"Plugin.apk");    PluginManager.getInstance(this).setPath(file.getAbsolutePath());}public void jumpAcitivity(View view){    Log.i(TAG, "jumpAcitivity: ");    Intent intent = new Intent(this, ProxyActivity.class);    intent.putExtra("className",PluginManager.getInstance().getEntryName());    startActivity(intent);}
同时记得将插件apk放到sd卡里面,这样就完成了。之后我会将代码上传。如有好的方法请联系我。
资源地址http://download.csdn.net/download/lixuesong13/10121561


原创粉丝点击