A Unixpilled Developer’s Guide to Hello World on Android
Suitable for developers with very little knowledge of the Java/Android ecosystems (like me!)
The Goal
Let’s write an Android app that displays the text “Hello World!”, but without such a massive build-time stack/dependency list.
Ok, what is an app?
For our purposes today, an “app” is an APK file. What an app is once it’s actually installed on the target device is something I do not know, and fortunately irrelevant for today.
So then what is an APK file? It’s an Android PacKage, which is a particular kind of ZIP file (like JARs, Many spreadsheet formats, etc.). The structure of an APK has some variance, and does not seem well documented, but the best resources I can find are, of course, the Wikipedia page, and this Medium article.
To simplify, for the purposes of today, the package contains
classes.dex, which is the actual code,
AndroidManifest.xml, which contains metadata about the
application, META-INF/{MANIFEST.MF,TEST.SF,TEST.RSA}, which
hold the signature data for the app, and some other noise
(resources.arsc) that isn’t relevant for our test.
Already, that’s a lot of new things to process, so let’s start with what we came for…
The Code
For the easy part, open a file HelloWorld.java, and
write
package com.example;
import android.widget.TextView;
import android.app.Activity;
import android.os.Bundle;
public final class HelloWorld extends Activity
{
protected @Override void onCreate(final Bundle activityState)
{
super.onCreate(activityState);
final TextView tv = new TextView(HelloWorld.this);
tv.setText("Hello World!");
setContentView(tv);
}
}Or, to be more modern with Kotlin, open HelloWorld.kt
and write:
package com.example;
import android.widget.TextView;
import android.app.Activity;
import android.os.Bundle;
class HelloWorld : Activity()
{
override fun onCreate(activityState: Bundle?)
{
super.onCreate(activityState);
var tv = TextView(this);
tv.setText("Hello World!");
setContentView(tv);
}
}(Well, I can see why people are moving to Kotlin)
Now we need to take our source code, and move to the JVM world by
compiling it to a “class file”. To do so, use either the Java compiler
javac, or the Kotlin compiler kotlinc –
depending on which source language you chose – but notice that we have
those android.* dependencies. How do we satisfy those? In
my case, since I use Arch (btw), I have the package
android-platform installed, which provides
/opt/android-sdk/platforms/android-${ANDROID_API}/android.jar,
where ${ANDROID_API} is 34 for me. Putting it all together,
we run:
${COMPILER} -cp ${ANDROID_SDK}/platforms/android-${ANDROID_API}/android.jar -d ./ HelloWorld.${EXT}Where:
${COMPILER}isjavacorkotlinc${EXT}isjavaorkt${ANDROID_SDK}is the install location of your android resources (/opt/android-sdkfor me)${ANDROID_API}is the API number you have installed (or are targeting), which is not the same as the Android version number. E.G., I am using API number 34, which coresponds to Android 14.-cptells the compiler what to have in its “class path” (analogous to a list of include directories, or, in this case, include archives).-dtells the compiler what directory or archive to write its output to.
This will create the file com/example/HelloWorld.class
(the compiler will create the parent directories as well).
Great! Now we have our executable JVM code! Except… Android doesn’t run the JVM, it runs ART, so we have to translate our Class file to a “Dalvik” executable (because Android used to use a Dalvik runtime, then switched to a different platform while keeping the same executable format, named for the previous system.)
Fine. How do we do that? First, we introduce the next dependency. The
Android SDK tools
(android-sdk-build-tools on Arch). This provides, among
other things, the d8 program, which is a “Dexer”, and the
successor to dx, which is still referenced from time to
time.
Now that we have the tool, run
d8 --lib ${ANDROID_SDK}/platforms/android-${ANDROID_API}/android.jar --output ./ ./com/example/HelloWorld.classWhich will produce ./classes.dex
[APK]: Android Package [JAR]: Java Archive [JVM]: Java Virtual Machine [JDK]: Java Development Kit [ART]: Android Run-Time [SDK]: Software Development Kit (specifically for Android, in this context)