[編譯] 5、在Linux下搭建安卓APP的開發燒寫環境(makefile版)—— 在Linux上用命令列+VIM開發安卓APP
星期三, 19. 九月 2018 02:19上午 - BEAUTIFULZZZZ
0)前言
本文不討論用IDE和文字編輯器開發的優劣,是基於以下兩點考慮去嘗試用命令列編譯安卓APP的:
- 瞭解安卓APP的編譯過程,瞭解IDE幹了什麼事;
- 放在打包伺服器上需要自動化生成APP的指令碼;
1)安裝配置環境
安裝java
sudo apt-get install openjdk-8-jdk-headless
note: 安裝之前先要解除安裝之前版本的java,否則會報錯!!! [error-1].
安裝SDK tools
wget https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
建議將其解壓到
/opt
目錄下:mkdir -p /opt/android-sdk unzip sdk-tools-linux-3859397.zip -d /opt/android-sdk
用sdkmanager安裝SDK(#1)
sdkmanager是用來檢視、安裝、更新、解除安裝Android SDK的命令列工具,官方說明如下:
The sdkmanager is a command line tool that allows you to view, install, update, and uninstall packages for the Android SDK. The sdkmanager tool is provided in the Android SDK Tools package (25.2.3 and higher) and is located in android_sdk/tools/bin/.
列出Installed packages和Available Packages,檢視包安裝情況:
cd /opt/android-sdk/tools/bin ./sdkmanager --list
安裝platform tools 19(寫文章時最新的是26),該工具包含adb和fastboot,該工具對應的API級別也是19:
./sdkmanager "platform-tools" "platforms;android-19"
安裝build tools 26.0.1(最新的),該工具包含aapt、apksigner、zipalign等編譯、認證、打包工具:
./sdkmanager "platform-tools" "build-tools;26.0.1"
最後你會在/opt/android-sdk/中看到build-tools、paltforms、tools三個資料夾~
2)編寫簡單Hello World程式
建立工程資料夾
cd ~/Downloads/
mkdir HelloAndroid
cd HelloAndroid
建立工程檔案tree
mkdir -p src/com/example/helloandroid
mkdir obj
mkdir bin
mkdir -p res/layout
mkdir res/values
mkdir res/drawable
Make the file src/com/example/helloandroid/MainActivity.java and put that inside:
package com.example.helloandroid;
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);
}
}
Make the strings.xml file in the res/values folder. It contains all the text that your application uses:
<resources>
<string name="app_name">A Hello Android</string>
<string name="hello_msg">Hello Android!</string>
<string name="menu_settings">Settings</string>
<string name="title_activity_main">MainActivity</string>
</resources>
The activity_main.xml is a layout file which have to be in res/layout:
<RelativeLayout 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" />
</RelativeLayout>
You also have to add the file AndroidManifest.xml at the root:
<?xml version='1.0'?>
<manifest xmlns:a='http://schemas.android.com/apk/res/android' package='com.example.helloandroid' a:versionCode='0' a:versionName='0'>
<application a:label='A Hello Android'>
<activity a:name='com.example.helloandroid.MainActivity'>
<intent-filter>
<category a:name='android.intent.category.LAUNCHER'/>
<action a:name='android.intent.action.MAIN'/>
</intent-filter>
</activity>
</application>
</manifest>
最終檔案構成為:
➜ HelloAndroid tree
.
├── AndroidManifest.xml
├── bin
├── libs
├── obj
├── res
│ ├── drawable
│ ├── layout
│ │ └── activity_main.xml
│ └── values
│ └── strings.xml
└── src
└── com
└── example
└── helloandroid
└── MainActivity.java
3)編譯工程
將工程路徑設定為變數(方便一會使用):
export PROJ=~/Downloads/HelloAndroid
First, we need generate the R.java file which is necessary for our code:
cd /opt/android-sdk/build-tools/26.0.1/
./aapt package -f -m -J $PROJ/src -M $PROJ/AndroidManifest.xml -S $PROJ/res -I /opt/android-sdk/platforms/android-19/android.jar
compile the .java files:
cd ~/Downloads/HelloAndroid
javac -d obj -classpath src -bootclasspath /opt/android-sdk/platforms/android-19/android.jar src/com/example/helloandroid/*.java
The compiled .class files are in obj folder, but Android can’t read them. We have to translate them in a file called “classes.dex” which will be read by the dalvik Android runtime:
cd /opt/android-sdk/build-tools/26.0.1/
./dx --dex --output=$PROJ/bin/classes.dex $PROJ/obj
We can now put everything in an APK:
./aapt package -f -m -F $PROJ/bin/hello.unaligned.apk -M $PROJ/AndroidManifest.xml -S $PROJ/res -I /opt/android-sdk/platforms/android-19/android.jar
cp $PROJ/bin/classes.dex .
./aapt add $PROJ/bin/hello.unaligned.apk classes.dex
If you want, you can check the content of the package like this:
./aapt list $PROJ/bin/hello.unaligned.apk
至此,我們生成了一個hello.unaligned.apk檔案,但是,它是不能安裝到安卓手機裡面的!因為它unaligned && unsigned。
4)Align and Sign the package
keytool -genkeypair -validity 365 -keystore mykey.keystore -keyalg RSA -keysize 2048
cd /opt/android-sdk/build-tools/26.0.1/
./zipalign -f 4 $PROJ/bin/hello.unaligned.apk $PROJ/bin/hello.apk
./apksigner sign --ks mykey.keystore $PROJ/bin/hello.apk
使用keytool建立一個keystore,只要依次回答其問題即可,輸入密碼自己別忘了,今後會用到!執行成功之後會生成一個mykey.keystore檔案,用於今後給apk簽名。
note: 記住務必要先Align,然後再Sign,否則會出錯 [error-2].
5)真機安裝測試
安裝並執行比較簡單:
adb install $PROJ/bin/hello.apk
adb shell am start -n com.example.helloandroid/.MainActivity
note: 一般執行安裝前,建議先執行adb logcat看看安卓有沒有連線並開啟開發者模式
6)自動化指令碼
為了不用每次都要手輸上面的每一步,我們將上面的操作整理成一個指令碼run.sh:
➜ HelloAndroid cat run.sh
#!/bin/bash
set -e
AAPT="/opt/android-sdk/build-tools/26.0.1/aapt"
DX="/opt/android-sdk/build-tools/26.0.1/dx"
ZIPALIGN="/opt/android-sdk/build-tools/26.0.1/zipalign"
APKSIGNER="/opt/android-sdk/build-tools/26.0.1/apksigner" # /!\ version 26
PLATFORM="/opt/android-sdk/platforms/android-19/android.jar"
function build(){
echo "Generating R.java file..."
$AAPT package -f -m -J src -M AndroidManifest.xml -S res -I $PLATFORM
echo "Compiling..."
javac -d obj -classpath src -bootclasspath $PLATFORM src/com/example/helloandroid/*.java
echo "Translating in Dalvik bytecode..."
$DX --dex --output=classes.dex obj
echo "Making APK..."
$AAPT package -f -m -F bin/hello.unaligned.apk -M AndroidManifest.xml -S res -I $PLATFORM
$AAPT add bin/hello.unaligned.apk classes.dex
echo "Aligning and signing APK..."
$ZIPALIGN -f 4 bin/hello.unaligned.apk bin/hello.apk
$APKSIGNER sign --ks mykey.keystore bin/hello.apk
}
function clean(){
echo "Cleaning..."
rm -rf classes.dex
rm -rf bin/*
rm -rf obj/*
rm -rf src/com/example/helloandroid/R.java
}
function program(){
echo "Launching..."
adb install -r bin/hello.apk
adb shell am start -n com.example.helloandroid/.MainActivity
}
if [ "$1" == "all" ]; then
clean
build
program
elif [ "$1" == "clean" ]; then
clean
elif [ "$1" == "build" ]; then
build
elif [ "$1" == "program" ]; then
program
else
echo "error"
fi
並編寫一個makefile指令碼,通過呼叫run.sh實現編譯、清除、安裝各種操作:
➜ HelloAndroid cat makefile
clean:
./run.sh clean
build:
./run.sh build
program:
./run.sh program
all:
./run.sh all
至此,我們完成了一個簡單的命令列版的Hello World工程!當然,大多數非常複雜的安卓工程需要用IDE去開發,或者開發用IDE打包用命令 ~ 下次我會把一個稍微複雜點的藍芽安卓工程改造成命令列版。
常見錯誤
error-1:
➜ HelloAndroid javac -d obj -classpath src -bootclasspath /opt/android-sdk/platforms/android-19/android.jar src/com/example/helloandroid/*.java
javac: option --boot-class-path not allowed with target 1.10
error-2:
➜ HelloAndroid ./build.sh test
Cleaning...
Generating R.java file...
Compiling...
Translating in Dalvik bytecode...
Making APK...
'classes.dex'...
Aligning and signing APK...
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.android.apksigner.PasswordRetriever (file:/opt/android-sdk/build-tools/26.0.1/lib/apksigner.jar) to method java.io.Console.encoding()
WARNING: Please consider reporting this to the maintainers of com.android.apksigner.PasswordRetriever
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Keystore password for signer #1:
Launching...
Failed to install bin/hello.apk: Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES: Failed to collect certificates from /data/app/vmdl1775334521.tmp/base.apk: META-INF/MYKEY.SF indicates /data/app/vmdl1775334521.tmp/base.apk is signed using APK Signature Scheme v2, but no such signature was found. Signature stripped?]
需要If you need to run zipalign, do it before the APK is signed,因此將APKSIGNER放在ZIPALIG之後(#4)。
LINKS
@beautifulzzzz
智慧硬體、物聯網,熱愛技術,關注產品
部落格:http://blog.beautifulzzzz.com
園友交流群:414948975