Android(安卓)apk动态加载机制的研究(二):资源加载和activity生命周期管理
转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/23387079 (来自singwhatiwanna的csdn博客)
前言
为了更好地阅读本文,你需要先阅读Android apk动态加载机制的研究这篇文章,在此文中,博主分析了Android中apk的动态加载机制,并在文章的最后指出需要解决的两个复杂问题:资源的访问和activity生命周期的管理,而本文将会分析这两个复杂问题的解决方法。需要说明的一点是,我们不可能调起任何一个未安装的apk,这在技术上是无法实现的,我们调起的apk必须受某种规范的约束,只有在这种约束下开发的apk,我们才能将其调起。另外,本文给出的解决方案也不是完美的,但是逻辑已经可以正常地跑通了,剩下的极个别细节问题是可以优化的。
资源管理
我们知道,宿主程序调起未安装的apk,一个很大的问题就是资源如何访问,具体来说就是,凡是以R开头的资源都不能访问了,因为宿主程序中并没有apk中的资源,所以通过R来加载资源是行不通的,程序会报错:无法找到某某id所对应的资源。针对这个问题,有人提出了将apk中的资源在宿主程序中也copy一份,这虽然能解决问题,可以一听起来就很奇怪,首先这样会持有两份资源,会增加宿主程序包的大小,其次,没发布一个插件都需要将资源copy到宿主程序中,这样就意味着每发布一个插件都要更新一下宿主程序,这和插件化的思想是相悖的,插件化的目的就是要减小宿主程序apk包的大小同时降低宿主程序的更新频率并做到自由装载模块。所以这种方法并不可行。还有人提供了一种方式:将apk中的资源解压出来,然后通过文件流去读取资源,这样做理论上是可行的,但是实际操作起来还是有很大难度的,首先不同资源有不同的文件流格式,比如图片、xml等,还有就是针对不同设备加载的资源可能是不一样的,如果选择合适的资源也是一个需要解决的问题,基于这两点,这种方法不建议使用,因为它实现起来有难度。下面说说本文所采用的方法。
我们知道,activity的工作主要是由ContextImpl来完成的, 它在activity中是一个叫做mBase的成员变量。注意到Context中有如下两个抽象方法,看起来是和资源有关的,实际上context就是通过它们来获取资源的,这两个抽象方法的真正实现在ContextImpl中。也即是说,只要我们自己实现这两个方法,就可以解决资源问题了。
/** Return an AssetManager instance for your application's package. */
public abstract AssetManager getAssets();
/** Return a Resources instance for your application's package. */
public abstract Resources getResources();
下面看一下如何实现这两个方法
首先要加载apk中的资源:
[java] view plain copy- protected void loadResources() {
- try {
- AssetManager assetManager = AssetManager.class.newInstance();
- Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
- addAssetPath.invoke(assetManager, mDexPath);
- 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());
- }
说明:加载的方法是通过反射,通过调用AssetManager中的addAssetPath方法,我们可以将一个apk中的资源加载到Resources中,由于addAssetPath是隐藏api我们无法直接调用,所以只能通过反射,下面是它的声明,通过注释我们可以看出,传递的路径可以是zip文件也可以是一个资源目录,而apk就是一个zip,所以直接将apk的路径传给它,资源就加载到AssetManager中了,然后再通过AssetManager来创建一个新的Resources对象,这个对象就是我们可以使用的apk中的资源了,这样我们的问题就解决了。
[java] view plain copy- /**
- * Add an additional set of assets to the asset manager. This can be
- * either a directory or ZIP file. Not for use by applications. Returns
- * the cookie of the added asset, or 0 on failure.
- * {@hide}
- */
- public final int addAssetPath(String path) {
- int res = addAssetPathNative(path);
- return res;
- }
其次是要实现那两个抽象方法
[java] view plain copy- @Override
- public AssetManager getAssets() {
- return mAssetManager == null ? super.getAssets() : mAssetManager;
- }
- @Override
- public Resources getResources() {
- return mResources == null ? super.getResources() : mResources;
- }
activity生命周期的管理
这是本文开头提到的另一个需要解决的难题。为什么会有这个问题,其实很好理解,apk被宿主程序调起以后,apk中的activity其实就是一个普通的对象,不具有activity的性质,因为系统启动activity是要做很多初始化工作的,而我们在应用层通过反射去启动activity是很难完成系统所做的初始化工作的,所以activity的大部分特性都无法使用包括activity的生命周期管理,这就需要我们自己去管理。谈到activity生命周期,其实就是那几个常见的方法:onCreate、onStart、onResume、onPause等,由于apk中的activity不是真正意义上的activity(没有在宿主程序中注册且没有完全初始化),所以这几个生命周期的方法系统就不会去自动调用了。针对此类问题,采用Fragment是一个不错的方法,Fragment从3.0引入,通过support-v4包,可以兼容3.0以下的android版本。Fragment既有类似于Activity的生命周期,又有类似于View的界面,将Fragment加入到Activity中,activity会自动管理Fragment的生命周期,通过第一篇文章我们知道,apk中的activity是通过宿主程序中的代理activity启动的,将Fragment加入到代理activity内部,其生命周期将完全由代理activity来管理,但是采用这种方法,就要求apk尽量采用Fragment来实现,还有就是在做页面跳转的时候有点麻烦,当然关于Fragment相关的内容我将在后面再做研究,本文不采用Fragment而是通过反射去手动管理activity的生命周期。
我们要在代理activity中去反射apk中activity的所有生命周期的方法,然后将activity的生命周期和代理activity的生命周期进行同步。首先,反射activity生命周期的所有方法,还反射了onActivityResult这个方法,尽管它不是典型的生命周期方法,但是它很有用。
[java] view plain copy- protected void instantiateLifecircleMethods(Class<?> localClass) {
- String[] methodNames = new String[] {
- "onRestart",
- "onStart",
- "onResume",
- "onPause",
- "onStop",
- "onDestory"
- };
- for (String methodName : methodNames) {
- Method method = null;
- try {
- method = localClass.getDeclaredMethod(methodName, new Class[] { });
- method.setAccessible(true);
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- }
- mActivityLifecircleMethods.put(methodName, method);
- }
- Method onCreate = null;
- try {
- onCreate = localClass.getDeclaredMethod("onCreate", new Class[] { Bundle.class });
- onCreate.setAccessible(true);
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- }
- mActivityLifecircleMethods.put("onCreate", onCreate);
- Method onActivityResult = null;
- try {
- onActivityResult = localClass.getDeclaredMethod("onActivityResult",
- new Class[] { int.class, int.class, Intent.class });
- onActivityResult.setAccessible(true);
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- }
- mActivityLifecircleMethods.put("onActivityResult", onActivityResult);
- }
其次,同步生命周期,主要看一下onResume和onPause,其他方法是类似的。看如下代码,很好理解,就是当系统调用代理activity生命周期方法的时候,就通过反射去显式调用apk中activity的对应方法。
[java] view plain copy- @Override
- protected void onResume() {
- super.onResume();
- Method onResume = mActivityLifecircleMethods.get("onResume");
- if (onResume != null) {
- try {
- onResume.invoke(mRemoteActivity, new Object[] { });
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- @Override
- protected void onPause() {
- Method onPause = mActivityLifecircleMethods.get("onPause");
- if (onPause != null) {
- try {
- onPause.invoke(mRemoteActivity, new Object[] { });
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- super.onPause();
- }
插件apk的开发规范
文章开头提到,要想成为一个插件apk,是要满足一定条件的,如下是采用本文机制开发插件apk所需要遵循的规范:
1. 不能用this:因为this指向的是当前对象,即apk中的activity,但是由于activity已经不是常规意义上的activity,所以this是没有意义的。
2. 使用that:既然this不能用,那就用that,that是apk中activity的基类BaseActivity中的一个成员,它在apk安装运行的时候指向this,而在未安装的时候指向宿主程序中的代理activity,anyway,that is better than this。
3. 不能直接调用activity的成员方法:而必须通过that去调用,由于that的动态分配特性,通过that去调用activity的成员方法,在apk安装以后仍然可以正常运行。
4. 启动新activity的约束:启动外部activity不受限制,启动apk内部的activity有限制,首先由于apk中的activity没注册,所以不支持隐式调用,其次必须通过BaseActivity中定义的新方法startActivityByProxy和startActivityForResultByProxy,还有就是不支持LaunchMode。
5. 目前暂不支持Service、BroadcastReceiver等需要注册才能使用的组件。
后续工作
1. DLIntent的定义,通过自定义的intent,来完成activity的无约束调起
2. 采用Fragment的生命周期管理
3. Service、BroadcastReceiver等组件的调起
4. 性能优化
效果
首先宿主程序运行后,会把位于/mnt/sdcard/DynamicLoadHost目录下的所有apk都加载进来,然后点击列表就可以调起对应的apk,本文中的demo和第一篇文章中的demo看起来差不多,实际是有区别的,区别有两点:activity具有生命周期、加载资源可以用R,具体的代码实现请大家参见源码。
源码下载:https://github.com/singwhatiwanna/dynamic-load-apk
- 顶
- 68
- 踩
- 4
- 上一篇Android apk动态加载机制的研究
- 下一篇Android源码分析-资源加载机制
我的同类文章
Android高手进阶(50)- •Android中MotionEvent的来源和ViewRootImpl2016-03-01阅读4048
- •循环广告位组件的实现2015-06-18阅读13045
- •APK动态加载框架(DL)解析2014-10-10阅读37819
- •Android View系统解析(上)2014-07-27阅读15182
- •Android源码分析-资源加载机制2014-04-26阅读11325
- •Android的消息机制之ThreadLocal的工作原理2015-09-10阅读6325
- •Android L中水波纹点击效果的实现2015-01-12阅读20860
- •Android View系统解析(下)2014-08-08阅读20207
- •可下拉的PinnedHeaderExpandableListView的实现2014-05-12阅读20096
- 猜你在找
- 52楼 sonnzy 2015-12-25 16:02发表 [回复]
- 厉害,一直被无法获取插件apk里的R烦恼,虽然网上也有类似dl,但是没这么详细,你说明了原理,还有源代码,非常的难得,赞一个
- 51楼 杭州山不高 2015-12-18 18:05发表 [回复]
- 好文,转了!
- 50楼 andywuchuanlong 2015-07-13 14:24发表 [回复]
- LZ,你这个无法宿主apk无法调用插件apk
- 49楼 xw568159764 2015-07-10 16:37发表 [回复]
- 请教楼主一下,既然activity中跟context相关的操作都是通过mBase完成的,是不是可以直接调用attachBaseContext方法直接将宿主activity的context赋给插件?
- 48楼 SanDiegoX 2015-05-12 23:50发表 [回复]
- 感谢博主的分享,有点儿问题请教一下:
1、资源文件的加载是不是在博主构造的 DL 框架(demo 中的 lib 目录 ?)中处理?而每次壳程序通过去调用 DL 框架,来加载插件APK、同时完成对资源文件的动态加载??
2、我用了另外一种方式来实现对APK的加壳,想按照博主的思路、通过壳的组件动态加载 APK 的资源文件。请问,除了创建AssetManager、Resources 对象外,还需要对 运行中的 ActivityThread 进行反射修改吗?博主提重写的 getAssets()、getResource() 方法,是在壳的主Activity、或者Application中重写即可吗?
谢谢!
- 47楼 godnessilove 2015-04-16 20:34发表 [回复]
- 你好,我在学习你的插件化的时候碰到个问题,host无法调起pluga或者plugb
报错:
04-16 11:46:26.962 2718-2718/? W/dalvikvm﹕ (Lcom/ryg/dynamicload/sample/mainplugin/MainActivity; had used a different Lcom/ryg/dynamicload/DLBasePluginActivity; during pre-verification)
04-16 11:46:26.962 2718-2718/? W/dalvikvm﹕ Unable to resolve superclass of Lcom/ryg/dynamicload/sample/mainplugin/MainActivity; (723)
我在研究后发现dexclassload找不到com/ryg/dynamicload/sample/mainplugin/MainActivity这个class,但是确实已经把这个apk给加载到app_dex目录下了
然后在需要用的时候从map里拿出对应的manager去Class.forName,这里就是不对,断点跟踪发现没有获得需要的class,然后我改成dexclassload.loadClass方法就报错 java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation,我总觉得是不是因为插件里面包含了一份dl-lib的DLBasePluginActivity,然后host里面libs里面也有一份,结果最后执行查找他的子类MainActivity就出问题了,是不是我2个包打包不对?
请问这个问题怎么解决啊~
感激不尽啊~
- 46楼 godnessilove 2015-04-16 20:32发表 [回复]
- 你好,我在学习你的插件化的时候碰到个问题,host无法调起pluga或者plugb
报错:
04-16 11:46:26.962 2718-2718/? W/dalvikvm﹕ (Lcom/ryg/dynamicload/sample/mainplugin/MainActivity; had used a different Lcom/ryg/dynamicload/DLBasePluginActivity; during pre-verification)
04-16 11:46:26.962 2718-2718/? W/dalvikvm﹕ Unable to resolve superclass of Lcom/ryg/dynamicload/sample/mainplugin/MainActivity; (723)
我在研究后发现dexclassload找不到com/ryg/dynamicload/sample/mainplugin/MainActivity这个class,但是确实已经把这个apk给加载到app_dex目录下了
然后在需要用的时候从map里拿出对应的manager去Class.forName,这里就是不对,断点跟踪发现没有获得需要的class,然后我改成dexclassload.loadClass方法就报错 java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation,我总觉得是不是因为插件里面包含了一份dl-lib的DLBasePluginActivity,然后host里面libs里面也有一份,结果最后执行查找他的子类MainActivity就出问题了,是不是我2个包打包不对?
请问这个问题怎么解决啊~
感激不尽啊~
- 45楼 cokepanm 2015-04-01 16:51发表 [回复]
- 询问下,当插件的资源已经加载后,怎么去释放其内存呢
- 44楼 余龙飞 2015-02-05 15:50发表 [回复]
- 赞楼主的分享精神,想问一下,百度卫士里面用到了这种技术吗?
2013年底的时候,我们团队碰到了这个问题,需要在宿主进程中访问插件中的资源,当时交给我解决,我阅读源码调研了好几天才调研出来,因为公司项目中使用了,所以一直没有分享出来。
一个宿主app的Context默认会关联2个apk的资源:自身apk中资源和framework-res.apk中的资源
我们只需要模拟android源码关联framework-res.apk资源的方式,把插件apk的资源也和宿主Context关联上即可。
这样我们宿主app的Context就关联上了3个apk的资源了。当然还可以关联更多,只要resouce id够用。- Re: fengzi422 2015-12-08 14:50发表 [回复]
- 回复gemmem:按照你这么说,确实可以解决多个apk的resource的问题,但是你在host中如何拿到你所想拿到的资源的id?需要使用另外一个R文件么?而且资源id冲突了怎么办?
- Re: singwhatiwanna 2015-02-05 18:47发表 [回复]
- 回复gemmem:不是反射addAssetPath这个方法做的?
- Re: 余龙飞 2015-02-06 10:19发表 [回复]
- 回复singwhatiwanna:我上面说的是实现原理,你多想想,应该能明白。
实现方法就是用addAssetPath构造出一个resouces对象,这个resource对象关联到宿主的Context环境中(具体做法就是重写宿主Context的getResources等方法),让宿主Context具备了解析插件apk资源的能力。- Re: fengzi422 2015-12-08 14:50发表 [回复]
- 回复gemmem:按照你这么说,确实可以解决多个apk的resource的问题,但是你在host中如何拿到你所想拿到的资源的id?需要使用另外一个R文件么?而且资源id冲突了怎么办?
- Re: 余龙飞 2015-12-29 15:35发表 [回复]
- 回复fengzi422:重写host app中的activity的getResources等函数,让它们返回自己构造的那个包含了plugin apk path的resource对象。
- Re: for_perfect 2015-04-07 14:34发表 [回复]
- 回复gemmem:您好,我现在的团队产品的需求是,app1是打开状态,需要在app1中读取app2中存储在sharedprference中的数据,wo使用这种重写getAssets(),getResources(),getTheme()可以实现吗
- Re: 余龙飞 2015-04-08 20:51发表 [回复]
- 回复u010359739:完全不相干的东西,当然不可以。
- Re: 简单才是美 2015-05-13 16:21发表 [回复]
- 回复gemmem:使用反射AssetManager方式,在android 5.0上会报错,会提示找不到资源的问题;请问一下你们有碰到过这种问题吗?
- Re: AriaLyy 2015-09-19 14:50发表 [回复]
- 回复waitingformysun:我也碰到了同样的问题,我猜想原因可能是addAssetPath这个方法调用失败了,我在5.0上用反射使用这个方法,一直返回0...
- Re: 余龙飞 2015-12-29 15:32发表 [回复]
- 回复qwe511455842:5.0,我没有试过。你看看源码吧
- 43楼 _自由人_ 2015-01-31 12:29发表 [回复]
- 楼主,我研究这插件化也有短时间了,你这blog的思路跟我综合起来的思路大概一致,但你讲了,能使用getResource()来使用插件中的资源,这点是我没有想到的,这里给你个赞!!!我刚大概看了你的代码,但我发现,你并没有使用getResources()的方法去使用插件apk中的资源!因此,我有个问题:你成功使用过getResource()引用过插件apk中的资源吗?盼探讨
- Re: singwhatiwanna 2015-01-31 19:17发表 [回复]
- 回复wuzhipeng1991:可以的,在插件中可以用R直接访问插件的资源,同时插件是运行在宿主中的,所以宿主也可以直接访问插件的资源,前提是知道id。
- Re: _自由人_ 2015-02-02 09:04发表 [回复]
- 回复singwhatiwanna:我自己尝试了一下在你的代码上修改。不过,我把插件的代码单独拿出来运行,却一直报找不到类异常,这其中有什么问题需注意的吗?望指出下。谢谢
- 42楼 小胖 2015-01-07 11:13发表 [回复]
- 请问一下,大牛们有没有用过DevAppsDirect这个展示开源demo的软件,原理是不是一样的?
- 41楼 yemin6666 2015-01-04 16:52发表 [回复]
- 请教下,~getAssets() ,getResources()是在宿主程序,还是插件程序里重写~?我复制了apk中的一份资源到宿主程序,然后在反射apk中用R来调用,发现也没调用不到资源
- Re: singwhatiwanna 2015-01-04 20:26发表 [回复]
- 回复yemin6666:请参看dl的源码
- 40楼 sinat_23061139 2014-11-07 18:12发表 [回复]
- 楼主良心!目前也在研究这一块找了下资料,找了下资料,确实不多,研究的人估计也不少,也有一些已经商用的SDK,但是能把技术原理和细节实现分享出来的真的不多。
- Re: 余龙飞 2015-02-06 10:25发表 [回复]
- 回复sinat_23061139:同感,其实2013年底时,由于项目需要,我承担了调研插件资源动态加载的任务,我费了好大劲调研出来的,但是一直舍不得分享。
- Re: singwhatiwanna 2015-02-06 10:41发表 [回复]
- 回复gemmem:觉得自己花了很多心思对吧,所以不舍得,也可以理解。不过我现在所推崇的是分享。
- 39楼 尼古拉斯_赵四 2014-10-24 15:47发表 [回复]
- mark一下,我以前写的动态加载技术一片文章,但是你mark了一下,apk插件的用途还是蛮大的,支付宝就是个好例子,还有微信的免安装游戏试玩等,核心技术还是反射。。。
- 38楼 amurocrash 2014-10-08 11:14发表 [回复]
- 大神,你最新github的版本里的插件基类因为onStart等方法没有super.onStart()等,插件直接运行的时候会导致程序崩溃,你把这些生命周期方法和setProxy方法抽取到了一个DLPlugin接口内我觉得意义不明,而且和Activity本身的生命周期方法是重复的,不知道你设计的思路是什么,个人觉得接口里只放setProxy这样的方法就可以了,盼探讨~
- Re: singwhatiwanna 2014-10-08 16:08发表 [回复]
- 回复amurocrash:215680213 加群探讨。
目前思路已经和博客上的有了不小改变,接下来我会重新发布说明文档的。目前你是用sample/main下面的demo,是没有问题的。如果想独立运行,需要把dl-lib.jar放入到插件的libs目录下。至于plugin接口的意义,是activity生命周期的管理所需,都是有用并且是非常有意义的。这一切都会让dl更加好用更加方便调用。
- 37楼 胖虎 2014-09-28 21:49发表 [回复]
- lz, 最近小弟也在研究这块,我想请问下比如apk A 调起了 apk B中的MainActivity, 那按照这样的处理,是不是在apk B中MainActivity 开启的服务,或者注册的广播接受者都不能用?
那MainActivity如果 startActivity呢?1.startActivity会受影响吗? 2.start起来的那个Activity依旧用的是 是apk A的上下文吗?- Re: singwhatiwanna 2014-09-29 20:12发表 [回复]
- 回复u011133213:目前暂时不支持service,广播可以通过代码注册。
- Re: 胖虎 2014-09-30 08:45发表 [回复]
- 回复singwhatiwanna:那被我A调起的那个B MainActivity,如果要再启动一个B OtherActivity 那需要用A的这种上下文来启动咯?
- 36楼 TigerBetree 2014-09-17 17:26发表 [回复]
- 膜拜啊~
- 35楼 花-开-花-谢 2014-09-09 18:30发表 [回复]
- 帅哥,我也刚开始写博客,自己弄得gif图片怎么在博客中只能显示第一侦,就不会动,请问是怎么回事,这是链接:http://blog.csdn.net/gaolei1201/article/details/39057057
- Re: singwhatiwanna 2014-09-10 21:20发表 [回复]
- 回复gaolei1201:首先要做一个gif图,其次图片尺寸不要太大,否则到csdn上动不了。
- Re: 花-开-花-谢 2014-09-11 00:09发表 [回复]
- 嗯,我用了包括GifCam等好几种工具,制作成gif图片,就是一传到博客就不会动,只有100kb左右,请问这是为什么?你用的什么工具
- Re: singwhatiwanna 2014-09-11 09:31发表 [回复]
- 回复gaolei1201:gif maker.首先确认你的gif在本地是可以动的,其次宽高不要太大,基本就可以了。
- Re: 花-开-花-谢 2014-09-11 14:00发表 [回复]
- 谢谢,昨天我又试了试,竖屏的录制的gif是可以的,横屏录制的gif在博客上不会动
- 34楼 厂圩菠萝菠萝蜜 2014-09-09 14:31发表 [回复]
- 博主知识博大精深,受教了。请问启动service的问题解决了吗?
- 33楼 worthwhile001 2014-09-04 15:38发表 [回复]
- host里面,先期client里面的mainactivity,通过mainactivity,起testactivity,。我把client里面testactivity和mainactivity,换一下顺序,怎么就不行了。。
- Re: singwhatiwanna 2014-09-08 15:12发表 [回复]
- 回复worthwhile001:startActivityByProxy
用这个来起activity
- 32楼 怀柔老纪 2014-08-19 10:46发表 [回复]
- 有一个问题想问问,插件用了这么多反射,还能不能正常的混淆代码了。宿主的代理Activity是不是也要从混淆中排除?
- Re: singwhatiwanna 2014-08-19 18:46发表 [回复]
- 回复coolstar1204:android的framework默认就不能参与混淆,否则你的activity就跑不起来,所以,插件化不影响正常混淆。
- 31楼 tanxiaojun 2014-07-29 11:14发表 [回复]
- 最近在研究这个,楼主的Demo可以用,已经有人把插件模块化做成SDK了,apkplug,不知道原理和楼主的是不是一样
http://www.apkplug.com/
- 30楼 gejw116 2014-07-25 20:18发表 [回复]
- String[] methodNames = new String[] {
"onRestart",
"onStart",
"onResume",
"onPause",
"onStop",
"onDestory"
};
for (String methodName : methodNames) {
Method method = null;
try {
method = localClass.getDeclaredMethod(methodName, new Class[] { });
method.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
mActivityLifecircleMethods.put(methodName, method);
}
反射这6个函数的时候,method为空,我试了下例子,手机上不能跑- Re: singwhatiwanna 2014-07-27 10:13发表 [回复]
- 回复gejw116:跑的时候是需要插件apk放在指定目录的,demo是可以跑的。
- 29楼 HiPhoneZhu 2014-07-24 16:45发表 [回复]
- 真的很不错,我知道阿里内部有个团队也在做这个,完全抛弃了系统的,加油,文章写得真的不错!
- Re: HiPhoneZhu 2014-07-24 17:27发表 [回复]
- 回复zhf198909:github上面最新的代码,无法启动插件
- Re: singwhatiwanna 2014-07-25 18:54发表 [回复]
- 回复zhf198909:是不是插件apk没有放在指定目录?
- 28楼 shuaizhimin123 2014-07-22 18:58发表 [回复]
- 为什么资源文件无法直接调用?求解。下载的是你gitHub上面的源码
- Re: singwhatiwanna 2014-07-25 18:56发表 [回复]
- 回复shuaizhimin123:你按照文章上面说的步骤来
- 27楼 赫贺鹤 2014-07-01 23:24发表 [回复]
- 这么牛逼你爹知道吗
- 26楼 asking1233 2014-06-22 13:11发表 [回复]
- 师父,请受徒儿一鞠躬
- 25楼 colcat2010 2014-05-04 22:04发表 [回复]
- lz写的非常好,可是源码地址我们学校校园网打不开,不知道能不能发到我邮箱,谢谢!coldcat2010@126.com
- 24楼 追风筝的孩子 2014-04-29 17:36发表 [回复]
- http://blogs.360.cn/blog/proxydelegate-application/
他们已经能不安装apk并且运行该apk了,不适合插件化,因为必须要在AndroidMainfest里面把需要的Activity插件话,但挺适合部门间合作。不用提供源码并且做小幅度修改即可- Re: singwhatiwanna 2014-04-29 22:01发表 [回复]
- 回复A328240784:个人觉得,360那个很受限制,而且很容易有问题,太深入底层了。
- Re: com360 2014-08-14 16:33发表 [回复]
- 回复singwhatiwanna:牛逼!和我们现在用的类似。可以在安全上和打包上再搞一搞。
- 23楼 cornivylove 2014-04-26 20:49发表 [回复]
- 相关技术方法我也整过,唉!越整越没脾气……
- 22楼 anbiandezacao 2014-04-25 10:03发表 [回复]
- 如果你能在DynamicLoadHost直接调用DynamicLoadClient里的res文件,那你解决了做jar包人纠结了四五年的问题
- Re: singwhatiwanna 2014-04-25 10:14发表 [回复]
- 回复anbiandezacao:你要搞清楚,host是要把jar包调起来,而host根本不知道jar包里有什么资源,怎么能访问jar包的资源?而且host调起jar包后,jar包是可以访问到自己的资源的。换句话来说,你在host里面访问一个未知jar包的资源干什么?也许我们理解的有偏差
- 21楼 anbiandezacao 2014-04-25 09:53发表 [回复]
- 额,JAVA基础好的都知道,class文件可以用反射调用,android的dex文件也可以用反射调用,做jar包最痛苦的是不能调用res里面的文件,看了你的代码,你也根本没解决...
- Re: singwhatiwanna 2014-04-25 10:19发表 [回复]
- 回复anbiandezacao:关于资源的加载问题,我做了处理,你可以再仔细看一下。
- 20楼 MrSimp1e 2014-04-24 18:35发表 [回复]
- 楼主,宿主apk能否获取到被加载apk的资源?多谢
- Re: singwhatiwanna 2014-04-25 10:15发表 [回复]
- 回复bboyfeiyu:从动态加载来说,宿主加载apk后可以访问apk里的资源。
- Re: MrSimp1e 2014-04-25 13:12发表 [回复]
- 回复singwhatiwanna:只需加载apk中的Activity类到虚拟机中,不需要onCreate就OK吗 ?
- 19楼 Lee坚持 2014-04-21 22:51发表 [回复]
- 厉害
- Re: singwhatiwanna 2014-04-21 23:14发表 [回复]
- 回复lxcay:徒弟
- Re: 追风筝的孩子 2014-05-15 17:00发表 [回复]
- 回复singwhatiwanna:你徒弟也是黑马的啊。。
- Re: mephistodemon1 2014-10-13 23:29发表 [回复]
- 回复A328240784:黑马?几期?
- 18楼 Simon_Lanzhou 2014-04-18 15:21发表 [回复]
- mark
- 17楼 l114624915 2014-04-17 14:51发表 [回复]
- 最好能在宿主和插件包之间定义一套接口IInterface,把
"onRestart","onStart"...定义在接口中,这样就可以不用反射那么麻烦了。类加载实例后Object instance = localConstructor.newInstance(new Object[] {});可以这样调用方法(IInterface)instance .onRestart。- Re: singwhatiwanna 2014-04-25 10:15发表 [回复]
- 回复l114624915:可以考虑下
- Re: qq744765669 2014-05-23 14:39发表 [回复]
- 回复singwhatiwanna:在宿主和插件之间建立接口的思路是否走过?我在建立这套接口,将目标Instance转化为接口的时候发生强转错误
- 16楼 zhenxiong25 2014-04-14 17:13发表 [回复]
- henniu
- 15楼 szltoy123 2014-04-13 13:37发表 [回复]
- 不过 你的 方法少重载了 gettheme 如果插件资源里面的 资源layout 关联了其他资源 例如图片 没有gettheme的方法是报错的 我测试过
- Re: singwhatiwanna 2014-04-13 15:09发表 [回复]
- 回复szltoy123:你说的对,getTheme我有重写,你看下源码就知道了。
- Re: szltoy123 2014-04-14 16:39发表 [回复]
- 回复singwhatiwanna:有个问题 就是 如果插件布局用到了自定义view 自定义view的实现肯定是放在插件里面了,这样子用您的方法去实现这个view的话就会报错 ,因为用that 去实例化 查找这个布局的时候找到这个view的类名 本程序并没有这个类的实现。所以就报错了。有什么办法解决这个问题呢。
- Re: singwhatiwanna 2014-04-14 23:20发表 [回复]
- 回复szltoy123:请看github上最新提交,已经支持在xml使用自定义view了,遗憾的是目前不支持在代码中find自定义view(会报类型转换失败),待后面再解决。
- Re: szltoy123 2014-04-15 10:48发表 [回复]
- 回复singwhatiwanna:加上getClassloader 的确可以显示自定义view了,不过我没遇到您的问题我实例化的时候也可以顺利的吧自定义view实例化出来。
虽然这样可是遇到一个比较怪的问题就是,
所以如果主程序有一份自定义view的代码插件也有一份一样的,加载实例化的时候居然不会报错,而是主程序的那份把插件的覆盖了。主程序要是没有就执行插件的。- Re: singwhatiwanna 2014-04-15 11:55发表 [回复]
- 回复szltoy123:那我那个问题可能是mui的bug。你遇到的这个问题:首先不要定义同一个类名,其次那个classloader写的有问题,应该先从插件中去加载类,加群讨论215680213
- Re: singwhatiwanna 2014-04-14 17:20发表 [回复]
- 回复szltoy123:override getClassloader,然后返回dexclassloader,后面会更新到github。
- Re: peacepassion 6天前 09:10发表 [回复]
- 回复singwhatiwanna:关于theme,我也遇到一个问题。我在尝试扩展对v7包中的AppCompatActivity进行支持,于是分别实现了DLProxyAppCompatActivity和DLBasePluginAppCompatActivity,在DLPluginImpl中将插件activity的主题设置给宿主activity的时候Activity#setTheme(),发现只有对AppCompatActivity主题的设置无效,其它两种类型的Activity都是OK的。
请问博主有遇到这个问题么?
- 14楼 szltoy123 2014-04-13 13:35发表 [回复]
- 非常开心看到您的文章动态加载资源这一块的确空白 我找了一年时间终于看到你的文章解决了所有的问题。谢谢 哈哈
- Re: singwhatiwanna 2014-04-13 15:09发表 [回复]
- 回复szltoy123:至于找一年那么久?
- Re: szltoy123 2014-04-14 09:46发表 [回复]
- 回复singwhatiwanna:唉 断断续续找 差不多啦 以前在书上找 网上找都说需要改源码,所以一直没去研究这部分的源码
- 13楼 scion_KK 2014-04-12 23:18发表 [回复]
- 不错的文章呀。有时候需要的就是这种功能
- 12楼 zwt069074237 2014-04-12 21:06发表 [回复]
- mark
- 11楼 KennethYo 2014-04-12 18:03发表 [回复]
- 目前业务上还用不到,但是在这种技术上我还是一片空白,先mark上,日后来仔细研究。
- 10楼 pageTan 2014-04-12 12:17发表 [回复]
- 学习了
- 9楼 yjiyjige 2014-04-11 22:57发表 [回复]
- 不错,有时候解决问题最好的方法就是去读源码了。
之前想实现一个功能,就是动态下载语言包。
实现的方法就是使用反射去自己构造出一个Resource出来。这方法的研究确实还比较少。
- 8楼 绿领巾童鞋 2014-04-11 21:56发表 [回复]
- 膜拜啊~
- 7楼 兰亭风雨 2014-04-11 21:40发表 [回复]
- 大神就是大神啊!真心膜拜!!
- Re: singwhatiwanna 2014-04-11 22:36发表 [回复]
- 回复mmc_maodun:嘿嘿
- 6楼 RowandJJ 2014-04-11 19:22发表 [回复]
- 赞~
- 5楼 Tony2005 2014-04-11 16:20发表 [回复]
- 非常不错~!顶上
- 4楼 soledadzz 2014-04-11 12:17发表 [回复]
- 您的文章已被推荐到CSDN首页,感谢您的分享。
- Re: singwhatiwanna 2014-04-11 16:25发表 [回复]
- 回复soledadzz:谢谢啦
- 3楼 时之沙 2014-04-11 11:37发表 [回复]
- 不错,顶一下
- Re: singwhatiwanna 2014-04-11 16:25发表 [回复]
- 回复t12x3456:沙兄
- 2楼 zhouqian88423 2014-04-11 11:26发表 [回复]
- 昨晚本来就想拜读了,结果12点半就睡觉去了,刚浏览一遍不是很懂,周末认真研究下
- 1楼 万境绝尘 2014-04-11 10:29发表 [回复]
- apk文件还能这么玩啊 有相关的资料或者书籍吗 参考下
- Re: singwhatiwanna 2014-04-11 10:34发表 [回复]
- 回复han1202012:没有书籍,相关资料你可以搜一下,不过多半都没用,目前这种技术还相对空白。
更多相关文章
- Android(安卓)编译环境小语种丢失Bug
- Android(安卓)资源获取
- Android运行异常:Unable to start activity ComponentInfo{}: and
- Android:Android(安卓)Studio配置Kotlin
- Android(安卓)Studio library R.java生成失败解决
- Android(安卓)安装配置及其项目开发
- Flutter插件开发之APK自动安装
- 创建和使用Android(安卓)library工程
- Android开发札记初级(三)探索Android(安卓)Studio Ⅱ