发新帖

【新人报到贴】Android回编译后运行报找不到ResourceID的错

[复制链接]
3915 1
  我们都是知道,在回编译之前,很有可能我们会对我们的android资源res进行一些修改,更有可能会对包名进行修改,所以回编译的时候,我们会利用以下步骤来进行编译打包:
1.去掉public.xml文件
2.生成用来存放R文件的gen文件夹
3.aapt生成关联了新资源和新包名的R.java
4.javac一下R.java,编译成class文件
5.打包这个class文件
6.dx工具把这个class文件编译为dex文件
7.利用baksmali.jar的包把dex文件编译为android设备执行的汇编smali语言
8.然后把得到的smali文件替换掉之前存在的文件
9.再利用apktool打包
10.签名
        至于关键的命令,读者就自行去网站里面找找了,很多,这里不是重点,就不多叙说了。
      经历以上的步骤之后,我们往往可以得到一个经过修改资源和包名的可运行的App,但是,这并不适用于所有的情况。因为我们偶尔会遇到这种情况,安装了app,运行它,运行到这个已修改的app的某个界面的时候,报出以下的错误:
   
   Android Resources$NotFoundException: Resource ID #0x0 Issue
      发生这些错误,通常因为工程中的有部分代码是依赖库的形式加入编译当中的,当包名改变或资源改变的时候,依赖库的代码是已写死为依赖修改前的包名或资源Id,所以导致利用上述回编译的时候依赖库方面的代码无法找到新的R.smali,导致无法找到资源id,以致运行报错。
解决上述的这个问题,首先要清楚为何我们在Eclipse中直接编译apk时没有发生这样的问题?显然,Eclipse中的编译方式与我上面说的步骤还是有很大不一样,首先它利用预先写好的ant问题,一个apkbuilder的文件装载着,这个文件里面描述如何把id打包,资源打包,代码编译。
很重要的一点,在Eclipse打包中对于第三方工程依赖库的描述是写在 project.properties 文件中的,打包过程中会引用到这个文件去找到第三方工程旗下的资源和manifest.问题就在这点上了,Eclipse在打包的时候会找到这些资源并引用到工程中进行编译,并且这种的依赖编译是死依赖,与第三方工程的包名绑定,例如第三方工程代码中使用了R.id.xxx;这种方式来描述资源的时候,就是一种死依赖模式(自定义的,请喷),但是我上述的步骤并没有这样的依赖编译的步骤,原因在于对于一个完整的apk,我根本就不知道它已经引用了第三方工程的依赖库,所以往往这种情况是不可预知的,除非你是写这个apk的人。
     所以一般情况,这种局比较难拆。特别是依赖一些比较私有化的第三方工程依赖包,就无法进行了,但对于一些公开的第三方依赖库的话,也不是不能拆,关键是找到依赖库的包名是什么,这个时候就需要不断找smali文件夹里面的R.smali文件,自行可以写个批处理命令找出来,或者搜索一下,不难,得到R.smali就可以根据其文件夹推断出其依赖包的包名,得到包名之后,可以去网上下载依赖库下来,一定要和接入的是统一版本才行。下载回来后,比对res下面的资源把是依赖库的资源从res中全部删除。然后真正的工作开始了。
报错的原因:找不到第三方资源Id
分析:编译的时候,没有对第三方资源进行依赖引用编译。
所以在以下的步骤中会对第三方资源进行依赖编译,关键命令看下面:

1.aapt编译项目包名下的资源
  
[Java] 纯文本查看 复制代码
	<!-- Generate the project's R.java file from the project's res and library's res directory 生成R文件  -->
		<!--  生成主程序的R文件  -->
	<target name="generat-main-res" depends="copy_smali_res">
		<echo>Generating this  main project's R.java.................</echo>
		<exec executable="${aapt}" failonerror="true">
			<arg value="package" />
			<arg value="-m" />
			<arg value="-J" />
			<arg value="${gen-dir}" />
			<arg value="-M" />
			<arg value="${project-base-dir}/AndroidManifest.xml" />
			<arg value="-S" /><!-- S指定res目录,生成对应的ID,可多个-->
			<arg value="${res-dir}" />
			<arg value="-S" />
			<arg value="${thrid-lib}/res" /><!-- 注意点:同时需要调用Library的res-->
			<arg value="-I" />
			<arg value="${android-jar}" />
		     <arg value="--auto-add-overlay" /> <!-- 这个重要,覆盖资源,不然报错-->
		</exec>
</target>



2.aapt依赖库下包名的资源
[Java] 纯文本查看 复制代码
<!-- Generate the project's R.java file from the project's res and library's res directory 生成R文件  -->
				<!--  生成依赖程序的R文件  -->
	<target name="generat-lib-res" depends="generat-main-res">
		<echo>Generating this lib  project's R.java.................</echo>
		<exec executable="${aapt}" failonerror="true">
			<arg value="package" />
			<arg value="-m" />
			 <arg value="--non-constant-id" /> <!-- 加了这个参数-->
              <arg value="--auto-add-overlay" />
			<arg value="-J" />
			<arg value="${gen-dir}" />
			<arg value="-M" />
			<arg value="${thrid-lib}/AndroidManifest.xml" /><!-- lib的AndroidManifest -->
			<arg value="-S" />
			<arg value="${res-dir}" />
			<arg value="-S" />
			<arg value="${thrid-lib}/res" />
			<arg value="-I" />
			<arg value="${android-jar}" />
		</exec>
</target>



  接着处理上述步骤4.5.6.7.8.
  在打包之后,再把依赖库的资源复制到项目工程中,然后才9.10.
  And,Done~!




举报 使用道具

回复

精彩评论1

tivhyy    发表于 2015-9-11 11:55:19 | 显示全部楼层
最后一句写错了,应该在打包前把资源复制进去

举报 使用道具

回复 支持 反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表