Last active
August 11, 2024 03:29
-
-
Save leok7v/a6ea231c66f2210ab3c6781583b53d97 to your computer and use it in GitHub Desktop.
Single file bash script to build Android Hello World apk (target API=21) on osx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# https://medium.com/@authmane512/how-to-build-an-apk-from-command-line-without-ide-7260e1e22676 | |
# dependencies: | |
# https://installvirtual.com/install-openjdk-8-on-mac-using-brew-adoptopenjdk/ | |
# brew updata | |
# brew tap AdoptOpenJDK/openjdk | |
# brew cask install adoptopenjdk8 | |
# https://developer.android.com/ndk/downloads | |
# https://dl.google.com/android/repository/sdk-tools-darwin-4333796.zip | |
# and use: | |
# $<android-sdk-location>/tools/android to update | |
export android_sdk=`dirname C:/android/sdk/.` | |
export android_ndk=`dirname C:/android/sdk/ndk/21.1.6352462/.` | |
export android_api=21 | |
export android_jar=$android_sdk/platforms/android-$android_api/android.jar | |
#latest tools: | |
export latest_tools=`ls -1v $android_sdk/build-tools | head -n 1` | |
export bt=$android_sdk/build-tools/$latest_tools # bt stands for build tools | |
# https://github.com/rmyorston/busybox-w32 does not implement pushd/popd | |
pushd() { # newline is importan below - it is stack entries separator | |
export bash_pushd_popd_stack="$PWD | |
${bash_pushd_popd_stack}" | |
cd "${1}" | |
} | |
popd() { | |
local dir=`echo "\${bash_pushd_popd_stack}" | sed -ne '1p'`; [ "$dir" != "" ] && cd $dir ; bash_pushd_popd_stack=`echo "\${bash_pushd_popd_stack}" | sed -e '1d'` | |
} | |
rm -rf app | |
mkdir app | |
pushd app | |
export project=`pwd` | |
mkdir -p src/com/example/helloandroid | |
mkdir obj | |
mkdir bin | |
mkdir libs | |
mkdir -p res/layout | |
mkdir res/values | |
mkdir res/drawable | |
pushd src/com/example/helloandroid | |
echo "package app.domain;" > A.java | |
echo "" >> A.java | |
echo "import android.app.Activity;" >> A.java | |
echo "import android.os.Bundle;" >> A.java | |
echo "" >> A.java | |
echo "public class A extends Activity {" >> A.java | |
echo "" >> A.java | |
echo " protected void onCreate(Bundle savedInstanceState) {" >> A.java | |
echo " super.onCreate(savedInstanceState);" >> A.java | |
echo " setContentView(R.layout.activity_main);" >> A.java | |
echo " }" >> A.java | |
echo "}" >> A.java | |
# cat A.java | |
popd | |
pushd res/values | |
echo "<resources>" > strings.xml | |
echo " <string name='app_name'>A</string>" >> strings.xml | |
echo " <string name='hello_msg'>Hello Android!</string>" >> strings.xml | |
echo " <string name='menu_settings'>Settings</string>" >> strings.xml | |
echo " <string name='title_activity_main'>A</string>" >> strings.xml | |
echo "</resources>" >> strings.xml | |
popd | |
pushd res/layout | |
echo "<RelativeLayout xmlns:android='http://schemas.android.com/apk/res/android' xmlns:tools='http://schemas.android.com/tools'" > activity_main.xml | |
echo " android:layout_width='match_parent'" >> activity_main.xml | |
echo " android:layout_height='match_parent' >" >> activity_main.xml | |
echo "" >> activity_main.xml | |
echo " <TextView" >> activity_main.xml | |
echo " android:layout_width='wrap_content'" >> activity_main.xml | |
echo " android:layout_height='wrap_content'" >> activity_main.xml | |
echo " android:layout_centerHorizontal='true'" >> activity_main.xml | |
echo " android:layout_centerVertical='true'" >> activity_main.xml | |
echo " android:text='@string/hello_msg'" >> activity_main.xml | |
echo " tools:context='.A' />" >> activity_main.xml | |
echo "</RelativeLayout>" >> activity_main.xml | |
popd | |
echo "<?xml version='1.0'?>" > AndroidManifest.xml | |
echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" >> AndroidManifest.xml | |
echo " package='app.domain'>" >> AndroidManifest.xml | |
echo " <uses-sdk android:minSdkVersion='21' android:targetSdkVersion='29' />" >> AndroidManifest.xml | |
echo " <uses-permission android:name='android.permission.INTERNET' />" >> AndroidManifest.xml | |
echo " <application android:label='@string/app_name'>" >> AndroidManifest.xml | |
echo " <activity android:name='.A'>" >> AndroidManifest.xml | |
echo " <intent-filter>" >> AndroidManifest.xml | |
echo " <category android:name='android.intent.category.LAUNCHER'/>" >> AndroidManifest.xml | |
echo " <action android:name='android.intent.action.MAIN'/>" >> AndroidManifest.xml | |
echo " </intent-filter>" >> AndroidManifest.xml | |
echo " </activity>" >> AndroidManifest.xml | |
echo " </application>" >> AndroidManifest.xml | |
echo "</manifest>" >> AndroidManifest.xml | |
$bt/aapt package -f -m -J $project/src -M $project/AndroidManifest.xml -S $project/res -I $android_jar | |
# for additional .jar libraries use: | |
# javac -d obj -classpath "src:libs/<your-lib>.jar" -bootclasspath $android_jar src/com/example/helloandroid/*.java | |
# for javac version 8 add -source 1.7 -target 1.7 | |
# javac -d -source 1.7 -target 1.7 obj -classpath src -bootclasspath $android_jar src/com/example/helloandroid/*.java | |
javac -source 1.7 -target 1.7 -d obj -classpath src -bootclasspath $android_jar src/com/example/helloandroid/*.java | |
keytool -genkeypair -validity 10000 -keystore apk.keystore -keyalg RSA -keysize 2048 -deststoretype pkcs12\ | |
-storepass android -keypass android -noprompt \ | |
-alias androiddebugkey \ | |
-dname "CN=exmple.com, OU=ID, O=IBM, L=Hursley, S=Hants, C=GB" | |
# for additional .jar libraries use: | |
# ./dx --dex --output=$project/bin/classes.dex $project/lib/*.jar $project/obj | |
$bt/dx --dex --output=$project/bin/classes.dex $project/obj | |
$bt/aapt package -f -m -F $project/bin/hello.unaligned.apk -M $project/AndroidManifest.xml -S $project/res -I $android_jar | |
# it is important that classes.dex do not have the folder path prefix on command line | |
pushd $project/bin | |
$bt/aapt add $project/bin/hello.unaligned.apk classes.dex | |
popd | |
# echo hello.unaligned.apk: | |
# $bt/aapt list $project/bin/hello.unaligned.apk | |
$bt/zipalign -v -f 4 $project/bin/hello.unaligned.apk $project/bin/hello.apk | |
$bt/apksigner sign --ks-pass pass:android --ks-key-alias androiddebugkey --ks $project/apk.keystore --in $project/bin/hello.apk --out $project/bin/hello.signed.apk | |
$bt/apksigner verify --verbose $project/bin/hello.signed.apk | |
# because key store is regenerated do adb uninstall first | |
$android_sdk/platform-tools/adb uninstall app.domain | |
$android_sdk/platform-tools/adb install $project/bin/hello.signed.apk | |
$android_sdk/platform-tools/adb shell am start -n app.domain/app.domain.A | |
popd |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment