Difference between revisions of "Build D for Android"
(add a little more setup info) |
(Update building sieve and basic GUI app) |
||
Line 26: | Line 26: | ||
==Setup== | ==Setup== | ||
− | Once you're at a command prompt or have the Termux app installed, get the ldc compiler for Android and the NDK for cross-compilation, | + | Once you're at a command prompt or have the Termux app installed, get the ldc compiler for Android and the NDK for cross-compilation, set some needed environment variables, and generate the runtime libraries for Android/ARM, which will be found in ldc-build-runtime.tmp/lib/. |
===Cross-compilation=== | ===Cross-compilation=== | ||
====Windows==== | ====Windows==== | ||
− | Download [https://cmake.org/download/ CMake] and the zip files for [https://developer.android.com/ndk/downloads/index.html one of the Android NDKs for Windows], [https://github.com/ldc-developers/ldc/releases/tag/v1.4.0 ldc 1.4], and either Make or [https://github.com/ninja-build/ninja/releases Ninja] (the following instructions assume Ninja). Make sure unzip is available to unpack all the build tools, then add them to your path, set the path of the NDK | + | Download [https://cmake.org/download/ CMake] and the zip files for [https://developer.android.com/ndk/downloads/index.html one of the Android NDKs for Windows], [https://github.com/ldc-developers/ldc/releases/tag/v1.4.0 ldc 1.4], and either Make or [https://github.com/ninja-build/ninja/releases Ninja] (the following instructions assume Ninja). Make sure unzip is available to unpack all the build tools, then add them to your path, set the path of the NDK and its C cross-compiler, and run ldc-build-runtime. I show the commands for 64-bit Windows, should be similar for 32-bit, except the Ninja zip only comes with a 64-bit version. |
<syntaxhighlight lang=powershell> | <syntaxhighlight lang=powershell> | ||
Line 48: | Line 48: | ||
ldc-build-runtime --ninja --targetPreset=Android-arm | ldc-build-runtime --ninja --targetPreset=Android-arm | ||
+ | |||
+ | set NDK=C:\Users\you\droid\android-ndk-r15c | ||
</syntaxhighlight> | </syntaxhighlight> | ||
====linux==== | ====linux==== | ||
− | Install needed packages, including optionally Ninja, as shown here for Ubuntu. You will need tar to unpack ldc and unzip for the NDK. Add ldc to your path and export the path of the NDK | + | Install needed packages, including optionally Ninja, as shown here for Ubuntu. You will need tar to unpack ldc and unzip for the NDK. Add ldc to your path and export the path of the NDK and its C cross-compiler, as shown here for bash, and run ldc-build-runtime. |
<syntaxhighlight lang=bash> | <syntaxhighlight lang=bash> | ||
Line 70: | Line 72: | ||
ldc-build-runtime --targetPreset=Android-arm | ldc-build-runtime --targetPreset=Android-arm | ||
+ | |||
+ | export NDK=/path/to/your/android-ndk-r15c | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 86: | Line 90: | ||
<syntaxhighlight lang=bash> | <syntaxhighlight lang=bash> | ||
+ | # Load this link in your browser and download the file otherwise | ||
curl -L -O https://raw.githubusercontent.com/dlang/dmd/master/samples/sieve.d | curl -L -O https://raw.githubusercontent.com/dlang/dmd/master/samples/sieve.d | ||
− | $ | + | # On linux |
+ | ldc2 -mtriple=armv7-none-linux-android -L-L/path/to/your/ldc-build-runtime.tmp/lib | ||
+ | -Xcc=--sysroot=$NDK/platforms/android-21/arch-arm -Xcc=-fuse-ld=bfd -Xcc=-gcc-toolchain | ||
+ | -Xcc=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 -Xcc=-target | ||
+ | -Xcc=armv7-none-linux-androideabi -Xcc=-fpie -Xcc=-pie sieve.d | ||
− | + | # On 64-bit Windows | |
− | --sysroot= | + | ldc2 -mtriple=armv7-none-linux-android -L-LC:\Users\you\droid\ldc-build-runtime.tmp\lib |
− | -gcc-toolchain | + | -Xcc=--sysroot=%NDK%\platforms\android-21\arch-arm -Xcc=-fuse-ld=bfd.exe -Xcc=-gcc-toolchain |
− | - | + | -Xcc=%NDK%\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64 -Xcc=-target |
− | + | -Xcc=armv7-none-linux-androideabi -Xcc=-fpie -Xcc=-pie sieve.d | |
− | |||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
− | Copy this sieve program onto an Android device or emulator. Here's how I do it in Termux, with an ssh server running on the | + | Copy this sieve program onto an Android device or emulator and set its permissions with the chmod command. Here's how I do it in Termux, with an ssh server running on the host PC with IP address 192.168.1.37: |
<syntaxhighlight lang=bash> | <syntaxhighlight lang=bash> | ||
apt install openssh | apt install openssh | ||
cd | cd | ||
− | scp jo@ | + | scp jo@192.168.1.37:sieve . |
+ | chmod 700 sieve | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 131: | Line 139: | ||
==Build a sample OpenGL ES 1.0 GUI app ported to D== | ==Build a sample OpenGL ES 1.0 GUI app ported to D== | ||
− | Clone [https://github.com/joakim-noah/android my android repository], which contains several headers and sample OpenGL apps from the NDK translated to D, and build the Native Activity app, which is written completely in D. As you'll see below, D code for an apk must be compiled to a shared library, which the Android runtime will call. | + | Clone [https://github.com/joakim-noah/android my android repository] or download its source, which contains several headers and sample OpenGL apps from the NDK translated to D, and build the Native Activity app, which is written completely in D. As you'll see below, D code for an apk must be compiled to a shared library, which the Android runtime will call. |
===Cross-compilation=== | ===Cross-compilation=== | ||
− | + | On linux, you can just clone my git repo: | |
<syntaxhighlight lang=bash> | <syntaxhighlight lang=bash> | ||
Line 142: | Line 150: | ||
git clone https://github.com/joakim-noah/android.git | git clone https://github.com/joakim-noah/android.git | ||
− | cd android/samples/native-activity/ | + | cd android/ |
+ | </syntaxhighlight> | ||
+ | |||
+ | Otherwise, simply get and unpack the zip file: | ||
+ | |||
+ | <syntaxhighlight lang=bash> | ||
+ | curl -L -O https://github.com/joakim-noah/android/archive/tea.zip | ||
+ | |||
+ | unzip tea.zip | ||
+ | cd android-tea/ | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | After getting the source, go to the sample app, compile the D source, then link the objects into a shared library and place it in the directory that the SDK expects. | ||
+ | |||
+ | <syntaxhighlight lang=bash> | ||
+ | cd samples/native-activity/ | ||
+ | |||
+ | ldc2 -mtriple=armv7-none-linux-android -I../../ -c jni/main.d | ||
− | + | ldc2 -mtriple=armv7-none-linux-android -I../../ -c ../../android/sensor.d | |
− | + | ldc2 -mtriple=armv7-none-linux-android -I../../ -c ../../android_native_app_glue.d | |
− | + | mkdir -p libs/armeabi-v7a/ # On Windows, mkdir libs\armeabi-v7a | |
− | + | # On linux | |
+ | $CC -Wl,-soname,libnative-activity.so -shared --sysroot=$NDK/platforms/android-21/arch-arm | ||
+ | main.o sensor.o android_native_app_glue.o /path/to/your/ldc-build-runtime.tmp/lib/libphobos2-ldc.a | ||
+ | /path/to/your/ldc-build-runtime.tmp/lib/libdruntime-ldc.a -gcc-toolchain | ||
+ | $NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 -fuse-ld=bfd -target | ||
+ | armv7-none-linux-androideabi -llog -landroid -lEGL -lGLESv1_CM | ||
+ | -o libs/armeabi-v7a/libnative-activity.so | ||
− | + | # On 64-bit Windows | |
− | -shared --sysroot= | + | %CC% -Wl,-soname,libnative-activity.so -shared --sysroot=%NDK%\platforms\android-21\arch-arm |
− | android_native_app_glue.o | + | main.o sensor.o android_native_app_glue.o C:\Users\you\droid\ldc-build-runtime.tmp\lib\libphobos2-ldc.a |
− | + | C:\Users\you\droid\ldc-build-runtime.tmp\lib\libdruntime-ldc.a -gcc-toolchain | |
− | + | %NDK%\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64 -fuse-ld=bfd.exe -target | |
− | + | armv7-none-linux-androideabi -llog -landroid -lEGL -lGLESv1_CM | |
− | -llog -landroid -lEGL -lGLESv1_CM | + | -o libs\armeabi-v7a\libnative-activity.so |
</syntaxhighlight> | </syntaxhighlight> | ||
− | Finally, package the app as the SDK directs. I document the older Ant approach, which is deprecated, replace it with the Gradle command from a newer SDK. With Ant, set the path to your SDK, then run these commands: | + | Finally, package the app as the SDK directs. I document the older Ant approach, which is deprecated, replace it with the Gradle command from a newer SDK. With Ant on linux, set the path to your SDK, then run these commands: |
<syntaxhighlight lang=bash> | <syntaxhighlight lang=bash> | ||
Line 169: | Line 200: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | Transfer the resulting bin/NativeActivity-debug.apk to your device. | + | Transfer the resulting bin/NativeActivity-debug.apk to your Android device, again shown here by using scp from the Termux app. |
<syntaxhighlight lang=bash> | <syntaxhighlight lang=bash> | ||
− | + | scp jo@192.168.1.37:android/samples/native-activity/bin/NativeActivity-debug.apk /sdcard/Download/ | |
− | scp jo@ | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 194: | Line 224: | ||
$PREFIX/bin/clang -Wl,-soname,libnative-activity.so -shared main.o sensor.o | $PREFIX/bin/clang -Wl,-soname,libnative-activity.so -shared main.o sensor.o | ||
android_native_app_glue.o $PREFIX/lib/libphobos2-ldc.a $PREFIX/lib/libdruntime-ldc.a | android_native_app_glue.o $PREFIX/lib/libphobos2-ldc.a $PREFIX/lib/libdruntime-ldc.a | ||
− | + | -target armv7-none-linux-androideabi -llog -landroid -lEGL -lGLESv1_CM | |
− | + | -o lib/armeabi-v7a/libnative-activity.so | |
− | -lGLESv1_CM | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Revision as of 11:21, 17 September 2017
These instructions show you how to build D command-line executables and OpenGL ES GUI apps for Android, either by using the Windows/linux compilers available here or a native Android compiler. There are separate steps for cross-compilation, ie building apps on a Windows or linux PC and running them on Android/ARM, versus native compilation, both building and running on your Android/ARM device itself.
Since you cannot install the Android SDK on Android, I end by showing how to package a GUI Android app, a zip file called an .apk, from scratch, by using the tools available in the Termux app for Android, a terminal emulator app and open-source package manager/repository for Android devices.
Contents
Prerequisites
Cross-compilation
- A command shell on your host PC, where you'll run the ldc cross-compiler
- Either a DOS command prompt or Powershell should work on Windows.
- Any shell should work on linux, typical commands for the bash shell are shown.
- Android native toolchain, the NDK and optionally the SDK
- The SDK is necessary if you want to package a GUI app; the NDK is enough if you just want to build a command-line binary.
- The ldc D compiler, either 1.4 or later
- Common build tools
- CMake and either Make or Ninja are required to build the runtime libraries for Android. There are instructions below on setting them up.
- Android/ARM, whether a device or emulator, to run your D code
- The SDK comes with an emulator. I use actual hardware, so that's what I'll discuss. Make sure it's a 32-bit ARM device, as 64-bit ARM is not supported yet.
- If using a device, you need some way to transfer the app over. There are several ways to do this, here are a few I've tried:
- Install an ssh server app on your Android device and scp the app over. Alternately, set up an ssh server on your host PC, and use an ssh/scp client on Android to get the app. This is what I do, by using the OpenSSH client in Termux.
- Host the app in a web server and get it by using your Android browser or a downloader app.
- Setup the Android Debug Bridge (adb) on your device and use the SDK tools to push your files over.
Native compilation
- Termux for Android, available in the official Play Store, APKMirror, or F-Droid
- Check if it's a 32-bit ARM device by running "uname -m". If it returns "armv7l", you're good. If it says "aarch64," your 64-bit ARM device is not supported by ldc yet.
Setup
Once you're at a command prompt or have the Termux app installed, get the ldc compiler for Android and the NDK for cross-compilation, set some needed environment variables, and generate the runtime libraries for Android/ARM, which will be found in ldc-build-runtime.tmp/lib/.
Cross-compilation
Windows
Download CMake and the zip files for one of the Android NDKs for Windows, ldc 1.4, and either Make or Ninja (the following instructions assume Ninja). Make sure unzip is available to unpack all the build tools, then add them to your path, set the path of the NDK and its C cross-compiler, and run ldc-build-runtime. I show the commands for 64-bit Windows, should be similar for 32-bit, except the Ninja zip only comes with a 64-bit version.
cd droid # assuming all the zip files have been placed in a folder called droid
unzip cmake-3.9.2-win64-x64.zip
unzip ldc2-1.4.0-win64-msvc.zip
unzip android-ndk-r15c-windows-x86_64.zip
unzip ninja-win.zip
set PATH=%PATH%;C:\Users\you\droid\cmake-3.9.2-win64-x64\bin;C:\Users\you\droid\ldc2-1.4.0-win64-msvc\bin;C:\Users\you\droid
ldc2 --version # run this to check that ldc is in your path
set CC=C:\Users\you\droid\android-ndk-r15c\toolchains\llvm\prebuilt\windows-x86_64\bin\clang
ldc-build-runtime --ninja --targetPreset=Android-arm
set NDK=C:\Users\you\droid\android-ndk-r15c
linux
Install needed packages, including optionally Ninja, as shown here for Ubuntu. You will need tar to unpack ldc and unzip for the NDK. Add ldc to your path and export the path of the NDK and its C cross-compiler, as shown here for bash, and run ldc-build-runtime.
sudo apt-get install build-essential cmake curl ninja unzip
curl -L -O https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip
unzip android-ndk-r15c-linux-x86_64.zip
curl -L -O https://github.com/ldc-developers/ldc/releases/download/v1.4.0/ldc2-1.4.0-linux-x86_64.tar.xz
tar xf ldc2-1.4.0-linux-x86_64.tar.xz
export PATH=$PATH:/path/to/your/ldc2-1.4.0-linux-x86_64/bin
ldc2 --version # check that ldc is your path
export CC=/path/to/your/android-ndk-r15c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang
ldc-build-runtime --targetPreset=Android-arm
export NDK=/path/to/your/android-ndk-r15c
Native compilation
Just install ldc from the Termux app, which will automatically pull in the clang compiler and a linker, as ldc tries to use the local C compiler for linking.
apt install ldc
Build a command-line executable
Now that we have a D compiler and runtime libraries for Android, let's try building a small program, the classic Sieve of Eratosthenes single-core benchmark, which finds all prime numbers up to a number you choose.
Cross-compilation
# Load this link in your browser and download the file otherwise
curl -L -O https://raw.githubusercontent.com/dlang/dmd/master/samples/sieve.d
# On linux
ldc2 -mtriple=armv7-none-linux-android -L-L/path/to/your/ldc-build-runtime.tmp/lib
-Xcc=--sysroot=$NDK/platforms/android-21/arch-arm -Xcc=-fuse-ld=bfd -Xcc=-gcc-toolchain
-Xcc=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 -Xcc=-target
-Xcc=armv7-none-linux-androideabi -Xcc=-fpie -Xcc=-pie sieve.d
# On 64-bit Windows
ldc2 -mtriple=armv7-none-linux-android -L-LC:\Users\you\droid\ldc-build-runtime.tmp\lib
-Xcc=--sysroot=%NDK%\platforms\android-21\arch-arm -Xcc=-fuse-ld=bfd.exe -Xcc=-gcc-toolchain
-Xcc=%NDK%\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64 -Xcc=-target
-Xcc=armv7-none-linux-androideabi -Xcc=-fpie -Xcc=-pie sieve.d
Copy this sieve program onto an Android device or emulator and set its permissions with the chmod command. Here's how I do it in Termux, with an ssh server running on the host PC with IP address 192.168.1.37:
apt install openssh
cd
scp jo@192.168.1.37:sieve .
chmod 700 sieve
Native compilation
apt install curl
curl -L -O https://raw.githubusercontent.com/dlang/dmd/master/samples/sieve.d
ldc2 sieve.d
Run the sieve program
The sieve program will tell you how many prime numbers there are in the first n integers, a limit you can specify. Run this command to find how many primes there are in the first million integers:
./sieve 1000000
If you built sieve successfully, it should return
78498 primes
Build a sample OpenGL ES 1.0 GUI app ported to D
Clone my android repository or download its source, which contains several headers and sample OpenGL apps from the NDK translated to D, and build the Native Activity app, which is written completely in D. As you'll see below, D code for an apk must be compiled to a shared library, which the Android runtime will call.
Cross-compilation
On linux, you can just clone my git repo:
sudo apt-get install git
git clone https://github.com/joakim-noah/android.git
cd android/
Otherwise, simply get and unpack the zip file:
curl -L -O https://github.com/joakim-noah/android/archive/tea.zip
unzip tea.zip
cd android-tea/
After getting the source, go to the sample app, compile the D source, then link the objects into a shared library and place it in the directory that the SDK expects.
cd samples/native-activity/
ldc2 -mtriple=armv7-none-linux-android -I../../ -c jni/main.d
ldc2 -mtriple=armv7-none-linux-android -I../../ -c ../../android/sensor.d
ldc2 -mtriple=armv7-none-linux-android -I../../ -c ../../android_native_app_glue.d
mkdir -p libs/armeabi-v7a/ # On Windows, mkdir libs\armeabi-v7a
# On linux
$CC -Wl,-soname,libnative-activity.so -shared --sysroot=$NDK/platforms/android-21/arch-arm
main.o sensor.o android_native_app_glue.o /path/to/your/ldc-build-runtime.tmp/lib/libphobos2-ldc.a
/path/to/your/ldc-build-runtime.tmp/lib/libdruntime-ldc.a -gcc-toolchain
$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 -fuse-ld=bfd -target
armv7-none-linux-androideabi -llog -landroid -lEGL -lGLESv1_CM
-o libs/armeabi-v7a/libnative-activity.so
# On 64-bit Windows
%CC% -Wl,-soname,libnative-activity.so -shared --sysroot=%NDK%\platforms\android-21\arch-arm
main.o sensor.o android_native_app_glue.o C:\Users\you\droid\ldc-build-runtime.tmp\lib\libphobos2-ldc.a
C:\Users\you\droid\ldc-build-runtime.tmp\lib\libdruntime-ldc.a -gcc-toolchain
%NDK%\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64 -fuse-ld=bfd.exe -target
armv7-none-linux-androideabi -llog -landroid -lEGL -lGLESv1_CM
-o libs\armeabi-v7a\libnative-activity.so
Finally, package the app as the SDK directs. I document the older Ant approach, which is deprecated, replace it with the Gradle command from a newer SDK. With Ant on linux, set the path to your SDK, then run these commands:
export SDK=/path/to/your/android-sdk-linux
$SDK/tools/android update project -p . -s --target 1
ant debug
Transfer the resulting bin/NativeActivity-debug.apk to your Android device, again shown here by using scp from the Termux app.
scp jo@192.168.1.37:android/samples/native-activity/bin/NativeActivity-debug.apk /sdcard/Download/
Native compilation
apt install git
git clone https://github.com/joakim-noah/android.git
cd android/samples/native-activity/
ldc2 -I../../ -c jni/main.d
ldc2 -I../../ -c ../../android/sensor.d
ldc2 -I../../ -c ../../android_native_app_glue.d
mkdir -p lib/armeabi-v7a/
$PREFIX/bin/clang -Wl,-soname,libnative-activity.so -shared main.o sensor.o
android_native_app_glue.o $PREFIX/lib/libphobos2-ldc.a $PREFIX/lib/libdruntime-ldc.a
-target armv7-none-linux-androideabi -llog -landroid -lEGL -lGLESv1_CM
-o lib/armeabi-v7a/libnative-activity.so
Follow the instructions below to package this native shared library into an Android apk.
Install and run the sample GUI app
Go to Settings->Security on your Android device and allow installation of apps from unknown sources, ie from outside the Play Store, then go to /sdcard/Download in your file manager and choose the NativeActivity-debug apk to install it. Open the app after installing or go to your app folder and run the app named NativeActivity: it'll show a black screen initially, then flash a bunch of colors when the screen is touched.
Build a sample OpenGL ES 2.0 GUI app mostly written in D, with some Java
Cross-compilation
This app comes with a simple script called build-apk, which will build the D shared library for you, as long as the LDC and NDK variables are set.
cd android/samples/Teapot/
./build-apk
Here are the contents of that script, so you can see what it's doing.
$LDC/bin/ldc2 -I../../ -c ../../ndk_helper/GLContext.d
$LDC/bin/ldc2 -I../../ -c ../../ndk_helper/JNIHelper.d
$LDC/bin/ldc2 -I../../ -c ../../ndk_helper/gestureDetector.d
$LDC/bin/ldc2 -I../../ -c ../../ndk_helper/perfMonitor.d
$LDC/bin/ldc2 -I../../ -c ../../ndk_helper/shader.d
$LDC/bin/ldc2 -I../../ -c ../../ndk_helper/tapCamera.d
$LDC/bin/ldc2 -I../../ -Ijni/ -Jjni/ -c jni/TeapotNativeActivity.d
$LDC/bin/ldc2 -I../../ -Jjni/ -c jni/TeapotRenderer.d
$LDC/bin/ldc2 -I../../ -c ../../android/sensor.d
$LDC/bin/ldc2 -I../../ -c ../../android_native_app_glue.d
$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/clang -Wl,-soname,libTeapotNativeActivity.so
-shared --sysroot=$NDK/platforms/android-21/arch-arm TeapotNativeActivity.o sensor.o
TeapotRenderer.o android_native_app_glue.o GLContext.o JNIHelper.o gestureDetector.o
perfMonitor.o shader.o tapCamera.o $LDC/lib/libphobos2-ldc.a $LDC/lib/libdruntime-ldc.a
-lgcc -gcc-toolchain $NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
-no-canonical-prefixes -fuse-ld=bfd -target armv7-none-linux-androideabi -Wl,--fix-cortex-a8
-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel
-Wl,--fatal-warnings -llog -landroid -lEGL -lGLESv2 -lc -lm -o libTeapotNativeActivity.so
Package this shared library into an apk by using the SDK, as you would normally, and try installing and running it on your device.
Native compilation
The steps are the same as above, except for a marginally different linker command, which is included in the build script but commented out. However, this app requires compiling some Java code and the Java compilers in Termux aren't working at the moment, so I'll hold off on this for now.
Package an Android app from scratch on your Android device
Install aapt, the Android Asset Packaging Tool, and apksigner, a tool to create a hashed manifest and sign your apps.
apt install aapt apksigner
I'll demonstrate with the NativeActivity app built above.
cd android/samples/native-activity/
aapt package -M AndroidManifest.xml -S res -F NativeActivity-debug-unsigned.apk
aapt add NativeActivity-debug-unsigned.apk lib/armeabi-v7a/libnative-activity.so
This simple app only requires three files, AndroidManifest.xml, resources.arsc, and lib/armeabi-v7a/libnative-activity.so, which you can check with the following aapt command.
aapt list NativeActivity-debug-unsigned.apk
Now let's generate a hashed manifest, just like a Java jar file, and sign the app. If you have your own Java Keystore already, just supply it to apksigner. If not, apksigner will generate a self-signed Keystore file, which we name debug.ks below, which is good enough to sign and install debug apps on your own Android device.
apksigner debug.ks NativeActivity-debug-unsigned.apk NativeActivity-debug.apk
You should see three additional files in the apk, if you list its contents using the command above. At this point, you can install and run the signed app on your own device.
Sign your app using a certificate and OpenSSL
Unfortunately, apksigner only supports Java Keystore files for signing right now and I don't know how to build one from scratch, so if you don't have a keystore and want to release your app to an app store, you'll have to use OpenSSL to sign the app.
For a valid certificate for the final release, there's plenty of information online on how to generate one. I'll just show how to create a self-signed certificate for debugging purposes.
First, install the OpenSSL package in Termux. Then, this OpenSSL command will generate a self-signed debug certificate, apk.cert, and a 2048-bit RSA private key, key.pem, which isn't encrypted with a password. It will ask you for some signing info, for which I've shown what's used by the debug certificate in the Android SDK, but it doesn't matter what you enter, as it's ignored:
apt install openssl-tool
openssl req -x509 -nodes -newkey rsa:2048 -keyout key.pem -out apk.cert
....................................+++
...............................................................................................................................................................+++
writing new private key to 'key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:.
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Android
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:Android Debug
Email Address []:
Now that we have a certificate- self-signed in this case, use your actual release certificate if you want to release the app- and private key, we use them to sign the app. Since the apk is just a zip file, unzip it into a directory and use OpenSSL to generate a new signature file, CERT.RSA, then update the apk with the new signature, and copy the apk to a public user directory from which you can install it:
mkdir unpack
cd unpack/
unzip ../NativeActivity-debug.apk
cd META-INF/
openssl smime -sign -md sha1 -binary -noattr -in CERT.SF -out CERT.RSA -outform der -inkey ../../key.pem -signer ../../apk.cert
cd ..
aapt remove ../NativeActivity-debug.apk META-INF/CERT.RSA
aapt add ../NativeActivity-debug.apk META-INF/CERT.RSA
cd ..
cp NativeActivity-debug.apk /sdcard/Download/
The OpenSSL commands to generate a certificate and sign the apk were taken from this 2012 blog post, you can follow it further to see what the signature consists of and verify it for yourself. This 2013 blog post was critical for me to understand how apk signing works, I used to run all those commands by hand until the apksigner package was added to the Termux package repo late last year.