前不久跑去折腾高德 SDK 中的 HUD 功能,相信用过该功能的用户都知道 HUD 界面上的导航转向图标是动态变化的。从高德官方导航 API 文档中 AMapNaviGuide 类的描述可知,导航转向图标有23种类型。
诶,等等,23 种?那图标应该是放在 assets 文件夹吧?总不可能是在服务器上下载吧?
看下导航 API 的 jar 包结构。
AMap_ Navi_v1.3.0_20150828.jar
|- assets
|- autonavi_Resource1_1_0.png
|- custtexture*.png (7 张)
|- com
|- amap.api.navi
|- autonavi
|- META-INF
纳尼?assets 上的图片总共也只有 8 张,而且图片的内容跟 HUD 毫无关系,莫非真的是从服务器下载资源?
用 Android Studio 打开 jar 包中的 AMapHudView.class 来看下 AMapHudView 的逻辑(AS 1.2 就引入了反编译功能)。
1
|
...
|
先看 hud_imgActions
,里面的值是不是很熟悉?转成16进制均为 0x7F02 开头(0x7F 是应用资源,而 0x02 则是 drawable 资源)。再看updateHudWidgetContent()
方法,逻辑比较简单,通过 resId
获取 hud_imgActions
对应的 drawable id,再通过该 id 获取到对应的 Drawable 对象并将其设置到 ImageView 中。
看到这,可以肯定高德 SDK 最终是通过本地资源的索引获取到 Drawable。
然而我们的 apk 中并没有相应的资源,为什么能够正常获取到对应的 Drawable?我们看回上面的第12行代码:
1
|
Drawable var1 = g.a().getDrawable(hud_imgActions[this.resId]);// g.a() 返回的是 Resource 对象
|
我们将注意力集中到 g.a()
中,找到 com.autonavi.tbt.g#a()
1
|
public static Resources a() {
|
其中变量 e
为上层传递进来的 Activity,而我们前面说过,我们的 apk 中并没有相应的资源,所以将注意力放到变量 b
在其他地方的赋值上。
1
|
public static boolean a(Context context) {
|
可以看到,高德 SDK 中先通过反射实例化 AssetManager,并且调用 addAssetPath(context.getFilesDir() + “/autonavi_Resource1_1_0.jar”),接着实例化 Resources 对象。所以事实上是通过这个新的 Resource 来获取到对应资源的 Drawable 对象。
但是我们的 apk 对应的 files 目录中并不存在 autonavi_Resource1_1_0.jar,这个文件又是怎么来的?
1
|
private static String k = "autonavi_Resource1_1_0.png";
|
还是 com.autonavi.tbt.g 这个类,可以看到,高德是将 jar 包内 assets 目录中的 autonavi_Resource1_1_0.png 复制到当前 apk 对应的 files 目录中,并将新的文件命名为 autonavi_Resource1_1_0.jar。
再回到加载资源的问题上,为什么加载 autonavi_Resource1_1_0.jar 能索引资源?
因为该文件其实是 apk(高德将后缀名改成了 jar)。AssetManager 加载该 apk 后,Resource 就能通过该 AssetManager 获取到里面的相应资源。
AssetManager 的相关知识请参考老罗的《Android应用程序资源管理器(Asset Manager)的创建过程分析》
至此,我们就可以清楚知道高德 SDK 是如何实现动态加载资源的:
将上述内容再简略,动态加载资源所必需的几个核心步骤:
这里需要注意的是,目标 apk(目录)需要放在 context.getFilesDir()
中,不然会加载失败(addAssetPath 返回 0)。另外,目标 apk 可以不签名,因为 addAssetPath 过程并没有进行签名校验。
实际情况中,如果我们需要获取相应的资源,就必须先获得资源对应的 id,而外部 apk 的 R.java 并不属于主 apk,这就导致了获取资源的困难。
目前存在的解决方案有:
最后两种方案各有各的优缺点,至于怎么选择,还得结合自身的场景。
动态加载资源技术目前的一些应用场景主要有:
动态加载资源技术相关文章有很多,但就我目前所看到的文章只涉及如何获取 drawable、string 等资源,并没有发现关于动态加载资源 apk 中的布局文件(我姿势不对?_(:зゝ∠)_
)。后续会分享如何动态加载资源 apk 中的布局文件。
最后特别感谢 Andy Zhang,MadisonRong 两位朋友帮忙校对并对文章提出了宝贵的意见,谢谢。
参考文章:
原文:http://www.cnblogs.com/dongweiq/p/5076595.html