Article^ Parent
使用命令行工具开发 Android 应用
Date: | 2023-12-29 17:29:01 |
Description: | 不想用 IDE 和 Android 应用构建系统 Gradle,太庞大了,尝试用命令行工具通过简单直接的方式构建一个 Android 应用。 |
Keywords: | Android, Command Line Tools, Android Studio, Gradle |
Category: | engineering_technology/computer/code_platform/android |
Tag: | android, build, android studio |
Link: | https://www.diewuxi.com/blog/article/51.html |
1 前言
Android Studio 是开发 Android 应用的官方 IDE(集成开发环境),它可以完成项目创建、代码编写、应用构建、签名、测试等任务。然而,有人出于某些原因并不想使用 IDE 和 Android 应用构建系统--Gradle,只希望用基本的命令行工具来完成 Android 应用的开发。首先,如果不用 IDE 提供的界面设计工具,那么 Android 应用的所有文本类型的源文件都可以用任何一个文本编辑器完成编写,包括命令行文本编辑器。其次,其实 Android 官方也提供了命令行工具来实现应用的构建。需要指出,Android 开发者网站虽然介绍了在命令行下构建应用,但是其中代码的构建仍然用的是 gradlew 这个脚本,使用的是 Gradle 构建系统,这需要提供项目文件,实际上只是项目的构建过程在命令行下,项目创建和管理仍需要 IDE。
在 Android Studio 的下载页面,除了它身下载链接外,下方还有 Command Line Tool 的下载链接,并指出 Command Line Tool 包含在 Android Studio 中,但是用户可以只下载 Command Line Tools,然后用其中的 sdkmanager 工具下载其它 SDK 包,Android 开发者网站提供了这些工具的使用说明。sdkmanager 可以安装的工具包括:Android SDK Build Tools,Android SDK Platform Tools,Android SDK Platform,Android Emulator 等,其中 Android SDK Build Tools 提供的命令行工具用于构建 Android 应用。
另外对于使用 Java 语言开发的 Android 应用,Java Development Kit 是必须的。
把庞大复杂的 Android Studio 和 Android 构建系统先放一边,本文记录了用命令行工具通过简单直接的方式展示一个 Android 应用是如何一步一步生成的。
本人测试所用的开发环境和软件版本如下:
macOS Sonoma 14.1
OpenJDK v21.0.1 macos aarch64
javac v21.0.1
keytool v21.0.1
Android SDK Build Tools v30.0.3
aapt v0.2-6966805
dx v1.16
zipalign unknown
apksigner v0.9
Android SDK Platform Tools v34.0.5
adb
2 项目文件
项目名称为 hello_world
,目录结构如下:
hello_world/
src/
com/
diewuxi/
hello_world/
MainActivity.java
res/
layout/
activity_main.xml
values/
strings.xml
gen/
bin/
AndroidManifest.xml
以下给出各文件内容。
2.1 src/com/diewuxi/hello_world/MainActivity.java
文件:
package com.diewuxi.hello_world;
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);
}
}
2.2 res/layout/activity_main.xml
文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="@string/hello_msg"
tools:context=".MainActivity"
/>
</LinearLayout>
2.3 res/values/strings.xml
文件:
<resources>
<string name="app_name">Hello World APP</string>
<string name="hello_msg">Hello World!</string>
<string name="menu_settings">Settings</string>
<string name="title_activity_main">MainActivity</string>
</resources>
2.4 AndroidManifest
文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.diewuxi.hello_world"
android:versionCode="1"
android:versionName="1.0"
>
<uses-sdk
android:minSdkVersion="21"
android:targetSdkVersion="21"
/>
<application
android:label="@string/app_name"
>
<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>
3 构建 app 步骤
3.1 处理资源文件,生成 R.java 文件到 gen 目录
$ aapt package \
-M AndroidManifest.xml \
-S res \
-I /Users/fjc/home/opt/android-sdk/android_sdk-macos/platforms/android-21/android.jar \
--extra-packages "" \
--auto-add-overlay \
-m -J gen \
-f \
-v
aapt 是 Android Asset Packaging Tool, aapt package 子命令打包 android 资源文件,选项说明如下:
Android Asset Packaging Tool
Usage:
aapt p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \
[-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \
[--debug-mode] [--min-sdk-version VAL] [--target-sdk-version VAL] \
[--app-version VAL] [--app-version-name TEXT] [--custom-package VAL] \
[--rename-manifest-package PACKAGE] \
[--rename-instrumentation-target-package PACKAGE] \
[--utf16] [--auto-add-overlay] \
[--max-res-version VAL] \
[-I base-package [-I base-package ...]] \
[-A asset-source-dir] [-G class-list-file] [-P public-definitions-file] \
[-D main-dex-class-list-file] \
[-S resource-sources [-S resource-sources ...]] \
[-F apk-file] [-J R-file-dir] \
[--product product1,product2,...] \
[-c CONFIGS] [--preferred-density DENSITY] \
[--split CONFIGS [--split CONFIGS]] \
[--feature-of package [--feature-after package]] \
[raw-files-dir [raw-files-dir] ...] \
[--output-text-symbols DIR]
Package the android resources. It will read assets and resources that are
supplied with the -M -A -S or raw-files-dir arguments. The -J -P -F and -R
options control which files are output.
-M
specify full path to AndroidManifest.xml to include in zip
-A
additional directory in which to find raw asset files
-S
directory in which to find resources. Multiple directories will be scanned
and the first match found (left to right) will take precedence.
-J
specify where to output R.java resource constant definitions
-P
specify where to output public resource definitions
-F
specify the apk file to output
-I
add an existing package to base include set
--extra-packages
generate R.java for libraries. Separate libraries with ':'.
--auto-add-overlay
Automatically add resources that are only in overlays.
-m
make package directories under location specified by -J
-f
force overwrite of existing files
3.2 编译 src 和 gen 目录下的 java 文件,输出 class 文件到 bin 目录
$ javac \
--boot-class-path /Users/fjc/home/opt/android-sdk/android_sdk-macos/platforms/android-21/android.jar \
--class-path "" \
-d bin \
--source 8 \
--target 8 \
-verbose \
src/com/diewuxi/hello_world/*.java gen/com/diewuxi/hello_world/R.java
选项解释如下:
Usage: javac <options> <source files>
where possible options include:
--boot-class-path <path>, -bootclasspath <path>
Override location of bootstrap class files
--class-path <path>, -classpath <path>, -cp <path>
Specify where to find user class files and annotation processors
-d <directory>
Specify where to place generated class files
--source <release>, -source <release>
Provide source compatibility with the specified Java SE release.
Supported releases:
8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
--target <release>, -target <release>
Generate class files suitable for the specified Java SE release.
Supported releases:
8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
3.3 转换 bin 目录下的 class 文件,输出 classes.dex 文件 到工程根目录
$ dx --dex --output=classes.dex --verbose bin
dx --dex 子命令转换 java class 文件到 dex 文件,选项如下:
dx --dex [--debug] [--verbose] [--positions=<style>] [--no-locals]
[--no-optimize] [--statistics] [--[no-]optimize-list=<file>] [--no-strict]
[--keep-classes] [--output=<file>] [--dump-to=<file>] [--dump-width=<n>]
[--dump-method=<name>[*]] [--verbose-dump] [--no-files] [--core-library]
[--num-threads=<n>] [--incremental] [--force-jumbo] [--no-warning]
[--multi-dex [--main-dex-list=<file> [--minimal-main-dex]]
[--input-list=<file>] [--min-sdk-version=<n>]
[--allow-all-interface-method-invokes]
[<file>.class | <file>.{zip,jar,apk} | <directory>] ...
Convert a set of classfiles into a dex file, optionally embedded in a
jar/zip. Output name must end with one of: .dex .jar .zip .apk or be a
directory.
Positions options: none, important, lines.
--multi-dex: allows to generate several dex files if needed. This option is
exclusive with --incremental, causes --num-threads to be ignored and only
supports folder or archive output.
--main-dex-list=<file>: <file> is a list of class file names, classes
defined by those class files are put in classes.dex.
--minimal-main-dex: only classes selected by --main-dex-list are to be put
in the main dex.
--input-list: <file> is a list of inputs.
Each line in <file> must end with one of: .class .jar .zip .apk or be a
directory.
--min-sdk-version=<n>: Enable dex file features that require at least sdk
version <n>.
3.4 打包资源文件到 apk 文件中
$ aapt package \
-M AndroidManifest.xml \
-S res \
-I /Users/fjc/home/opt/android-sdk/android_sdk-macos/platforms/android-21/android.jar \
--extra-packages "" \
--auto-add-overlay \
-F com.diewuxi.hello_world.apk \
-f \
-v
该命令与之前 aapt 类似,不是 -m -J 输出 R.java 文件。而是 -F 输出 apk 文件,这是最终 apk 的前身。这个 apk 文件里面只有资源文件,使用 aapt 工具 aapt list 子命令列出 apk 文件内容:
$ aapt list -v com.diewuxi.hello_world.apk
Archive: com.diewuxi.hello_world.apk
Length Method Size Ratio Offset Date Time CRC-32 Name
-------- ------ ------- ----- ------- ---- ---- ------ ----
1636 Deflate 620 62% 0 01-01-80 08:00 67731b84 AndroidManifest.xml
8328 Deflate 1381 83% 669 01-01-80 08:00 ffffffff86d49223 res/layout/activity_main.xml
2404 Stored 2404 0% 2108 01-01-80 08:00 302b1639 resources.arsc
-------- ------- --- -------
12368 4405 64% 3 files
3.5 添加 dex 文件到 apk 文件中
$ aapt add -v com.diewuxi.hello_world.apk classes.dex
该命令为 aapt add 子命令,选项解释如下:
aapt a[dd] [-v] file.{zip,jar,apk} file1 [file2 ...]
Add specified files to Zip-compatible archive.
此时 apk 文件内容如下:
$ aapt list -v com.diewuxi.hello_world.apk
Archive: com.diewuxi.hello_world.apk
Length Method Size Ratio Offset Date Time CRC-32 Name
-------- ------ ------- ----- ------- ---- ---- ------ ----
1636 Deflate 620 62% 0 01-01-80 08:00 67731b84 AndroidManifest.xml
8328 Deflate 1381 83% 669 01-01-80 08:00 ffffffff86d49223 res/layout/activity_main.xml
2404 Stored 2404 0% 2108 01-01-80 08:00 302b1639 resources.arsc
6004 Deflate 2733 54% 4556 01-01-80 08:00 ffffffffa3c673f9 classes.dex
-------- ------- --- -------
18372 7138 61% 4 files
3.6 zip 文件对齐
$ zipalign -f -p -v 4 com.diewuxi.hello_world.apk com.diewuxi.hello_world-aligned.apk
zipalign 是 zip 文件对齐工具,见详细说明,目的是为了加快 Android 应用的运行速度,减少内存占用,选项说明如下:
Zip alignment utility
Copyright (C) 2009 The Android Open Source Project
Usage: zipalign [-f] [-p] [-v] [-z] <align> infile.zip outfile.zip
zipalign -c [-p] [-v] <align> infile.zip
<align>: alignment in bytes, e.g. '4' provides 32-bit alignment
-c: check alignment only (does not modify file)
-f: overwrite existing outfile.zip
-p: memory page alignment for stored shared object files
-v: verbose output
-z: recompress using Zopfli
3.7 签名
3.7.1 生成 keystore
$ keytool -genkeypair -keyalg RSA -validity 36000 -keystore ~/.android/apk.keystore -alias apk_release
根据提示输入密码和个人信息例如:
CN=CD DWX, OU=diewuxi.com, O=Diewuxi, L=Songjiang, ST=Shanghai, C=CN
完成后会生成 ~/.android/apk.keystore
文件,只需生成一次,-keyalg RSA
指定加密算法为 RSA
,-validity 36000
指定有效期 36000 天,-alias apk_release
指定这个条目的别名为 apk_release
(因为一个 keystore 文件里面能添加多个条目)。Android 开发者网站有相关介绍。keytool -genkeypair 子命令选项如下:
keytool -genkeypair [OPTION]...
Generates a key pair
Options:
-alias <alias> alias name of the entry to process
-keyalg <alg> key algorithm name
-keysize <size> key bit size
-groupname <name> Group name. For example, an Elliptic Curve name.
-sigalg <alg> signature algorithm name
-dname <name> distinguished name
-startdate <date> certificate validity start date/time
-ext <value> X.509 extension
-validity <days> validity number of days
-keypass <arg> key password
-keystore <keystore> keystore name
-signer <alias> signer alias
-signerkeypass <arg> signer key password
-storepass <arg> keystore password
-storetype <type> keystore type
-providername <name> provider name
-addprovider <name> add security provider by name (e.g. SunPKCS11)
[-providerarg <arg>] configure argument for -addprovider
-providerclass <class> add security provider by fully-qualified class name
[-providerarg <arg>] configure argument for -providerclass
-providerpath <list> provider classpath
-v verbose output
-protected password through protected mechanism
Use "keytool -?, -h, or --help" for this help message
3.7.2 签名
$ apksigner sign \
--ks /Users/fjc/.android/apk.keystore \
--ks-pass pass:android \
--ks-key-alias apk_release \
--out com.diewuxi.hello_world-signed.apk \
--verbose \
com.diewuxi.hello_world-aligned.apk
Android 应用需要被签名后才能安装到设备上,apksigner sign 子命令完成这个操作,其中用到了上一步生成的 keystore 文件和当时设置的密码。完成签名之后,该 apk 就可以安装到设备上了。选项解释如下:
USAGE: apksigner sign [options] apk
This signs the provided APK, stripping out any pre-existing signatures. Signing
is performed using one or more signers, each represented by an asymmetric key
pair and a corresponding certificate. Typically, an APK is signed by just one
signer. For each signer, you need to provide the signer's private key and
certificate.
GENERAL OPTIONS
--in Input APK file to sign. This is an alternative to
specifying the APK as the very last parameter, after all
options. Unless --out is specified, this file will be
overwritten with the resulting signed APK.
--out File into which to output the signed APK. By default, the
APK is signed in-place, overwriting the input file.
-v, --verbose Verbose output mode
--v1-signing-enabled Whether to enable signing using JAR signing scheme (aka v1
signing scheme) used in Android since day one. By default,
signing using this scheme is enabled based on min and max
SDK version (see --min-sdk-version and --max-sdk-version).
--v2-signing-enabled Whether to enable signing using APK Signature Scheme v2
(aka v2 signing scheme) introduced in Android Nougat,
API Level 24. By default, signing using this scheme is
enabled based on min and max SDK version (see
--min-sdk-version and --max-sdk-version).
--v3-signing-enabled Whether to enable signing using APK Signature Scheme v3
(aka v3 signing scheme) introduced in Android P,
API Level 28. By default, signing using this scheme is
enabled based on min and max SDK version (see
--min-sdk-version and --max-sdk-version). Multiple
signers are not supported when using v3 signing, but
multiple signers may be provided in conjunction with the
"lineage" option to make sure that the app is signed by
an appropriate signer on all supported platform versions.
--v4-signing-enabled Whether to enable signing using APK Signature Scheme v4
(aka v4 signing scheme) introduced in Android 11,
API Level 30. By default, signing using this scheme is
enabled based on min and max SDK version (see
--min-sdk-version and --max-sdk-version).
--force-stamp-overwrite Whether to overwrite existing source stamp in the
APK, if found. By default, it is set to false. It has no
effect if no source stamp signer config is provided.
--verity-enabled Whether to enable the verity signature algorithm for the
v2 and v3 signature schemes.
--min-sdk-version Lowest API Level on which this APK's signatures will be
verified. By default, the value from AndroidManifest.xml
is used. The higher the value, the stronger security
parameters are used when signing.
--max-sdk-version Highest API Level on which this APK's signatures will be
verified. By default, the highest possible value is used.
--debuggable-apk-permitted Whether to permit signing android:debuggable="true"
APKs. Android disables some of its security protections
for such apps. For example, anybody with ADB shell access
can execute arbitrary code in the context of a debuggable
app and can read/write persistently stored data of the
app. It is a good security practice to not sign
debuggable APKs with production signing keys, because
such APKs puts users at risk once leaked.
By default, signing debuggable APKs is permitted, for
backward compatibility with older apksigner versions.
--lineage Signing certificate history to use in the event that
signing certificates changed for an APK using APK
Signature Scheme v3 supported signing certificate
rotation. This object may be created by the apksigner
"rotate" command. If used, all signers used to sign the
APK must be present in the signing lineage,
and if v1 or v2 signing is enabled, the first (oldest)
entry in the lineage must have a signer provided, so that
it can be used for those v1 and/or v2 signing. Multiple
signers are not supported when using APK Signature Scheme
v3, so multiple signers input will correspond to different
points in the lineage and will be used on older platform
versions when the newest signer in the lineage is
unsupported.
An APK previously signed with a SigningCertificateLineage
can also be specified; the lineage will then be read from
the signed data in the APK.
-h, --help Show help about this command and exit
PER-SIGNER OPTIONS
These options specify the configuration of a particular signer. To delimit
options of different signers, use --next-signer.
--next-signer Delimits options of two different signers. There is no
need to use this option when only one signer is used.
--v1-signer-name Basename for files comprising the JAR signature scheme
(aka v1 scheme) signature of this signer. By default,
KeyStore key alias or basename of key file is used.
--stamp-signer The signing information for the signer of the source stamp
to be included in the APK.
PER-SIGNER SIGNING KEY & CERTIFICATE OPTIONS
There are two ways to provide the signer's private key and certificate: (1) Java
KeyStore (see --ks), or (2) private key file in PKCS #8 format and certificate
file in X.509 format (see --key and --cert).
--ks Load private key and certificate chain from the Java
KeyStore initialized from the specified file. NONE means
no file is needed by KeyStore, which is the case for some
PKCS #11 KeyStores.
--ks-key-alias Alias under which the private key and certificate are
stored in the KeyStore. This must be specified if the
KeyStore contains multiple keys.
--ks-pass KeyStore password (see --ks). The following formats are
supported:
pass:<password> password provided inline
env:<name> password provided in the named
environment variable
file:<file> password provided in the named
file, as a single line
stdin password provided on standard input,
as a single line
A password is required to open a KeyStore.
By default, the tool will prompt for password via console
or standard input.
When the same file (including standard input) is used for
providing multiple passwords, the passwords are read from
the file one line at a time. Passwords are read in the
order in which signers are specified and, within each
signer, KeyStore password is read before the key password
is read.
--key-pass Password with which the private key is protected.
The following formats are supported:
pass:<password> password provided inline
env:<name> password provided in the named
environment variable
file:<file> password provided in the named
file, as a single line
stdin password provided on standard input,
as a single line
If --key-pass is not specified for a KeyStore key, this
tool will attempt to load the key using the KeyStore
password and, if that fails, will prompt for key password
and attempt to load the key using that password.
If --key-pass is not specified for a private key file key,
this tool will prompt for key password only if a password
is required.
When the same file (including standard input) is used for
providing multiple passwords, the passwords are read from
the file one line at a time. Passwords are read in the
order in which signers are specified and, within each
signer, KeyStore password is read before the key password
is read.
--pass-encoding Additional character encoding (e.g., ibm437 or utf-8) to
try for passwords containing non-ASCII characters.
KeyStores created by keytool are often encrypted not using
the Unicode form of the password but rather using the form
produced by encoding the password using the console's
character encoding. apksigner by default tries to decrypt
using several forms of the password: the Unicode form, the
form encoded using the JVM default charset, and, on Java 8
and older, the form encoded using the console's charset.
On Java 9, apksigner cannot detect the console's charset
and may need to be provided with --pass-encoding when a
non-ASCII password is used. --pass-encoding may also need
to be provided for a KeyStore created by keytool on a
different OS or in a different locale.
--ks-type Type/algorithm of KeyStore to use. By default, the default
type is used.
--ks-provider-name Name of the JCA Provider from which to request the
KeyStore implementation. By default, the highest priority
provider is used. See --ks-provider-class for the
alternative way to specify a provider.
--ks-provider-class Fully-qualified class name of the JCA Provider from which
to request the KeyStore implementation. By default, the
provider is chosen based on --ks-provider-name.
--ks-provider-arg Value to pass into the constructor of the JCA Provider
class specified by --ks-provider-class. The value is
passed into the constructor as java.lang.String. By
default, the no-arg provider's constructor is used.
--key Load private key from the specified file. If the key is
password-protected, the password will be prompted via
standard input unless specified otherwise using
--key-pass. The file must be in PKCS #8 DER format.
--cert Load certificate chain from the specified file. The file
must be in X.509 PEM or DER format.
JCA PROVIDER INSTALLATION OPTIONS
These options enable you to install additional Java Crypto Architecture (JCA)
Providers, such as PKCS #11 providers. Use --next-provider to delimit options of
different providers. Providers are installed in the order in which they appear
on the command-line.
--provider-class Fully-qualified class name of the JCA Provider.
--provider-arg Value to pass into the constructor of the JCA Provider
class specified by --provider-class. The value is passed
into the constructor as java.lang.String. By default, the
no-arg provider's constructor is used.
--provider-pos Position / priority at which to install this provider in
the JCA provider list. By default, the provider is
installed as the lowest priority provider.
See java.security.Security.insertProviderAt.
EXAMPLES
1. Sign an APK, in-place, using the one and only key in keystore release.jks:
$ apksigner sign --ks release.jks app.apk
1. Sign an APK, without overwriting, using the one and only key in keystore
release.jks:
$ apksigner sign --ks release.jks --in app.apk --out app-signed.apk
3. Sign an APK using a private key and certificate stored as individual files:
$ apksigner sign --key release.pk8 --cert release.x509.pem app.apk
4. Sign an APK using two keys:
$ apksigner sign --ks release.jks --next-signer --ks magic.jks app.apk
5. Sign an APK using PKCS #11 JCA Provider:
$ apksigner sign --provider-class sun.security.pkcs11.SunPKCS11 \
--provider-arg token.cfg --ks NONE --ks-type PKCS11 app.apk
6. Sign an APK using a non-ASCII password KeyStore created on English Windows.
The --pass-encoding parameter is not needed if apksigner is being run on
English Windows with Java 8 or older.
$ apksigner sign --ks release.jks --pass-encoding ibm437 app.apk
7. Sign an APK on Windows using a non-ASCII password KeyStore created on a
modern OSX or Linux machine:
$ apksigner sign --ks release.jks --pass-encoding utf-8 app.apk
8. Sign an APK with rotated signing certificate:
$ apksigner sign --ks release.jks --next-signer --ks release2.jks \
--lineage /path/to/signing/history/lineage app.apk
4 安装测试
安装:
adb install -r com.diewuxi.hello_world-signed.apk
启动:
adb shell am start -n com.diewuxi.hello_world/.MainActivity
卸载:
adb uninstall com.diewuxi.hello_world
也可以吧 apk 文件复制到手机上,进行安装,操作,卸载。
5 使用 Makefile 文件
利用 make 工具可以简化以上一系列命令行操作,只要建立 Makefile 文件:
PROJECT_NAME = hello_world
PACKAGE_NAME = com.diewuxi.hello_world
PACKAGE_PATH = com/diewuxi/hello_world
APK__BASE = $(PACKAGE_NAME).apk
APK__ALIGNED = $(PACKAGE_NAME)-aligned.apk
APK__SIGNED = $(PACKAGE_NAME)-signed.apk
START_STRING = $(PACKAGE_NAME)/.MainActivity
HOME = /Users/fjc
HOME_MAIN = /Users/fjc/home
OS_MARK = macos
SDK_HOME = $(HOME_MAIN)/opt/android-sdk/android_sdk-$(OS_MARK)
JAR__ANDROID = $(SDK_HOME)/platforms/android-21/android.jar
KEYSTORE = $(HOME)/.android/apk.keystore
KEYSTORE_PASS = android
KEYSTORE_ALIAS = apk_release
DIR__SRC = src
DIR__RES = res
DIR__GEN = gen
DIR__BIN = bin
APPT__RES = -S $(DIR__RES)
APPT__EXTRA_PACKAGES = ""
JAVA__CLASSPATH = ""
JAVA__SRC = $(DIR__SRC)/$(PACKAGE_PATH)/*.java $(DIR__GEN)/$(PACKAGE_PATH)/R.java
DX__INCLUDE = $(DIR__BIN)
#DIR__CONSTRAINT_LAYOUT = $(SDK_HOME)/extras/m2repository/com/android/support/constraint/constraint-layout/1.0.2/constraint-layout-1.0.2
#JAR__CONSTRAINT_LAYOUT = $(DIR__CONSTRAINT_LAYOUT)/classes.jar
#JAR__CONSTRAINT_LAYOUT_SOLVER = $(SDK_HOME)/extras/m2repository/com/android/support/constraint/constraint-layout-solver/1.0.2/constraint-layout-solver-1.0.2.jar
#
#APPT__RES += -S $(DIR__CONSTRAINT_LAYOUT)/res
#APPT__EXTRA_PACKAGES += :android.support.constraint
#JAVA__CLASSPATH += :$(JAR__CONSTRAINT_LAYOUT):$(JAR__CONSTRAINT_LAYOUT_SOLVER)
#JAVA__SRC += $(DIR__GEN)/android/support/constraint/R.java
#DX__INCLUDE += $(JAR__CONSTRAINT_LAYOUT) $(JAR__CONSTRAINT_LAYOUT_SOLVER)
.PHONY: all res class apk install run uninstall clean
all: run
res:
aapt package \
-M AndroidManifest.xml \
$(APPT__RES) \
-I $(JAR__ANDROID) \
--extra-packages $(APPT__EXTRA_PACKAGES) \
--auto-add-overlay \
-m -J $(DIR__GEN) \
-f \
-v
class: res
javac \
--boot-class-path $(JAR__ANDROID) \
--class-path $(JAVA__CLASSPATH) \
-d $(DIR__BIN) \
--source 8 \
--target 8 \
-verbose \
$(JAVA__SRC)
apk: class
dx --dex --output=classes.dex --verbose $(DX__INCLUDE)
aapt package \
-M AndroidManifest.xml \
$(APPT__RES) \
-I $(JAR__ANDROID) \
--extra-packages $(APPT__EXTRA_PACKAGES) \
--auto-add-overlay \
-F $(APK__BASE) \
-f \
-v
aapt add -v $(APK__BASE) classes.dex
zipalign -f -p -v 4 $(APK__BASE) $(APK__ALIGNED)
apksigner sign \
--ks $(KEYSTORE) \
--ks-pass pass:$(KEYSTORE_PASS) \
--ks-key-alias $(KEYSTORE_ALIAS) \
--out $(APK__SIGNED) \
--verbose \
$(APK__ALIGNED)
install: apk
adb install -r $(APK__SIGNED)
run: install
adb shell am start -n $(START_STRING)
uninstall:
adb uninstall $(PACKAGE_NAME)
clean:
- rm $(APK__BASE)
- rm $(APK__ALIGNED)
- rm $(APK__SIGNED)
- rm $(APK__SIGNED).idsig
- rm classes.dex
- rm -r $(DIR__GEN)/*
- rm -r $(DIR__BIN)/*
例如用 make run
就可以自动完成从代码构建到 app 运行起来。
6 附录
- 命令行选项变化
新版本 Android SDK Build Tools 使用了 aapt2 和 d8,命令行选项有改动,本人对此不了解,不在此叙述。
- 本文所述命令不是通用的
命令行工具的选项很多,本文只使用了能完成本项目的选项,对于其它项目,所用命令行选项很可能与本文不同,需要根据实际需求找到适合的命令行选项。IDE 的优点之一就是自动帮你命令行选项。
7 参考资料
Last modified: 2024-01-21
Comments [0]
There is no comments now.