一个使用命令行编译Android项目的工具类

简单介绍

编译apk项目须要使用的几个工具,基本都在sdk中,它们各自是(Windows系统):

  • 1.aapt.exe

    资源打包工具
  • 2.android.jar

    Android编译工具
  • 3.dx.bat

    dex文件生成工具
  • 4.sdklib.jar

    生成apk
  • 5.jarsigner

    签名工具

准备

在打包前。须要的环境例如以下:

1.JDK1.6+

2.Android SDK

3.上述5个工具的路径

打包过程

1.生成R.java文件

比方:

aapt package -f -m -J ./gen -S res -M AndroidManifest.xml -I D:\android_sdk_for_studio\platforms\android-22\android.jar

2.清空bin文件夹

清空上次生成的文件

3.编译java文件和jar包

javac -encoding GBK -target 1.5 -bootclasspath D:\android_sdk_for_studio\platforms\android-22\android.jar -d bin src\net\mobctrl\normal\apk\*.java gen\net\mobctrl\normal\apk\R.java -classpath libs\*.jar

4.使用dx工具打包成classes.dex

dx --dex --output=C:\Users\mochuan.zhb\newworkspace\BundleApk5\bin\classes.dex C:\Users\mochuan.zhb\newworkspace\BundleApk5\bin\

5.编译成资源文件

aapt package -f -M AndroidManifest.xml -S res -I D:\android_sdk_for_studio\platforms\android-22\android.jar -F bin\resources.ap_ --non-constant-id

6.使用sdklib.jar工具生成未签名的apk

java -cp D:\android_sdk_for_studio\tools\lib\sdklib.jar com.android.sdklib.build.ApkBuilderMain bin\MyCommond.apk -v -u -z bin\resources.ap_ -f bin\classes.dex -rf C:\Users\mochuan.zhb\newworkspace\BundleApk5\src

7.使用jarsigner对apk进行签名

jarsigner -verbose -keystore C:\test.keystore -storepass 123456 -keypass 123456 -signedjar C:\projectdemo-signed.apk C:\test.apk test

BuildApkUtils源代码。自己主动生成命令并执行

package com.taobao.trip;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List; /**
* @Author Zheng Haibo (mochuan)
* @Company Alibaba Group
* @PersonalWebsite http://www.mobctrl.net
* @version $Id: BuildUtils.java, v 0.1 2016年1月8日 下午8:47:42 mochuan.zhb Exp $
* @Description 在Windows平台,怎样使用命令行编译android项目
*/
public class BuildApkUtils { private static final String ANDROID_JAR_PATH = "D:\\android_sdk_for_studio\\platforms\\android-22\\android.jar"; private static final String AAPT_PATH = "D:\\mochuan.zhb\\android-sdks\\build-tools\\22.0.1\\aapt_alitrip.exe"; private static final String DX_PATH = "D:\\android_sdk_for_studio\\build-tools\\22.0.1\\dx.bat"; private static final String SDK_LIB_JAR_PATH = "D:\\android_sdk_for_studio\\tools\\lib\\sdklib.jar"; private static final String batchDir = System.getProperty("user.dir")
+ "\\batch\\"; private String projectDir;
private int packageId = 127; public BuildApkUtils() { } public BuildApkUtils(String projectDir) {
this.projectDir = projectDir;
} public BuildApkUtils(String projectDir, int packageId) {
this.projectDir = projectDir;
this.packageId = packageId;
} public void buildUnsingedApk() {
clearDir(batchDir);
clearDir(projectDir + "\\bin");
generateR(projectDir, packageId);
compileJavaFiles(projectDir);
buildDexFile(projectDir);
complieResources(projectDir, packageId);
buildUnsignedApk(projectDir, "unsigned.apk");
mergeExeBatchFiles();
} /**
* 第一步:产生R文件
*
* @param projectDir
* @param packageId
*/
private static void generateR(String projectDir, int packageId) {
StringBuffer command = new StringBuffer();
command.append(AAPT_PATH).append(" package -f -m -J ")
.append(projectDir).append("\\gen ").append("-S ")
.append(projectDir).append("\\res ").append("-M ")
.append(projectDir).append("\\AndroidManifest.xml ")
.append(" -A ").append(projectDir).append("\\assets ")
.append("-I ").append(ANDROID_JAR_PATH)
.append(" --non-constant-id -x --package-id ")
.append(packageId);
buildExeBatchFiles(command.toString(), "1.bat");
} /**
* 编译java文件
*
* @param projectDir
*/
private static void compileJavaFiles(String projectDir) {
StringBuffer command = new StringBuffer();
command.append("javac -target 1.5 -bootclasspath ")
.append(ANDROID_JAR_PATH).append(" -d ").append(projectDir)
.append("\\bin ");
List<String> javaFilePaths = new ArrayList<String>();
findJavaFiles(projectDir + "\\src", javaFilePaths);
findJavaFiles(projectDir + "\\gen", javaFilePaths);
for (String javaPath : javaFilePaths) {
command.append(javaPath).append(" ");
}
command.append("-classpath ").append(projectDir)
.append("\\libs\\.*jar");
buildExeBatchFiles(command.toString(), "2.bat");
} /**
* 创建dex文件
*
* @param projectDir
*/
private static void buildDexFile(String projectDir) {
StringBuffer command = new StringBuffer();
command.append(DX_PATH).append(" --dex --output=").append(projectDir)
.append("\\bin\\classes.dex").append(" ").append(projectDir)
.append("\\bin");
buildExeBatchFiles(command.toString(), "3.bat");
} /**
* 编译资源文件
*
* @param projectDir
*/
private static void complieResources(String projectDir, int packageId) {
StringBuffer command = new StringBuffer();
command.append(AAPT_PATH).append(" package -f -M ").append(projectDir)
.append("\\AndroidManifest.xml ").append("-S ")
.append(projectDir).append("\\res ").append("-I ")
.append(ANDROID_JAR_PATH).append(" -A ").append(projectDir)
.append("\\assets ").append(" -F ").append(projectDir)
.append("\\bin\\resources.ap_")
.append(" --non-constant-id -x --package-id ")
.append(packageId);
buildExeBatchFiles(command.toString(), "4.bat");
} /**
* 生成未签名的apk
*
* @param projectDir
* @param apkName
*/
private static void buildUnsignedApk(String projectDir, String apkName) {
StringBuffer command = new StringBuffer();
command.append("java -cp ").append(SDK_LIB_JAR_PATH)
.append(" com.android.sdklib.build.ApkBuilderMain ")
.append(projectDir).append("\\bin\\").append(apkName)
.append(" -v -u -z ").append(projectDir)
.append("\\bin\\resources.ap_").append(" -f ")
.append(projectDir).append("\\bin\\classes.dex")
.append(" -rf ").append(projectDir).append("\\src");
buildExeBatchFiles(command.toString(), "5.bat");
} /**
* 递归查找
*
* @param projectDir
* @param javaFilePaths
*/
private static void findJavaFiles(String projectDir,
List<String> javaFilePaths) {
File file = new File(projectDir);
File[] files = file.listFiles();
if (files == null || files.length == 0) {
return;
}
for (File f : files) {
if (f.isDirectory()) {
findJavaFiles(f.getAbsolutePath(), javaFilePaths);
} else {
if (f.getAbsolutePath().endsWith(".java")) {
javaFilePaths.add(f.getAbsolutePath());
}
}
}
} /**
* 清理文件夹
*
* @param projectDir
*/
private static void clearDir(String projectDir) {
File file = new File(projectDir);
File[] files = file.listFiles();
if (files == null || files.length == 0) {
return;
}
for (File f : files) {
if (f.isDirectory()) {
clearDir(f.getAbsolutePath());
} else {
f.delete();
}
}
} /**
* 创建批处理文件
*
* @param command
* @param file
*/
private static void buildExeBatchFiles(String command, String fileName) {
System.out.println(command);
if (!new File(batchDir).exists()) {
new File(batchDir).mkdirs();
}
String filePath = batchDir + fileName;
try {
writeFile(filePath, command);
} catch (IOException e) {
e.printStackTrace();
}
} private static void mergeExeBatchFiles() {
File file = new File(batchDir);
System.out.println("debug:current path = " + file.getAbsolutePath());
File[] files = file.listFiles();
if (files == null || files.length == 0) {
return;
}
Arrays.sort(files, new Comparator<File>() {
public int compare(File file1, File file2) {
if (file1.lastModified() > file2.lastModified()) {
return 1;
} else if (file1.lastModified() < file2.lastModified()) {
return -1;
} else {
return 0;
}
}
});
StringBuffer command = new StringBuffer();
for (File f : files) {
command.append("call ").append(f.getAbsolutePath()).append("\n");
}
try {
String filePath = batchDir + "build.bat";
writeFile(filePath, command.toString());
Runtime.getRuntime().exec("cmd /c start " + filePath);
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 写文件
*
* @param filePath
* @param sets
* @throws IOException
*/
private static void writeFile(String filePath, String content)
throws IOException {
FileWriter fw = new FileWriter(filePath);
PrintWriter out = new PrintWriter(fw);
out.write(content);
out.println();
fw.close();
out.close();
} }

使用

执行的时候,我们仅仅须要传入项目路径就可以:


public class BuildMain { private static final String PROJECT_PATH = "C:\\Users\\mochuan.zhb\\newworkspace\\BundleApk5"; private static final int PACKAGE_ID = 5; public static void main(String[] args) {
new BuildApkUtils(PROJECT_PATH, PACKAGE_ID).buildUnsingedApk();
} }

执行过程中。会将生成的命令打印出来:


D:\mochuan.zhb\android-sdks\build-tools\22.0.1\aapt_alitrip.exe package -f -m -J C:\Users\mochuan.zhb\newworkspace\BundleApk5\gen -S C:\Users\mochuan.zhb\newworkspace\BundleApk5\res -M C:\Users\mochuan.zhb\newworkspace\BundleApk5\AndroidManifest.xml -A C:\Users\mochuan.zhb\newworkspace\BundleApk5\assets -I D:\android_sdk_for_studio\platforms\android-22\android.jar --non-constant-id -x --package-id 5
javac -target 1.5 -bootclasspath D:\android_sdk_for_studio\platforms\android-22\android.jar -d C:\Users\mochuan.zhb\newworkspace\BundleApk5\bin C:\Users\mochuan.zhb\newworkspace\BundleApk5\src\net\mobctrl\normal\apk\BaseActivity.java C:\Users\mochuan.zhb\newworkspace\BundleApk5\src\net\mobctrl\normal\apk\BundleActivity.java C:\Users\mochuan.zhb\newworkspace\BundleApk5\src\net\mobctrl\normal\apk\FileUtils.java C:\Users\mochuan.zhb\newworkspace\BundleApk5\src\net\mobctrl\normal\apk\Utils.java C:\Users\mochuan.zhb\newworkspace\BundleApk5\gen\net\mobctrl\normal\apk\BuildConfig.java C:\Users\mochuan.zhb\newworkspace\BundleApk5\gen\net\mobctrl\normal\apk\R.java -classpath C:\Users\mochuan.zhb\newworkspace\BundleApk5\libs\.*jar
D:\android_sdk_for_studio\build-tools\22.0.1\dx.bat --dex --output=C:\Users\mochuan.zhb\newworkspace\BundleApk5\bin\classes.dex C:\Users\mochuan.zhb\newworkspace\BundleApk5\bin
D:\mochuan.zhb\android-sdks\build-tools\22.0.1\aapt_alitrip.exe package -f -M C:\Users\mochuan.zhb\newworkspace\BundleApk5\AndroidManifest.xml -S C:\Users\mochuan.zhb\newworkspace\BundleApk5\res -I D:\android_sdk_for_studio\platforms\android-22\android.jar -A C:\Users\mochuan.zhb\newworkspace\BundleApk5\assets -F C:\Users\mochuan.zhb\newworkspace\BundleApk5\bin\resources.ap_ --non-constant-id -x --package-id 5
java -cp D:\android_sdk_for_studio\tools\lib\sdklib.jar com.android.sdklib.build.ApkBuilderMain C:\Users\mochuan.zhb\newworkspace\BundleApk5\bin\unsigned.apk -v -u -z C:\Users\mochuan.zhb\newworkspace\BundleApk5\bin\resources.ap_ -f C:\Users\mochuan.zhb\newworkspace\BundleApk5\bin\classes.dex -rf C:\Users\mochuan.zhb\newworkspace\BundleApk5\src

參考

1.Android应用程序资源的编译和打包过程分析

2.Android 自己主动编译、打包生成apk文件 1 - 命令行方式

3.使用ANT打包Android应用

4.怎样改动android aapt源代码实现自己定义package ID

Author

郑海波-莫川

未经同意,不得转载

一个使用命令行编译Android项目的工具类的更多相关文章

  1. Ant 命令行编译Android项目

    首先把android sdk下的tools目录加到系统path环境变量里, 要么就得直接指定android.bat的绝对路径 对于一个新项目, 可以用这个命令创建需要的ant编译环境(可以看到andr ...

  2. 命令行编译java项目

    命令行编译java项目 项目名: testproj 目录 src -> cn -> busix -> test bin lib 编译项目 cd testproj javac -d . ...

  3. 韩顺平细说Servlet视频系列意外收获之用命令行编译带有包的java类解决方案

    命令行编译带有包的java类 在命令行编译这一块,基本上都是新手入门时了解一下,然后就直奔IDE而去.这样固然没错,就怕那些--.然后今天在视频中看到了这种方法,觉得可能会用到,所以就记录下来了,以备 ...

  4. Windows下使用命令行编译Qt项目(解决DLL丢失问题)

    一.前言 我之前用Qt做了个hello world,结果各种报错,一大堆DLL找不到,今天用命令行编译就通过了 二.准备工作 1.Visual Studio(有nmake就行) 2.Qt 3.把qma ...

  5. 打造一个全命令行的Android构建系统

    IDE都是给小白程序员的,大牛级别的程序员一定是命令行控,终端控,你看大牛都是使用vim,emacs 就一切搞定” 这话说的虽然有些绝对,但是也不无道理,做开发这行要想效率高,自动化还真是缺少不了命令 ...

  6. 用Gradle命令行编译Android工程

    在Android sdk 目录下的samples/android-21/ 文件夹下,任找一个工程,如果在命令行直接编译 可能会报这种错误:gradle buile.gradle FAILURE: Bu ...

  7. 命令行编译vs2013项目

    echo off path %SYSTEMROOT%\Microsoft.NET\Framework\v4.0.30319\ msbuild.exe .\src\ElectricManagement. ...

  8. 命令行编译vs10项目工程

    参考网址: http://www.oschina.net/question/234345_42135 1. 1.1.使用的命令行为:开始-->所有程序--> vs2020 --> V ...

  9. sublimetext 创建一个php命令行编译环境

    菜单栏=>工具->编译系统=>新编译系统(插入如下代码,前提是有php批处理 然后编译php ctrl+b即可) { "cmd": ["php" ...

随机推荐

  1. Ruby类扩张(extension)

    创建: 2017/09/07 更新: 2017/09/16 修改标题字母大小写 ruby ---> Ruby    扩张类  class 类名     扩张的内容  end           ...

  2. ecshop类的解析1

    前面写了一下我理解的ecshop数据库表,现在看一下我理解的ecshop的类. ecshop类,ECS是一个基础类,它的取得域名的函数我感觉是比较不错的. function get_domain() ...

  3. Django 创建新项目后要完成的几个步骤

    首先,在过一遍创建新项目的步骤: -创建一个新项目 -建了数据库后要确定自己是用 mysql数据库  还是用 sqlite3数据库 -如果是mysql数据库,那一堆配置 -如果是sqlite3数据库, ...

  4. python3爬取豆瓣排名前250电影信息

    #!/usr/bin/env python # -*- coding: utf-8 -*- # @File : doubanmovie.py # @Author: Anthony.waa # @Dat ...

  5. windows 装XP系统

    笔记本型号:HPCQ40-506AX 1.在BIOS中更改启动顺序:将USB设为第一启动项2.插入装有PE系统的USB设备3.开机后一直按F124.到达选择系统界面,目前我的HPCQ40用其他系统进去 ...

  6. PHP获取远程和本地文件信息(汇总)

    1.PHP filesize() 函数filesize() 函数返回指定文件的大小.若成功,则返回文件大小的字节数.若失败,则返回 false 并生成一条 E_WARNING 级的错误. 但是只能获取 ...

  7. MyEclipse加入jquery.js文件missing semicolon的错误

    今天打开项目,发现有一个小红叉,虽然不影响项目的编译和运行,但是看着非常影响心情.原因是jquery-1.8.2.min.js报了一堆missing semicolon的错误.之所以会这样,其实是My ...

  8. SQLite-编译指示

    SQLite – 编译指示 SQLite编译指示命令(PRAGMA)是一个特殊的命令是用于控制各种环境变量和状态标志在SQLite的环境.编译指示值可以读取,也可以根据需求设置. 语法: 查询当前的编 ...

  9. dubbo之集群容错

    在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试. 集群容错模式 1. Failover Cluster 失败自动切换,当出现失败,重试其它服务器 .通常用于读操作,但 ...

  10. OpenCv:椭圆上点的计算方程

    椭圆         椭圆(Ellipse)是平面内到定点F1.F2的距离之和等于常数(大于|F1F2|)的动点P的轨迹,F1.F2称为椭圆的两个焦点.其数学表达式为:                 ...