[AIR接入Android 平台]处理res资源之找不到资源ID

一点声明:我的水平有限 这里仅仅只能写出我认为可行的方案 和 代码

打包ANE会经常遇到找不到资源R.XXX ID的问题,或者是找到的资源ID不对 然后报NULL POINT错 直接程序崩溃。

AIR与android原生取资源方式的区别
ADOBE给出的取资源的方式是:

[code lang=”java”]
_context.getResourceId("id.AlipayTitleItemName");
[/code]
但是原生JAVA取资源的方式是:
[code lang=”java”]
findViewById(R.id.AlipayTitleItemName);
[/code]

ADOBE的取资源方式 是我们在ANE中使用到资源的时候的取法,
但是一般运营商提供的SDK都是混淆的jar 取资源的方式都是清一色的findViewById。
而我们不可能去修改SDK 的jar。除非你的逆向能力到一定水平。其实修改SDK的jar也不是不可能的。对于android逆向有兴趣的同学 可以去试试。其实android逆向也是一门非常好玩的技术。如果你有兴趣 我们可以一起探讨。

ANE打包资源后生成的R.java特点:
前面的文章说了 ANE打包资源是通过把资源文件夹res放到 Android-ARM下。然后打包的时候就可以在ANE内部生成R.java了。我们反编译一个APK看看AIR生成的R.java有什么特点:

默认是生成R.java处在 包名为APK的ID下。也就是air+(你程序的-app.xml的ID)。
而我们的SDK取ID都是 R.id.AlipayTitleItemName 也就是说取的是SDK的同级包下的R.java。这就会导致取不到资源ID:

也就是说 导致取不到ID的原因之一 有可能是(之所以说有可能 是因为取不到资源ID还有其他各种的原因,起码我遇遇到过的是如此):

真正的资源ID 
所在的类[air.xxx.xxx.xx.R.java]
与SDK资源ID的包名[wxd.view.R.java]
地址不同

现在知道问题所在了。那解决这个问题仔细一想就能知道如下几种方法:

A.最简单的方式。说服运营商 把SDK的取资源的包改为我们AIR生成资源的包

但是这也是最异想天开的方法。永远别梦想着运营商会针对你一家修改它的SDK。虽然想法美好 但是却是痴心妄想。

B.在ANE源码中新建一个包例如上面举例的情况是 在src下新建 包 [wxd.view] 在这个包下新建类R.java。如图:

然后把运营商给的java SDK demo下的 gen文件夹下的R.java的内容复制到 wxd.view.R.java类中。

然后再打包ANE  就能正常取资源ID了。

C.也是目前我发现最完美的解决方式:

灵活使用context.getResourceId 取AIR生成的R.java下的ID 取填补 SDK下的 R.java的资源ID。

如图:

例如上图的例子中。加一个resHandle.java类。
[code lang=”java”]
package com.xxx.ane;

import android.util.Log;

import com.adobe.fre.FREContext;

/**
* R.java ID处理
* @author Rect
* @version Time:2013-5-14
*/
public class ResHandle {
public static void setResourctID(FREContext _context,String TAG)
{
if(wxd.view.R.array.address == _context.getResourceId("array.address") &&
wxd.view.R.anim.elseway == _context.getResourceId("anim.elseway"))
return;

Log.d(TAG, "———anim——-"+_context.getResourceId("anim.elseway"));
wxd.view.R.anim.elseway = _context.getResourceId("anim.elseway");
wxd.view.R.anim.elseway_in = _context.getResourceId("anim.elseway_in");
wxd.view.R.anim.landscape_anim = _context.getResourceId("anim.landscape_anim");
wxd.view.R.anim.portrait_anim = _context.getResourceId("anim.portrait_anim");
wxd.view.R.anim.zoom_enter = _context.getResourceId("anim.zoom_enter");
wxd.view.R.anim.zoom_exit = _context.getResourceId("anim.zoom_exit");
wxd.view.R.anim.zoomin = _context.getResourceId("anim.zoomin");
wxd.view.R.anim.zoomout = _context.getResourceId("anim.zoomout");


[/code]

当然 在SDK包下的R.java要做一些处理 使得能访问全部静态变量 例如我的
wxd.view.R.java 如下:
[code lang=”java”]
package wxd.view;

public class R
{
public static class anim
{
public static int elseway = 2130968576;
public static int elseway_in = 2130968577;
public static int landscape_anim = 2130968578;
public static int portrait_anim = 2130968579;
public static int zoom_enter = 2130968580;
public static int zoom_exit = 2130968581;
public static int zoomin = 2130968582;
public static int zoomout = 2130968583;
}

[/code]

这样外部就能访问 各个变量了。
然后在 调用SDK打开SDK界面之前 调用这句对R.java进行处理:
[code lang=”java”]
Log.d(TAG, "———R.java处理——-");
ResHandle.setResourctID(_context, TAG);
Log.d(TAG, "———Login开始——-");
[/code]

至此 由于取不到资源ID的问题 就得到了解决。当然再强调一次 取不到资源ID 也有可能是由于其他问题导致的。这仅仅是导致这个问题的原因之一。

《[AIR接入Android 平台]处理res资源之找不到资源ID》有10个想法

  1. 要是能讲一个百度云推送的集成就好了,,试了很久都还是不成功。。。

  2. 不太明白,上面说的那句“.在ANE源码中新建一个包例如上面举例的情况是 在src下新建 包 [wxd.view] 在这个包下新建类R.java。如图:”….我是在JAR源码中新建的包,然后把R.JAVA文件复制进去,合并JAR,生成ANE,是这个意思吗?

  3. 例如UC的SDK包资源在包 com.uc.res.R.java中,则在ANE中则建一个包为com.uc.res,然后新建R.java源码文件 把ID复制过去。@JHM

  4. rect 你好 请问一下 libs目录下的 so文件怎样一起打进ane里面 谢谢啦

    1. @gg, 把so库放到ANE下Android-ARM/lib/armeabi (调试模式)或者 armeabi-v7a(发行模式)下

Rect进行回复 取消回复

邮箱地址不会被公开。 必填项已用*标注