by Amour.wang

通常我们都是在电脑上开发android应用,但是有些情况下不方便带电脑,又想临时修改一些参数重新生成apk,于是就发现了一个神器 AIDE(http://www.android-ide.com/)。有免费的版本基本够用了,还有高级版需要$.

然而本篇文章并不是要介绍AIDE,出于程序猿一贯的好奇心,于是决定研究一下这当中的奥秘。本篇文章主要就是介绍apk 打包的流程及如何在手机上生成一个apk 的过程。

一、apk 的打包过程分析

既然是要生成Apk 那就得来了解一下APK 的生成过程,以往我们都是在eclipse 中点一下run 然后就可以在bin 文件夹下找到xxx.apk. 再高级一点的使用ant 编译,或者谷歌家大力推崇的 android studio 中的gradle build,都大致是这样。

但是没有过程啊,于是开始研究这个过程,基本可以分为如下几步

从这个图就可以很明确的看出蓝色的小方块就是我们需要的工具了,白色的小方块是输入,浅蓝色的小方块是中间产物。有了这个流程不管在什么平台上只要找到相应的工具都可以完成apk 的编译打包过程了,目前在 windows,OSX,linux 上网上都已经有很多人有分享了相关的资料的,这边我就不再重复了。下面重点来了,这个目前在网上很少有相关的资料,所以特别整理一下分享给大家。

一、在手机上完成APK 的编译打包。

按照上述的流程分为如下几个步骤,待我一一详细介绍

1.      aapt

google 官方有提供windows 下的aapt.exe 和 linux/mac 的aapt,可是这个aapt 是X86 架构的,在arm 下无法使用,于是想到可以自己编译一个arm 版的。

于是开始各种折腾,aapt 谷歌是有提供官方源码在frameworks/base/tools/aapt/下,又是各种折腾,最后还是直接用别人生成的的比较好用(以后有时间再折腾,还得看下aapt 的源码更深入了解apk 资源的编译原理,这个包含的内容较多就不在这篇详细介绍了)。

Aapt 的基本用法

Aapt  package

-f  overwrite file

-m  make package directoriesunder location specified by –J

[-S resource-sources [-S resource-sources ...]] \

-J  specify where to outputR.java resource constant definitions

-M  specify full path toAndroidManifest.xml to include in zip

-I  add an existing package tobase include set

-F  specify the apk file tooutput

在使用之前必须先把aapt 拷贝到自己应用的目录下,再chmod 为可执行,

String[] chmod = {"chmod", "744", aaptLoc.getAbsolutePath()};
Process chmodProcess = Runtime.getRuntime().exec(chmod);

private boolean runaapt(File aaptLoc, File androidJarLoc,String actName) {
    try {
       String[] args = {
               aaptLoc.getAbsolutePath(), //Thelocation of AAPT
               
"package", "-v", "-f", "-m",
                "-S", buildFolder.getAbsolutePath() + "/res/",                

 "-J", genFolder.getAbsolutePath(),
               
"-A", assetsFolder.getAbsolutePath(),              

 "-M", buildFolder.getAbsolutePath() + "/AndroidManifest.xml",               

"-I", androidJarLoc.getAbsolutePath(),

                "-F", binFolder.getAbsolutePath() + "/" + actName + ".apk.res"/

        };
        Process aaptProcess = Runtime.getRuntime().exec(args);
        int code =aaptProcess.waitFor();
        if (code!= 0){
            System.err.println("AAPTexited with error code " +code);
            copyStream(aaptProcess.getErrorStream(),System.out);
            return false;
        }
        return true;
    } catch (IOExceptione) {
       
System.out.println("AAPT failed");
        e.printStackTrace();
        return false;
    } catch (InterruptedException e) {
       
System.out.println("AAPT failed");
        e.printStackTrace();
        return false;
    }
}

2.      aidl

源码在frameworks/base/tools/aidl/,这个跟aapt 差不多,依葫芦画瓢,这边就不再详细描述。

3.      javac compiler

把java 变成class 文件,这个比较简单了,从SDK tools里面抠出来,直接就用了 ecj.jar

private boolean ecj(File androidJarLoc, String actName, String mainActivityLoc) {{System.out.println("Compiling with ECJ...");Main main = new Main(new PrintWriter(System.out), new PrintWriter(System.err), false, null, null);String[] args = {("-verbose"), "-extdirs", libsFolder.getAbsolutePath(),"-bootclasspath", androidJarLoc.getAbsolutePath(),"-classpath", srcFolder.getAbsolutePath()+ ":" + genFolder.getAbsolutePath()  + ":" + libsFolder.getAbsolutePath(),"-1.6","-target", "1.6", "-proc:none", "-d", binFolder.getAbsolutePath() + "/classes/", srcFolder.getAbsolutePath() + "/" + mainActivityLoc + "/" + actName + ".java", };System.out.println("Compiling: " + srcFolder.getAbsolutePath() + "/" + mainActivityLoc + "/" + actName + ".java");if (main.compile(args)) {System.out.println();return true;} else {System.out.println();System.out.println("Compilation with ECJ failed");return false;}}
}

4.dex

这个也是一样从SDK buildtools 里面抠出来 dx.jar,这些个jar的用法参数都是参考各路大神,时间有限也没再多去研究

private boolean dexer(int cores) {try {System.out.println("Dexing with DX Dexer...");String[] args;args = new String[]{"--verbose","--num-threads=" + cores,"--output=" + binFolder.getAbsolutePath() + "/classes.dex", // binFolder.getAbsolutePath() + "/classes/" };        com.android.dx.command.dexer.Main.Arguments dexArgs = new com.android.dx.command.dexer.Main.Arguments();dexArgs.parse(args);int resultCode = com.android.dx.command.dexer.Main.run(dexArgs);if (resultCode != 0) {System.err.println("DX Dexer result code: " + resultCode);return false;}return true;} catch (Exception e) {System.out.println("DX Dexer failed");e.printStackTrace();return false;}
}

5.      apkbuilder

一样的套路在 SDK 的tools 目录下 sdklib.jar,执行完这步,就已经生成了一个未签名的APK

private boolean buildapk(String sketchName, boolean verbose) {try {System.out.println("Building APK file with APKBuilder...");
com.android.sdklib.build.ApkBuilder builder = new com.android.sdklib.build.ApkBuilder(new File(binFolder.getAbsolutePath() + "/" + sketchName + ".apk.unsigned"),new File(binFolder.getAbsolutePath() + "/" + sketchName + ".apk.res"), new File(binFolder.getAbsolutePath() + "/classes.dex"), null, (verbose ? System.out : null)        );builder.addSourceFolder(srcFolder); builder.sealApk();return true;} catch (Exception e) {e.printStackTrace();System.out.println("APKBuilder failed");return false;}
}

6.      sign

这个eclipse中是调用java 来对apk 进行签名的没有现成的jar包可以用。从谷歌家拿 https://code.google.com/archive/p/zip-signer/,好了一切顺利的话(通常这种情况发生的概率跟中500万差不多),你就可以看到你在手机上生成的apk了

private boolean signApk(String actName) {String mode = "testkey";String inFilename = binFolder.getAbsolutePath() + "/" + actName + ".apk.unsigned";String outFilename = binFolder.getAbsolutePath() + "/" + actName + ".apk";ZipSigner signer;try {signer = new ZipSigner();signer.setKeymode(mode);signer.signZip(inFilename, outFilename);return true;} catch (Exception e) {e.printStackTrace();}return false;
}

二、小结

遗留的一些已知的问题:

1.      aidl 没有处理,这个应该跟aapt 类似,不过过程太折腾了,暂时没有时间弄

2.      多个dex 合并,这个部分没有处理,但是在SDK里面有看到对应的jar包,这部分应该还好

3.      JNI 编译,这个估计只有大神才可以做到

当中还有很多未知的问题,因个人精力所限,暂时也不能一一查明。

引用查询资料出处

http://www.cnblogs.com/royi123/p/3576746.html

http://1025250620.iteye.com/blog/1974214

https://code.google.com/archive/p/zip-signer/

如何在手机上打包生成APK相关推荐

  1. androidstudio打包apk 文件_Android 打包生成APK文件时报lintOptions配置错误

    问题描述: 今天在原来得基础上优化了部分功能,想打包成apk文件安装到手机上运行一下,结果在打包时发生了异常.具体异常如下图所示: 翻译右边的错误: Lint在组装释放目标时发现致命错误. 要继续下去 ...

  2. linux(以ubuntu为例)下Android利用ant自动编译、修改配置文件、批量多渠道,打包生成apk文件...

    原创,转载请注明:http://www.cnblogs.com/ycxyyzw/p/4555328.html  之前写过一篇<windows下Android利用ant自动编译.修改配置文件.批量 ...

  3. Android Studio打包生成APK

    Android Studio打包生成APK 当我们编写好代码,测试号应用后,需要在真机环境下测试,这个时候要生成apk,具体步骤如下: 如图,点击Build > Generate Signed ...

  4. as将安卓应用打包_Android Studio打包生成apk的方法(超级简单哦)

    释放双眼,带上耳机,听听看~! 打包文件是需要生成APK文件,其他人可以通过APK安装和使用,一般来说,包是指APK生成的发布版本,下文技术狗小编还介绍了Android Studio 超级简单的打包生 ...

  5. Android Studio 超级简单的打包生成apk

    为什么要打包: apk文件就是一个包,打包就是要生成apk文件,有了apk别人才能安装使用.打包分debug版和release包,通常所说的打包指生成release版的apk,release版的apk ...

  6. AndroidStudio打包生成apk

    AndroidStudio打包生成apk 1. 点击Build->Generate 2. 点击Create new,新建keystore 3. 填写相关内容 4. 填写路径,选择签名版本 注意 ...

  7. Android项目打包生成apk文件

    Android开发打包生成APK文件 打包apk文件分为两种 无需密钥的apk 有密钥的apk(常规) 他们的区别只是就是安全问题. 1.没有密钥的apk 点击之后会自动生成没有密钥的APK. 在编辑 ...

  8. Android开发超级简单的打包生成apk

    Androidk开发超级简单的打包生成apk 为什么要打包: apk文件就是一个包,打包就是要生成apk文件,有了apk别人才能安装使用.打包分debug版和release包,通常所说的打包指生成re ...

  9. 《Android studio 创建生成keystore SHA1值的申请 高德地图key值申请 android studio 打包生成apk》

    开发背景:目前做车载项目,领导要求用高德地图.整理了一下,差不多就是下面的目录: 一.创建生成keystore: 二.SHA1值的申请: 三.高德地图key值申请: 四.android studio ...

最新文章

  1. Python开发基础总结之XML+time+OO
  2. 花了几百万,创业一年学到了什么
  3. JS页面跳转的各种形式
  4. imgageJ开发【Java】
  5. es6 Class的严格模式
  6. HDFS源码解析:教你用HDFS客户端写数据
  7. [转]设定version 更新js缓存
  8. [原创]c# 加解密通用类
  9. 小米出品的最干净的APP,浏览器界的一股“清流”!
  10. linux的ip是什么,Linux-IP地址后边加个/8(16,24,32)是什么意思?
  11. Apache Kafka教程A系列:与Storm整合
  12. 怎样设置图片大小php,php调整图片大小的方法
  13. win10蓝牙鼠标、耳机无法连接,无蓝牙开关标志解决方案
  14. 期待已久的Apple Tablet PC - iPad 发布了
  15. 图片作为背景的相关方法
  16. 关于mysql的timestamp时间范围
  17. 数据库设计之物理结构设计
  18. linux替换文件中内容
  19. 夜深人静学32系列16——RTC实时时钟
  20. 凑够3000字畅聊我国大气污染当下严峻的形势

热门文章

  1. 什么是框架?框架和库有什么区别?
  2. Java日志框架简介
  3. win10 取消任务栏图标合并
  4. 倍福触摸屏维修倍福工控机维修CP3916-0010详解
  5. 苹果展开新显示器带动高阶需求:Mini LED背光技术
  6. Python100道经典练习题(一)
  7. 【转】人脸识别图像库
  8. Linux下浏览器的选择
  9. 手机虚拟化--人人都只用手机了
  10. 平阳县抖音平台直播运营主播带货第三期培训提升班开班啦!