星期三, 19. 九月 2018 02:19上午 - BEAUTIFULZZZZjava
0)前言linux
本文不讨论用IDE和文本编辑器开发的优劣,是基于如下两点考虑去尝试用命令行编译安卓APP的:android
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