Skip to content

Instantly share code, notes, and snippets.

@leok7v
Last active August 11, 2024 03:29
Show Gist options
  • Save leok7v/a6ea231c66f2210ab3c6781583b53d97 to your computer and use it in GitHub Desktop.
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
#!/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