咱们平时都是用Android Studio进行Android应用的开发,Android Studio构建APK是经过调用Gradle脚本实现的,而Gradle脚本最终是经过调用Android SDK Build Tools里的各类命令行工具实现的。php
下面尝试直接用Build Tools构建一个极简的Hello World APK,了解一下这个过程和各个工具的基本用法。html
整个构建过程大体分为如下几步:java
项目的目录结构及文件源码以下:android
D:\helloworld>tree /F
│ AndroidManifest.xml
│
├─compiled
│
├─java
│ └─com
│ └─cdjtest
│ └─helloworld
│ MainActivity.java
│
└─res
├─drawable
│ ic_launcher.png
│
├─layout
│ activity_main.xml
│
└─values
strings.xml
复制代码
AndroidManifest.xmlbash
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.cdjtest.helloworld">
<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@android:style/Theme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
复制代码
MainActivity.javaapp
package com.cdjtest.helloworld;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
复制代码
activity_main.xmlide
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="Hello World!"/>
复制代码
strings.xml工具
<resources>
<string name="app_name">helloworld</string>
</resources>
复制代码
先设置一下环境变量,将Build Tools 28.0.3的路径加到PATH中,方便调用优化
D:\helloworld>set PATH=%PATH%;$ANDROID_HOME%\build-tools\28.0.3\
复制代码
编译res目录下的3个资源文件,生成.flat中间二进制文件ui
D:\helloworld>aapt2 compile res\values\strings.xml -o compiled\
D:\helloworld>aapt2 compile res\layout\activity_main.xml -o compiled\
D:\helloworld>aapt2 compile res\drawable\ic_launcher.png -o compiled\
复制代码
连接.flat文件,生成helloworld.unsigned.apk(还未包含DEX字节码),--java java
参数指定在java目录生成R.java文件,和MainActivity.java在同一目录
D:\helloworld>aapt2 link -o helloworld.unsigned.apk ^
-I %ANDROID_HOME%\platforms\android-28\android.jar ^
compiled\values_strings.arsc.flat ^
compiled\layout_activity_main.xml.flat ^
compiled\drawable_ic_launcher.png.flat ^
--manifest AndroidManifest.xml --java java\
复制代码
用javac将MainActivity.java和R.java编译成.class文件
D:\helloworld>javac java\com\cdjtest\helloworld\*.java -classpath %ANDROID_HOME%\platforms\android-28\android.jar
复制代码
用d8将.class编译成classes.dex
,(d8和dx的对比可参考Jake大神的这篇文章)
D:\helloworld>d8 --lib %ANDROID_HOME%\platforms\android-28\android.jar --release --output . java\com\cdjtest\helloworld\*.class
复制代码
将classes.dex
导入APK中
D:\helloworld>aapt add helloworld.unsigned.apk classes.dex
复制代码
用zipalign优化APK,主要做用是内存对齐,提升运行时读取资源的效率
D:\helloworld>zipalign -p 4 helloworld.unsigned.apk helloworld.unsigned.aligned.apk
复制代码
用JDK自带的keytool工具生成keystore文件my-release-key.jks
D:\helloworld>keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-alias
复制代码
用apksigner和my-release-key.jks
签名APK,生成helloworld-release.apk
D:\helloworld>apksigner sign --ks my-release-key.jks --out helloworld-release.apk helloworld.unsigned.aligned.apk
Keystore password for signer #1:
复制代码
最终的目录结构:
D:\helloworld>tree /F
│ AndroidManifest.xml
│ classes.dex
│ helloworld-release.apk
│ helloworld.unsigned.aligned.apk
│ helloworld.unsigned.apk
│ my-release-key.jks
│
├─compiled
│ drawable_ic_launcher.png.flat
│ layout_activity_main.xml.flat
│ values_strings.arsc.flat
│
├─java
│ └─com
│ └─cdjtest
│ └─helloworld
│ MainActivity.class
│ MainActivity.java
│ R$drawable.class
│ R$layout.class
│ R$string.class
│ R.class
│ R.java
│
└─res
├─drawable
│ ic_launcher.png
│
├─layout
│ activity_main.xml
│
└─values
strings.xml
复制代码
安装APK
D:\helloworld>adb install helloworld-release.apk
Success
复制代码
成功运行屏幕中间可见"Hello World!"。