守望者--AIR技术交流

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

搜索
热搜: ANE FlasCC 炼金术
查看: 1090|回复: 1

[Android] 解密ADT第二篇-编译APK资源

[复制链接]
  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    51788
    钢镚
    1422

    开源英雄守望者

    发表于 2015-1-19 10:45:58 | 显示全部楼层 |阅读模式
    前言

    继前一篇介绍了android编译aapt的工具之后,可能会困惑我为什么会花一大篇文章去写一个工具怎么用,在这第二篇文章我就详细分析 ADT是怎么使用aapt来编译android资源的.

    ADT编译资源

    我们用原生语言java编写android程序的时候,我们仅仅需要负责编写代码 配置权限参数的工作,而编译资源 编译代码 打包apk 全部交给eclipse或者交给androidSDK的工具代劳,同样我们编写AIR for android程序也是如此 我们仅仅编写代码  其他工作都一般交给FB代劳,而FB又交给ADT代劳,而ADT则指挥android SDK的各种工具工作,这编译资源 便是 从 完成代码之后的第一步工作.下面我们看看ADT是如此操作aapt实现编译android资源的.


    1.前期目录申请 文件定位

    1. <font color="rgb(51, 51, 51)"><b>//获取本机aapt工具路径
    2. String pathToApptTool = getAapt().getPath();
    3. //若不存在则报错 若要引发此错误很简单,把你AIR SDK上的aapt删掉便可
    4. if (!new File(pathToApptTool).exists()) {
    5.    throw new SDKDamagedException(pathToApptTool);
    6. }
    7. //申请临时文件夹
    8. File tempDir = Utils.createTempDirectory(this.OsTempDir);
    9. tempDir.deleteOnExit();
    10. //根据之前取得的-app.xml的参数信息创建androidManiFest.xml文件
    11. File androidManifestXmlFile = createAndroidManifestXml(packageName, descriptor, appVersionCode, tempDir);
    12. if (!androidManifestXmlFile.exists()) {
    13.    new IOException("Unable to create AndroidManifest.");
    14. }

    15. //获取目录绝对路径 用来存放R.java文件
    16. //编译资源的结果会生成R.java
    17. //这点在上一篇的命令中已经验证
    18. String destDirForRJavaFile = tempDir.getCanonicalPath();
    19. //获取绝对路径,用来存放R.java编译后的R.class
    20. //所有*.java源码都会被编译成*.class
    21. String destDirForRJavaClasses = tempDir.getCanonicalPath();
    22. //新建android资源文件
    23. File appEntryResources = editAppEntryResources(descriptor, tempDir);
    24. //新建运行时资源文件  若FB中勾选了运行时 则会使用到
    25. File captiveRuntimeResources = copySupportedLanguagesResources(new File(Utils.getSDKLibDir(), "android/lib/resources/captive_runtime/res"), tempDir, "captive_runtime_res");
    26. //定位android.jar 上一篇说了aapt编译需要指出android.jar文件
    27. File androidResJar = new File(Utils.getSDKLibDir(), "android/lib/resources/android-res.jar");
    28. //新建文件 用于编译后的输出
    29. File apkFileToOutput = new File(tempDir, "resources.apk");
    30. //若添加运行时 则会操作runtime.apk文件
    31. if ((hasCaptiveRuntime()) && (!captiveRuntimeResources.exists()))
    32.    throw new SDKDamagedException(captiveRuntimeResources.getPath());
    33. if (!androidResJar.exists()) {
    34.    throw new SDKDamagedException(androidResJar.getPath());
    35. }</b></font>
    复制代码
    2.组合aapt命令 用于编译

    1. <font color="rgb(51, 51, 51)"><b><b>//申请List用于存放命令
    2. List aaptCommand = new LinkedList();
    3. //aapt
    4. aaptCommand.add(pathToApptTool);
    5. //编译资源头命令
    6. aaptCommand.add("package");
    7. //强制资源国际化
    8. aaptCommand.add("-z");
    9. //更新现有的包 u = update;
    10. aaptCommand.add("-u");
    11. //指定R.java输出的路径
    12. aaptCommand.add("-J");
    13. aaptCommand.add(destDirForRJavaFile);
    14. //AndroidManifest.xml的路径;
    15. aaptCommand.add("-M");
    16. aaptCommand.add(androidManifestXmlFile.getPath());
    17. //指定资源目录 一般是 res
    18. aaptCommand.add("-S");
    19. aaptCommand.add(appEntryResources.getPath());
    20. //若打包运行时 则增加运行时资源
    21. boolean needsAutoAddOverlayArg = false;
    22. if (hasCaptiveRuntime())
    23. {
    24.   aaptCommand.add("-S");
    25.   aaptCommand.add(captiveRuntimeResources.getPath());
    26.   needsAutoAddOverlayArg = true;
    27. }
    28. //自动添加资源覆盖
    29. if (this.m_extraResourceDirectories != null) {
    30.   Iterator i = this.m_extraResourceDirectories.iterator();
    31.   while (i.hasNext())
    32.   {
    33.     aaptCommand.add("-S");
    34.     aaptCommand.add(i.next());
    35.     needsAutoAddOverlayArg = true;
    36.   }
    37. }
    38. if (needsAutoAddOverlayArg)
    39. {
    40.   aaptCommand.add("--auto-add-overlay");
    41. }

    42. aaptCommand.add("-I");
    43. aaptCommand.add(androidResJar.getPath());
    44. aaptCommand.add("--min-sdk-version");
    45. aaptCommand.add("8");
    46. aaptCommand.add("--target-sdk-version");
    47. aaptCommand.add("14");
    48. aaptCommand.add("--version-code");
    49. aaptCommand.add(Integer.toString(appVersionCode));
    50. aaptCommand.add("--version-name");
    51. aaptCommand.add(descriptor.versionLabel());
    52. aaptCommand.add("-F");
    53. aaptCommand.add(apkFileToOutput.getPath());</b></b></font>
    复制代码
    经过上一段代码组合后,我们大体能分析出ADT调用aapt编译android项目的资源后的命令行如下:

    1. <font color="rgb(51, 51, 51)"><b><b>aapt package -z -u
    2. -J javaFilePath
    3. -M androidMainfast.xml
    4. -S appResourcePath
    5. -S runtimeAsset
    6. -S otherAsset
    7. -I path/android.jar
    8. --min-sdk-version 8
    9. --target-sdk-version 14
    10. --version-code xxxx//-app.xml中的versionNumber
    11. --version-name xxxx//-app.xml中的versionLabel
    12. -F outPath //输出文件夹</b></b></font>
    复制代码
    3.调用aapt编译

    1. <font color="rgb(51, 51, 51)"><b><b><b>//输出字符串,用来存放aapt错误信息  若有的话
    2. String aaptOutputString = null;
    3. try {
    4.   //新建builder
    5.    ProcessBuilder pb = new ProcessBuilder(aaptCommand);
    6.    Process p = pb.start();
    7.    ByteArrayOutputStream aaptOutput = new ByteArrayOutputStream();
    8.    //指定错误信息输出
    9.    new Utils.OutputEater(p.getErrorStream(), aaptOutput).start();
    10.    new Utils.OutputEater(p.getInputStream()).start();
    11.    //开始编译 等待返回 这里类似我们AS3调用cmd操作各种命令 大概这意思
    12.    p.waitFor();
    13.    if (p.exitValue() != 0)
    14.      //若失败 则输出到字符串  ps:0表示成功
    15.      aaptOutputString = new String(aaptOutput.toByteArray(), "UTF-8");
    16. }
    17. catch (Exception e)
    18. {
    19.    throw new IOException("Unable to run aapt");
    20. }
    21. if (aaptOutputString != null)
    22. {
    23.    //注意:aapt tool failed  请问你打包APK出错的时候是不是非常常见?
    24.    //不信可以看下图
    25.    throw new ADTException("aapt tool failed:" + aaptOutputString.toString(), 17);
    26. }
    27. //新建R.java文件
    28. File rJavaFile = new File(destDirForRJavaFile, "R.java");
    29. if (!rJavaFile.exists())
    30.    throw new IOException("could not generate an R.java file.");
    31. //把R.java编译成jar文件
    32. File resourceJarFile = ResourceBytecodeGenerator.generateFromRFile(rJavaFile, new File(destDirForRJavaClasses));
    33. if (!resourceJarFile.exists())
    34.    throw new IOException("could not generate bytecode for R.java class.");
    35. if (!apkFileToOutput.exists()) {
    36.    throw new IOException("could not generate a resource apk.");
    37. }

    38. //编译资源结束 存好 resource.jar apk
    39. this.m_resourceJar = resourceJarFile;
    40. this.m_resourceApk = apkFileToOutput;</b></b></b></font>
    复制代码
    附图一张,相信这个图在你编写ANE打包进去APK的时候肯定遇到过:
    [/url]

    aapt tool failed 有没看到??看完这篇文章 你应该能理解这个错误信息的根源了.

    案例地址

    Anti-ADT:[url=https://github.com/recter/Anti-ADT]https://github.com/recter/Anti-ADT






    本文来自:http://shadowkong.com/archives/1408

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    守望者AIR技术交流社区(www.airmyth.com)
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    51788
    钢镚
    1422

    开源英雄守望者

     楼主| 发表于 2015-1-19 11:05:31 | 显示全部楼层
    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    
    关闭

    站长推荐上一条 /4 下一条

    QQ|手机版|Archiver|网站地图|小黑屋|守望者 ( 京ICP备14061876号

    GMT+8, 2019-11-18 16:47 , Processed in 0.049384 second(s), 35 queries .

    守望者AIR

    守望者AIR技术交流社区

    本站成立于 2014年12月31日

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