动态加载第三方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();资源地址http://download.csdn.net/download/lixuesong13/10121561}实现一个插件管理类,这个类用来获得插件的资源信息等,这里属于重点,需要了解反射等知识。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卡里面,这样就完成了。之后我会将代码上传。如有好的方法请联系我。
阅读全文
0 0
- 动态加载第三方activity笔记(1)--加载三方页面
- 动态加载第三方字库
- 第三方加载图片
- 第三方加载图片
- 加载第三方图片
- QT 加载第三方库
- python 加载第三方库
- codeIgniter加载第三方库
- android 加载第三方库
- 图片加载 第三方 KVO
- 第三方图片加载库
- iOS 加载第三方字体
- 第三方图片加载ImageLoader
- UE4 加载第三方库
- 如何加载第三方js
- 加载第三方Js减少页面渲染时间
- cmake 入门编程之动态加载第三方库
- Android动态加载第三方APK的View研究过程
- BIOS设置通电开机?请问高手怎么设置?
- java并发-线程的创建和运行(2)
- hive字符串基础解析函数
- 动网论坛 上传文件类型
- SqlLite创建数据库
- 动态加载第三方activity笔记(1)--加载三方页面
- Java序列化与反序列化
- XSL是指可扩展样式表语言 (EXtensible Stylesheet Language)
- DLL Hell (DLL噩梦)
- 句柄
- SVM支持向量机分类模型SVC理论+python sklean.svm实践
- 我们为什么需要Windows Workflow Foundation?
- 中国金融牌照全解读
- Java有字符型转化为无字符型字节数组探索学习笔记