Android Studio引入Library后运行报”Resources$NotFoundException”的解决办法

【前提条件】

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”,内容如下:

  1. afterEvaluate {
  2.     for (variant in android.libraryVariants) {
  3.         def scope = variant.getVariantData().getScope()
  4.         String mergeTaskName = scope.getMergeResourcesTask().name
  5.         def mergeTask = tasks.getByName(mergeTaskName)
  6.         mergeTask.doLast {
  7.             copy {
  8.                 int i=0
  9.                 from(android.sourceSets.main.res.srcDirs) {
  10.                     include ‘values/public.xml’
  11.                     rename ‘public.xml’, (i++ == 0? “public.xml”: “public_${i}.xml”)
  12.                 }
  13.                 into(mergeTask.outputDir)
  14.             }
  15.         }
  16.     }
  17. }

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

  1. apply from: ‘public-xml.gradle’

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

  1. afterEvaluate {
  2.     for (variant in android.applicationVariants) {
  3.         def scope = variant.getVariantData().getScope()
  4.         String mergeTaskName = scope.getMergeResourcesTask().name
  5.         def mergeTask = tasks.getByName(mergeTaskName)
  6.         mergeTask.doLast {
  7.             copy {
  8.                 int i=0
  9.                 from(android.sourceSets.main.res.srcDirs) {
  10.                     include ‘values/public.xml’
  11.                     rename ‘public.xml’, (i++ == 0? “public.xml”: “public_${i}.xml”)
  12.                 }
  13.                 into(mergeTask.outputDir)
  14.             }
  15.         }
  16.     }
  17. }

这个脚本与Library中脚本的唯一区别就是applicationVariantslibraryVariants
4、在app的build.gradle文件中添加如下内容:

  1. apply from: ‘public-xml.gradle’

5、然后,重新rebuild工程即可(核实AndroidStudio生成的R文件与public.xml文件中ID一致)。

分享到:

2 条评论

昵称
  1. 我赚啦

    抱着学习的态度来看看

  2. 我赚啦

    古人日三省其身,我从博客里吸收养分!