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中的资源:

  1. protected void loadResources() {  
  2.     try {  
  3.         AssetManager assetManager = AssetManager.class.newInstance();  
  4.         Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);  
  5.         addAssetPath.invoke(assetManager, mDexPath);  
  6.         mAssetManager = assetManager;  
  7.     } catch (Exception e) {  
  8.         e.printStackTrace();  
  9.     }  
  10.     Resources superRes = super.getResources();  
  11.     mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(),  
  12.             superRes.getConfiguration());  
  13.     mTheme = mResources.newTheme();  
  14.     mTheme.setTo(super.getTheme());  
  15. }  

说明:加载的方法是通过反射,通过调用AssetManager中的addAssetPath方法,我们可以将一个apk中的资源加载到Resources中,由于addAssetPath是隐藏api我们无法直接调用,所以只能通过反射,下面是它的声明,通过注释我们可以看出,传递的路径可以是zip文件也可以是一个资源目录,而apk就是一个zip,所以直接将apk的路径传给它,资源就加载到AssetManager中了,然后再通过AssetManager来创建一个新的Resources对象,这个对象就是我们可以使用的apk中的资源了,这样我们的问题就解决了。

  1. /** 
  2.  * Add an additional set of assets to the asset manager.  This can be 
  3.  * either a directory or ZIP file.  Not for use by applications.  Returns 
  4.  * the cookie of the added asset, or 0 on failure. 
  5.  * {@hide} 
  6.  */  
  7. public final int addAssetPath(String path) {  
  8.     int res = addAssetPathNative(path);  
  9.     return res;  
  10. }  

其次是要实现那两个抽象方法

  1. @Override  
  2. public AssetManager getAssets() {  
  3.     return mAssetManager == null ? super.getAssets() : mAssetManager;  
  4. }  
  5.   
  6. @Override  
  7. public Resources getResources() {  
  8.     return mResources == null ? super.getResources() : mResources;  
  9. }  
okay,问题搞定。这样一来,在apk中就可以通过R来访问资源了。

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这个方法,尽管它不是典型的生命周期方法,但是它很有用。

  1. protected void instantiateLifecircleMethods(Class<?> localClass) {  
  2.     String[] methodNames = new String[] {  
  3.             "onRestart",  
  4.             "onStart",  
  5.             "onResume",  
  6.             "onPause",  
  7.             "onStop",  
  8.             "onDestory"  
  9.     };  
  10.     for (String methodName : methodNames) {  
  11.         Method method = null;  
  12.         try {  
  13.             method = localClass.getDeclaredMethod(methodName, new Class[] { });  
  14.             method.setAccessible(true);  
  15.         } catch (NoSuchMethodException e) {  
  16.             e.printStackTrace();  
  17.         }  
  18.         mActivityLifecircleMethods.put(methodName, method);  
  19.     }  
  20.   
  21.     Method onCreate = null;  
  22.     try {  
  23.         onCreate = localClass.getDeclaredMethod("onCreate"new Class[] { Bundle.class });  
  24.         onCreate.setAccessible(true);  
  25.     } catch (NoSuchMethodException e) {  
  26.         e.printStackTrace();  
  27.     }  
  28.     mActivityLifecircleMethods.put("onCreate", onCreate);  
  29.   
  30.     Method onActivityResult = null;  
  31.     try {  
  32.         onActivityResult = localClass.getDeclaredMethod("onActivityResult",  
  33.                 new Class[] { int.classint.class, Intent.class });  
  34.         onActivityResult.setAccessible(true);  
  35.     } catch (NoSuchMethodException e) {  
  36.         e.printStackTrace();  
  37.     }  
  38.     mActivityLifecircleMethods.put("onActivityResult", onActivityResult);  
  39. }  

其次,同步生命周期,主要看一下onResume和onPause,其他方法是类似的。看如下代码,很好理解,就是当系统调用代理activity生命周期方法的时候,就通过反射去显式调用apk中activity的对应方法。

  1. @Override  
  2. protected void onResume() {  
  3.     super.onResume();  
  4.     Method onResume = mActivityLifecircleMethods.get("onResume");  
  5.     if (onResume != null) {  
  6.         try {  
  7.             onResume.invoke(mRemoteActivity, new Object[] { });  
  8.         } catch (Exception e) {  
  9.             e.printStackTrace();  
  10.         }  
  11.     }  
  12. }  
  13.   
  14. @Override  
  15. protected void onPause() {  
  16.     Method onPause = mActivityLifecircleMethods.get("onPause");  
  17.     if (onPause != null) {  
  18.         try {  
  19.             onPause.invoke(mRemoteActivity, new Object[] { });  
  20.         } catch (Exception e) {  
  21.             e.printStackTrace();  
  22.         }  
  23.     }  
  24.     super.onPause();  
  25. }  

插件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
我的同类文章
猜你在找
Qt基础与Qt on Android入门
3G Android实战开发从入门到精通
Android底层技术:Java层系统服务(Android Service)
Android底层技术:Linux驱动框架与开发
精讲精练_参悟Android核心技术
查看评论
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:没有书籍,相关资料你可以搜一下,不过多半都没用,目前这种技术还相对空白。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值