We usually use Android Studio to develop Android applications. Android Studio builds APK by calling Gradle scripts. Gradle scripts are ultimately implemented by calling various command line Tools in the Android SDK Build Tools.

Let’s try building a simple Hello World APK directly with Build Tools to understand the process and the basic usage of each tool.

The whole construction process can be roughly divided into the following steps:

  1. Compile resource files with AAPT2 to generate intermediate binaries
  2. Intermediate files are merged with aapT2 links to generate APK without code, and r.java is generated
  3. Compile Java source files with Javac, resulting in. Class Java bytecode files
  4. Compile. Class into DEX bytecode files using D8
  5. Import the DEX file to the APK
  6. Sign the APK

Create the project source file

The directory structure and file source code of the project are as follows:

D:\ helloWorld >tree /F │ ├─ already │ ├─ Java │ ├─com │ ├─ cdjtest │ ├─ helloWorld │ ├.java │ └ ─ res ├ ─ drawable │ ic_launcher. PNG │ ├ ─ layout │ activity_main. XML │ └ ─ values strings. The XMLCopy the code

AndroidManifest.xml

<?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>
Copy the code

MainActivity.java

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); }}Copy the code

activity_main.xml

<?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!"/>
Copy the code

strings.xml

<resources>
    <string name="app_name">helloworld</string>
</resources>
Copy the code

Compile resource files with AAPT2

Set environment variables and add Build Tools 28.0.3 to PATH for easy call

D:\helloworld>set PATH=%PATH%;$ANDROID_HOME% \ build - tools \ 28.0.3 \Copy the code

Compile 3 resource files in the RES directory to generate. Flat intermediate binary

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\Copy the code

The.flat file that generates helloworld.unsigned. Apk (not yet including DEX bytecode), — Java The Java argument specifies that r.Java is generated in the Java directory, the same directory as 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\
Copy the code

Compile the source code with JAVAC and D8

Compile mainActivity. Java and r.java into.class files using javac

D:\helloworld>javac java\com\cdjtest\helloworld\*.java -classpath %ANDROID_HOME%\platforms\android-28\android.jar
Copy the code

Compile.class to classes.dex with d8.

D:\helloworld>d8 --lib %ANDROID_HOME%\platforms\android-28\android.jar --release --output . java\com\cdjtest\helloworld\*.class
Copy the code

Import classes.dex into APK

D:\helloworld>aapt add helloworld.unsigned.apk classes.dex
Copy the code

APK signature

APK optimization with Zipalign is mainly used to align memory and improve the efficiency of reading resources at run time

D:\helloworld>zipalign -p 4 helloworld.unsigned.apk helloworld.unsigned.aligned.apk
Copy the code

Use the JDK keytool to generate the keystore file my-release-key. JKS

D:\helloworld>keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-alias
Copy the code

Sign the APK with apkSigner and my-release-key. JKS to generate 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:
Copy the code

The final directory structure:

D: \ helloworld > tree/F │ AndroidManifest. XML │ classes. Dex │ helloworld - the apk │ helloworld. Unsigned. Aligned. The apk │ Apk │ my-release-key. JKS │ ├─ Compiled │ drawable_ic_launcher. PNG Layout_activity_main. XML MainActivity. Class │ MainActivity. Java │ R$drawable.class
│                  R$layout.class
│                  R$string.class │ R.c lass │ R.j ava │ └ ─ res ├ ─ drawable │ ic_launcher. PNG │ ├ ─ layout │ activity_main. XML │ └ ─ values strings. The XMLCopy the code

Install the APK

D:\helloworld>adb install helloworld-release.apk
Success
Copy the code

Successful run “Hello World!” in the middle of the screen. .

References:

  • www.ignas.in/blog/190226…
  • Developer.android.com/studio/comm…
  • Developer.android.com/studio/comm…
  • Developer.android.com/studio/publ…