您的位置:首页 > 移动开发 > Android开发

Android Studio引入Library后运行报"Resources$NotFoundException"的解决办法(原)

2017-02-27 14:25 851 查看
【前提条件】
        Eclipse导出的Library工程,其中的src目录被编译为jar,然后将此Library合入AndroidStudio中,编译(build)可以通过,但是运行(run)报错,报错信息:

        android.content.res.Resources$NotFoundException: Resource ID #0x7f030003
【主要特征】

        1、Library和宿主工程均编译通过,但是运行时出现crash;

        2、Library的res/value目录下存在public.xmlids.xml文件;

        3、在Eclipse工程下使用该Library运行通过,AndroidStudio工程使用该Library出现crash;

        4、核实Eclipse工程发现其gen目录下生成的R文件中的ID和res/value目录下public.xml中的ID是相同的,但是AndroidStudio的app\build\generated\source\r\debug\目录下的R文件与public.xml文件中同名的资源项ID不同;
【原因分析】

        1、Android的资源ID在编译时才可以确定下来,也就是说,每次编译的R文件中ID都可能是不一样的,这就给Library工程的打包造成了困扰,因为Library一旦打包完成,其src中的代码就锁定了,但是R文件却会在每次编译过程中更换,为了解决此问题,打包Library时,开发者往往会选择使用固定资源ID的形式,将Library中的资源ID固定下来,这样Library中打包的java就可以顺利找到R.java中的资源了。

        2、以上的"固定资源ID"的方法,会在Library工程的"res\values"目录下生成ids.xml和public.xml两个文件,其内容就是让AAPT在打包该package资源时,使用public.xml中规定的资源ID;

        3、Eclipse在引用该Library工程时,就会按照2中描述的过程生成固定的R.java文件,从而让jar中的src可以顺利找到自己的资源包;

        4、但是当该Library被AndroidStudio工程编译时(gradle版本大于1.3.0时)AndroidStudio就会忽略public.xml文件,重新为每个资源生成ID,如此,Library中的src文件就会找不到Library中的资源ID,导致报错;
【解决思路】

        在AndroidStudio的工程的build.gradle文件中对gradle进行配置,让其在利用AAPT生成资源ID时扫描public.xml文件,使用固定的资源ID。
【具体步骤】
        1、在AndroidStudio的Library工程目录下build.gradle同级目录添加文件"public-xml.gradle",内容如下:

afterEvaluate {
for (variant in android.libraryVariants) {
def scope = variant.getVariantData().getScope()
String mergeTaskName = scope.getMergeResourcesTask().name
def mergeTask = tasks.getByName(mergeTaskName)

mergeTask.doLast {
copy {
int i=0
from(android.sourceSets.main.res.srcDirs) {
include 'values/public.xml'
rename 'public.xml', (i++ == 0? "public.xml": "public_${i}.xml")
}

into(mergeTask.outputDir)
}
}
}
}


        2、在Library的build.gradle文件中添加如下内容:
apply from: 'public-xml.gradle'

        3、在AndroidStudio的app主工程的build.gradle同级目录下添加文件"public-xml.gradle",其内容如下:

afterEvaluate {
for (variant in android.applicationVariants) {
def scope = variant.getVariantData().getScope()
String mergeTaskName = scope.getMergeResourcesTask().name
def mergeTask = tasks.getByName(mergeTaskName)

mergeTask.doLast {
copy {
int i=0
from(android.sourceSets.main.res.srcDirs) {
include 'values/public.xml'
rename 'public.xml', (i++ == 0? "public.xml": "public_${i}.xml")
}

into(mergeTask.outputDir)
}
}
}
}


        这个脚本与Library中脚本的唯一区别就是applicationVariantslibraryVariants

    4、在app的build.gradle文件中添加如下内容:

apply from: 'public-xml.gradle'
    5、然后,重新rebuild工程即可(核实AndroidStudio生成的R文件与public.xml文件中ID一致)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐