Hello World Using The Android Sdk Alone (no Ide)
Solution 1:
These are the instructions that eventually worked for me. I got them by deconstructing Google's Ant script, on which Rob's answer is based.
The following content is from "Android programming without an IDE" from Stack Overflow Documentation (archived here); copyright 2017 by geekygenius, Michael Allan, cascal, Doron Behar, mnoronha, and AndroidMechanic; licensed under CC BY-SA 3.0. An archive of the full Stack Overflow Documentation content can be found at archive.org, in which this example is indexed by its topic ID: 85, as example: 9496.
This is a minimalist Hello World example that uses only the most basic Android tools.
Requirements and assumptions
- Oracle JDK 1.7 or later
- Android SDK Tools (just the command line tools)
This example assumes Linux. You may have to adjust the syntax for your own platform.
Setting up the Android SDK
After unpacking the SDK release:
Install additional packages using the SDK manager. Don't use
android update sdk --no-ui
as instructed in the bundled Readme.txt; it downloads some 30 GB of unnecessary files. Instead use the interactive SDK managerandroid sdk
to get the recommended minimum of packages.Append the following JDK and SDK directories to your execution PATH. This is optional, but the instructions below assume it.
- JDK/bin
- SDK/platform-tools
- SDK/tools
- SDK/build-tools/LATEST (as installed in step 1)
Create an Android virtual device. Use the interactive AVD Manager (
android avd
). You might have to fiddle a bit and search for advice; the on-site instructions aren't always helpful.(You can also use your own device)
Run the device:
emulator -avd DEVICE
If the device screen appears to be locked, then swipe to unlock it.
Leave it running while you code the app.
Coding the app
Change to an empty working directory.
Make the source file:
mkdir --parents src/dom/domain touch src/dom/domain/SayingHello.java
Content:
package dom.domain; import android.widget.TextView; publicfinalclassSayingHelloextendsandroid.app.Activity { protected@OverridevoidonCreate( final android.os.Bundle activityState ) { super.onCreate( activityState ); finalTextViewtextV=newTextView( SayingHello.this ); textV.setText( "Hello world" ); setContentView( textV ); } }
Add a manifest:
touch AndroidManifest.xml
Content:
<?xml version='1.0'?><manifestxmlns:a='http://schemas.android.com/apk/res/android'package='dom.domain'a:versionCode='0'a:versionName='0'><applicationa:label='Saying hello'><activitya:name='dom.domain.SayingHello'><intent-filter><categorya:name='android.intent.category.LAUNCHER'/><actiona:name='android.intent.action.MAIN'/></intent-filter></activity></application></manifest>
Make a sub-directory for the declared resources:
mkdir res
Leave it empty for now.
Building the code
Generate the source for the resource declarations. Substitute here the correct path to your SDK, and the installed API to build against (e.g. "android-23"):
aapt package -f \ -I SDK/platforms/android-API/android.jar \ -J src -m \ -M AndroidManifest.xml -S res -v
Resource declarations (described further below) are actually optional. Meantime the above call does nothing if res/ is still empty.
Compile the source code to Java bytecode (.java → .class):
javac \ -bootclasspath SDK/platforms/android-API/android.jar \ -classpath src -source 1.7 -target 1.7 \ src/dom/domain/*.java
Translate the bytecode from Java to Android (.class → .dex):
First using Jill (.class → .jayce):
java -jar SDK/build-tools/LATEST/jill.jar \ --output classes.jayce src
Then Jack (.jayce → .dex):
java -jar SDK/build-tools/LATEST/jack.jar \ --import classes.jayce --output-dex .
Android bytecode used to be called "Dalvik executable code", and so "dex".
You could replace steps 11 and 12 with a single call to Jack if you like; it can compile directly from Java source (.java → .dex). But there are advantages to compiling with
javac
. It's a better known, better documented and more widely applicable tool.Package up the resource files, including the manifest:
aapt package -f \ -F app.apkPart \ -I SDK/platforms/android-API/android.jar \ -M AndroidManifest.xml -S res -v
That results in a partial APK file (Android application package).
Make the full APK using the
ApkBuilder
tool:java -classpath SDK/tools/lib/sdklib.jar \ com.android.sdklib.build.ApkBuilderMain \ app.apkUnalign \ -d -f classes.dex -v -z app.apkPart
It warns, "THIS TOOL IS DEPRECATED. See --help for more information." If
--help
fails with anArrayIndexOutOfBoundsException
, then instead pass no arguments:java -classpath SDK/tools/lib/sdklib.jar \ com.android.sdklib.build.ApkBuilderMain
It explains that the CLI (
ApkBuilderMain
) is deprecated in favour of directly calling the Java API (ApkBuilder
). (If you know how to do that from the command line, please update this example.)Optimize the data alignment of the APK (recommended practice):
zipalign -f -v 4 app.apkUnalign app.apk
Installing and running
Install the app to the Android device:
adb install -r app.apk
Start the app:
adb shell am start -n dom.domain/.SayingHello
It should run and say hello.
That's all. That's what it takes to say hello using the basic Android tools.
Declaring a resource
This section is optional. Resource declarations aren't required for a simple "hello world" app. If they aren't required for your app either, then you could streamline the build somewhat by omitting step 10, and removing the reference to the res/ directory from step 13.
Otherwise, here's a brief example of how to declare a resource, and how to reference it.
Add a resource file:
mkdir res/values touch res/values/values.xml
Content:
<?xml version='1.0'?><resources><stringname='appLabel'>Saying hello</string></resources>
Reference the resource from the XML manifest. This is a declarative style of reference:
<!-- <application a:label='Saying hello'> --><applicationa:label='@string/appLabel'>
Reference the same resource from the Java source. This is an imperative reference:
// v.setText( "Hello world" ); v.setText( "This app is called " + getResources().getString( R.string.appLabel ));
Test the above modifications by rebuilding, reinstalling and re-running the app (steps 10-17).
It should restart and say, "This app is called Saying hello".
Uninstalling the app
adb uninstall dom.domain
See also
- working example - A working build script that uses the above commands
Solution 2:
First off, seriously do not even consider using the emulator. Unless you just want to submit to needless torture. For someone who doesn't want the baggage of an IDE, the Emulator is 100x worse. Get a device would be advice on that point.
You are not going to be able to forego XML. I understand and appreciate that impulse I had a similar one. However, I eventually came to love it. Use styles a lot. I would recommend using Android Studio. It has a great lint tool for the code and the interface builder markup.
Even if you want to just code from an editor, you might want to use Android Studio to make your project stub. It's pretty good at that. In case you didn't know this, in the docs, there is a command line way to make a project (not using AS): it's documented here.
Solution 3:
Very helpful post. I made a simple brightness setter using your very good instructions. Just wish I could figure out the args for just Jack alone. Was able to put everything in one directory except for the icon which needed to go in res\drawable-hdpi to be found.
javac -bootclasspath c:\android\SDK/platforms/android-19/android.jar -classpath . *.java
java -jar c:\android\SDK/build-tools/24.0.1/jill.jar --output classes.jayce .
java -jar c:\android\SDK/build-tools/24.0.1/jack.jar --import classes.jayce --output-dex .
aapt package -f -F app.apkPart -I c:\android\SDK/platforms/android-19/android.jar -M AndroidManifest.xml -S res -v
java -classpath c:\android\SDK/tools/lib/sdklib.jar com.android.sdklib.build.ApkBuilderMain app.apkUnalign -d -f classes.dex -v -z app.apkPart
zipalign -f -v 4 app.apkUnalign brite.apk
<?xml version="1.0" encoding="utf-8"?><manifestxmlns:android="http://schemas.android.com/apk/res/android"package="dom.domain"android:versionCode="1"android:versionName="1.0" ><uses-sdkandroid:minSdkVersion="8"android:targetSdkVersion="19" /><uses-permissionandroid:name="android.permission.WRITE_SETTINGS"></uses-permission><applicationandroid:allowBackup="true"android:icon="@drawable/slkimage"android:label="brite" ><activityandroid:name="dom.domain.MainActivity"android:label="brite" ><intent-filter><actionandroid:name="android.intent.action.MAIN" /><categoryandroid:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>
Solution 4:
Since Jack and Jill are outdated, I had to modify a few commands.
Installed the sdk,ndk in /a
(the ndk is not used in this hello world), the jdk in the system, and the android-tools-adb in the /usr/bin
etc (this one contains adb and fastboot and phone definitions so that it can detect them).
I added this to .bashrc
:
export JAVA_HOME=/usr/lib64/java
export ANDROID_HOME=/a
export ANDROID_PLATFORM=$ANDROID_HOME/platforms/android-23
export ANDROID_BUILD_TOOLS=$ANDROID_HOME/build-tools/28.0.0-rc1
export ANDROID_NDK=$ANDROID_HOME/ndk
export ANDROID_TOOLS=$ANDROID_HOME/tools # sdk tools
PATH=$PATH:$JAVA_HOME/bin:$ANDROID_HOME:$ANDROID_BUILD_TOOLS:$ANDROID_NDK:$ANDROID_TOOLS:$ANDROID_TOOLS/bin:$ANDROID_PLATFORM
Here are my modified commands:
sdkmanager --list
sdkmanager "platforms;android-23"
sdkmanager platform-tools
mkdir /a/prj
cd /a/prj
mkdir --parents src/dom/domain
vi src/dom/domain/SayingHello.java
package dom.domain;
import android.widget.TextView;
public final classSayingHelloextendsandroid.app.Activity
{
protected@OverridevoidonCreate( final android.os.Bundle activityState )
{
super.onCreate( activityState );
final TextView textV = newTextView( SayingHello.this );
textV.setText( "Hello world" );
setContentView( textV );
}
}
vi AndroidManifest.xml
<?xml version='1.0'?>
<manifestxmlns:a='http://schemas.android.com/apk/res/android'package='dom.domain'a:versionCode='0'a:versionName='0'><applicationa:label='Saying hello'><activitya:name='dom.domain.SayingHello'><intent-filter><categorya:name='android.intent.category.LAUNCHER'/><actiona:name='android.intent.action.MAIN'/></intent-filter></activity></application></manifest>
If you choose to use the res/
directory instead, adapt the source code and AndroidManifest.xml
as shown below:
# this section is OPTIONAL , the hello world can run without any res
mkdir res/values -p
vi res/values/values.xml
<?xml version='1.0'?><resources><stringname='appLabel'>Saying hello</string></resources>
# Reference the resource from the AndroidManifest.xml manifest.
vi AndroidManifest.xml
<!-- <application a:label='Saying hello'> --><!-- edit this --><applicationa:label='@string/appLabel'>
vi src/dom/domain/SayingHello.java
// v.setText( "Hello world" ); // edit this
v.setText( "This app is called "
+ getResources().getString( R.string.appLabel ));
# end OPTIONAL section
I also created a build script, buildprj
:
#!/bin/bash#Generate the source for the resource declarations.
aapt package -f \
-I $ANDROID_PLATFORM/android.jar \
-J src -m \
-M AndroidManifest.xml -S res -v
#Compile the source code to Java bytecode (.java ニ .class)
javac \
-bootclasspath $ANDROID_PLATFORM/android.jar \
-classpath src -source 1.7 -target 1.7 \
src/dom/domain/*.java
#Translate the bytecode from Java to Android (.class ニ .dex)
dx --dex --output="classes.dex" src
#Package up the resource files, including the manifest
aapt package -f -F app.apkPart -I $ANDROID_PLATFORM/android.jar \
-M AndroidManifest.xml -S res -v
#Make the full APK using the ApkBuilder tool:
CLASSPATH=$ANDROID_TOOLS/lib/* java \
com.android.sdklib.build.ApkBuilderMain app.apkUnalign \
-d -f classes.dex -v -z app.apkPart
#Optimize the data alignment of the APK (recommended practice https://developer.android.com/studio/command-line/zipalign.html ):
zipalign -f -v 4 app.apkUnalign app.apk
adb install -r app.apk
adb shell am start -n dom.domain/.SayingHello
echo"To uninstall the app: adb uninstall dom.domain"# cleanuprm app.apkPart app.apkUnalign classes.dex
find . -name "*.class" -execrm {} +
find . -name "R.java" -execrm {} +
To run the build script, just call it:
./buildprj # run the build script
Along the way I ran into some pitfalls:
java -classpath $ANDROID_TOOLS/lib/sdklib.jar \
com.android.sdklib.build.ApkBuilderMain \
app.apkUnalign \
-d -f classes.dex -v -z app.apkPart
it gave an error that didn't say "sdklib.jar doesn't exist/is not found" Error: Could not find or load main class com.android.sdklib.build.ApkBuilderMain
... :(
cd /a/tools/lib/
ln -s sdklib-25.3.1.jar sdklib.jar
java -classpath $ANDROID_TOOLS/lib/sdklib.jar \
com.android.sdklib.build.ApkBuilderMain \
app.apkUnalign \
-d -f classes.dex -v -z app.apkPart
Exception in thread "main" java.lang.NoClassDefFoundError: com/android/prefs/AndroidLocatio
java -classpath $ANDROID_TOOLS/lib/sdklib.jar \
com.android.sdklib.build.ApkBuilderMain \
app.apkUnalign \
-d -f classes.dex -v -z app.apkPart --help
THIS TOOL IS DEPRECATED. See --help for more information.
Unknown argument: --help
Wow...
Anyway it turns out it 's just explaining that the CLI (ApkBuilderMain) is deprecated in favour of directly calling the Java API (ApkBuilder). If you know how to do that from the command line, please update this example. UPDATE:Actually it seems impossible to do that from the command line so that warning is a bit strange...
"If --help fails with an ArrayIndexOutOfBoundsException, then instead pass no arguments:
java -classpath SDK/tools/lib/sdklib.jar \
com.android.sdklib.build.ApkBuilderMain
" all right...
Solution 5:
The command dx is now unavailable and the Apk Builder needs to configure a key. This is my settings...
Installations
Firt you need the Software Developer Kit (SDK), the Java Developer Kit (JDK) and a key file.
- To use SDK without IDE download the
Command line tools
here. - Uncompress the
Command line tools
(e.g.unzip commandlinetools-linux.zip
). - Move the directory
cmdline-tools
for a convenient location and rename it toSDK
(e.g.mv cmdline-tools ~/.android/SDK
). - Go to
SDK/bin
and run (see note 1)
./sdkmanager --sdk_root=../ --list
./sdkmanager --sdk_root=../ "platforms;android-31"
./sdkmanager --sdk_root=../ platform-tools
./sdkmanager --sdk_root=../ "build-tools;31.0.0"
- Download the JDK version 11 here (>11 do not work for android java virtual machine).
- Uncompress the JDK in a convenient directory and rename it to JDK (e.g.
unzip openjdk-11.zip ; mv jdk-11 ~/.android/JDK
). - Go to
JDK/bin
and make a key with./keytool -genkey -keystore ~/.keystore -keyalg RSA
. - Make an script to compile your applications. For example (see note 2)
#!/bin/bash# Script to compile a android application source.# The argument of the scrit is the directory of the source code (e.g. `ac hello_world/`),# this directory may be have the file `AndroidManifest.xml`, the `res` directory# and subdirectories containing the java source files.cd"$1"# #### seting up the ambient variables# ###export JAVA_HOME="$HOME/.android/JDK"export ANDROID_HOME="$HOME/.android/SDK"export ANDROID_PLATFORM="$ANDROID_HOME/platforms/android-31"export ANDROID_BUILD_TOOLS="$ANDROID_HOME/build-tools/31.0.0"export ANDROID_TOOLS="$ANDROID_HOME/tools"export PATH=$JAVA_HOME/bin:$ANDROID_BUILD_TOOLS:$ANDROID_TOOLS:$PATH# #### Compile the code# #### Compile the source code to Java bytecode (.java to .class)
javac -cp$ANDROID_PLATFORM/android.jar $(find . -name "*.java")
# Translate the bytecode from Java to Android (.class to .dex)
d8 --lib $ANDROID_PLATFORM/android.jar $(find . -name "*.class")
# Package up the resource files, including the manifest
aapt package -f \
-F app.apkPart \
-I $ANDROID_PLATFORM/android.jar \
-M AndroidManifest.xml \
-S res/
# Make the full APK using the `ApkBuilder` tool
CLASSPATH=$ANDROID_TOOLS/lib/* java \
com.android.sdklib.build.ApkBuilderMain app.apkUnalign \
-u -f classes.dex -z app.apkPart
# Optimize the data alignment of the APK
zipalign -f 4 app.apkUnalign app_aligned.apk
# Signer the APK
apksigner sign --ks ~/.keystore --out app.apk app_aligned.apk
# #### Remove generated files# ###rm app.apkUnalign
rm app_aligned.apk
rm app.apkPart
rm classes.dex
find . -name "*.class" -execrm {} +
exit 0
- Put the script in a bin directory (e.g.
~/bin/ac
of/bin/ac
wereac
is the script name) and make it executable (e.g.chmod 755 ~/ac
).
Notes:
platforms;android-31
andbuild-tools;31.0.0
say "Download tools to API 31 of android" but you can download another version, see disponible versions with./sdkmanager --sdk_root=../ --list | grep "platforms;android"
and./sdkmanager --sdk_root=../ --list | grep "build-tools;"
.- This script supose that you put the SDK and the JDK in
~/.android/SDK
and~/.android/JDK
and supose that you downloaded the tools for android API 31.
Read more:
Coding
You need basicaly two files, the AndroidManifest.xml
and the MainActivity.java
.
Eventually you need resources, for more advanced programs, in a directory called res
, for this example the res directory are empty.
The content of AndroidManifest.xml
is like the following.
<?xml version='1.0'?><manifestxmlns:android='http://schemas.android.com/apk/res/android'package='com.your_company.app'android:versionCode='0'><applicationandroid:label='App name'><activityandroid:name='com.your_company.app.MainActivity'><intent-filter><categoryandroid:name='android.intent.category.LAUNCHER'/><actionandroid:name='android.intent.action.MAIN'/></intent-filter></activity></application></manifest>
The content of MainActivity.java
is like the following.
package com.your_company.app;
import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;
publicfinalclassMainActivityextendsActivity {
@OverrideprotectedvoidonCreate(final Bundle activityState){
super.onCreate(activityState);
finalTextViewtextV=newTextView(MainActivity.this);
textV.setText("Hello World");
setContentView( textV );
}
}
Is common to put the file MainActivity.java
in a directory called src/com/your_company/app/
. The file tree looks like the following.
hello_world/
|
|--- AndroidManifest.xml
|--- res/
|--- src/
|--- com/
|--- your_company/
|--- app/
|--- MainActivity.java
Suposing that you have a command that you inform the source directory and the command invokes a compiler for your source (see the section installations item 8) and the command name are ac
, open the directory hello_world
in a terminal and type
ac ./
Now copy the file app.apk
to your phone and install it.
Post a Comment for "Hello World Using The Android Sdk Alone (no Ide)"