[編譯] 五、在Linux下搭建安卓APP的開發燒寫環境(makefile版)—— 在Linux上用命令行+VIM開發安卓APP

星期三, 19. 九月 2018 02:19上午 - BEAUTIFULZZZZjava


0)前言linux

本文不討論用IDE和文本編輯器開發的優劣,是基於如下兩點考慮去嘗試用命令行編譯安卓APP的:android

  • 瞭解安卓APP的編譯過程,瞭解IDE幹了什麼事;
  • 放在打包服務器上須要自動化生成APP的腳本;



1)安裝配置環境git

  • 安裝javagithub

    sudo apt-get install openjdk-8-jdk-headless

    note: 安裝以前先要卸載以前版本的java,不然會報錯!!! [error-1].shell

  • 安裝SDK toolsapi

    wget https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip

    建議將其解壓到/opt目錄下:bash

    mkdir -p /opt/android-sdk
      unzip sdk-tools-linux-3859397.zip -d /opt/android-sdk
  • 用sdkmanager安裝SDK(#1)服務器

    sdkmanager是用來查看、安裝、更新、卸載Android SDK的命令行工具,官方說明以下:app

    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)

error-3:

$ avdmanager
Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema
    at com.android.repository.api.SchemaModule$SchemaModuleVersion.<init>(SchemaModule.java:156)
    at com.android.repository.api.SchemaModule.<init>(SchemaModule.java:75)
    at com.android.sdklib.repository.AndroidSdkHandler.<clinit>(AndroidSdkHandler.java:81)
    at com.android.sdklib.tool.AvdManagerCli.run(AvdManagerCli.java:213)
    at com.android.sdklib.tool.AvdManagerCli.main(AvdManagerCli.java:200)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
    ... 5 more

須要加:export JAVA_OPTS='-XX:+IgnoreUnrecognizedVMOptions --add-modules java.se.ee'

[1].sdkmanager 用法
[2].Build your app from the command line
[3].How to make Android apps without IDE from command line
[4].Android signing apk signature V2
[5].What are the Android SDK build-tools, platform-tools and tools? And which version should be used?
[6].Not able to build code after installing latest java version 1.9
[7].Android SDK is not installed or is not configured properly, environment looks ok
[8].Command line tools only Download
[9].GITHUB this project

@beautifulzzzz
智能硬件、物聯網,熱愛技術,關注產品
博客:http://blog.beautifulzzzz.com
園友交流羣:414948975
相關文章
相關標籤/搜索