Compare commits

...

10 commits

7 changed files with 128 additions and 66 deletions

6
.gitignore vendored
View file

@ -1,8 +1,6 @@
/Dockerfile /Dockerfile
/app/result
/app/result/* /app/result/*
/app/obj
/app/obj/* /app/obj/*
/app/bin !/app/obj/.gitkeep
/app/bin/*
/app/app.apk /app/app.apk
/app/Makefile.app-config

View file

@ -8,31 +8,21 @@ test -f app-config.sh && {
echo "package $APP_PACKAGE;" echo "package $APP_PACKAGE;"
cat << 'APPACTIVITYJAVA' cat << 'APPACTIVITYJAVA'
import android.provider.Settings ; import android.provider.Settings ;
import android.content.Intent; import android.content.Intent;
import android.util.Log; import android.util.Log;
import android.util.Base64;
import java.util.Objects;
import android.app.Activity; import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Environment; import android.os.Environment;
import android.text.method.ScrollingMovementMethod;
import android.view.*;
//import android.view.MenuItem; //import android.view.MenuItem;
import android.view.ViewGroup.*; import android.view.*;
import android.widget.*; // for WebView,WebMessage,WebMessagePort,
//import android.widget.Toast;
//import android.widget.TextView;
import android.webkit.*; import android.webkit.*;
import android.net.Uri; import android.net.Uri;
import org.json.JSONObject; import org.json.JSONObject;
//import android.webkit.WebView;
//import android.webkit.WebMessage;
//import android.webkit.WebMessagePort;
import java.io.InputStream; import java.io.InputStream;
import java.io.File; import java.io.File;
import java.util.Objects;
@ -70,6 +60,9 @@ public class AppActivity extends Activity {
myWebSettings.setBuiltInZoomControls(true); myWebSettings.setBuiltInZoomControls(true);
myWebSettings.setDisplayZoomControls(false); myWebSettings.setDisplayZoomControls(false);
myWebSettings.setJavaScriptEnabled(true); myWebSettings.setJavaScriptEnabled(true);
myWebSettings.setDomStorageEnabled(true);
myWebSettings.setDatabaseEnabled(true);
myWebSettings.setDatabasePath("/data/data/" + myWebView.getContext().getPackageName() + "/databases/");
myWebView.addJavascriptInterface(this, "myJavaScriptInterface"); myWebView.addJavascriptInterface(this, "myJavaScriptInterface");
// load the html from assets file // load the html from assets file
String html = readFileFromAssets("index.html"); String html = readFileFromAssets("index.html");
@ -85,4 +78,3 @@ public class AppActivity extends Activity {
return "this is good"; return "this is good";
} }
} }
APPACTIVITYJAVA

View file

@ -13,11 +13,21 @@ test -n "$LINES" || {
test -n "$LINES" || { test -n "$LINES" || {
read -r LINES COLUMNS < <(stty size) read -r LINES COLUMNS < <(stty size)
} }
test -n "$LINES" || {
test -z "$LINES" && {
LINES=25 LINES=25
COLUMS=80 }
test "$LINES" -lt "16" && {
LINES=16
} }
test -z "$COLUMNS" && {
COLUMNS=80
}
test "$COLUMNS" -lt "36" && {
COLUMNS=36
}
type whiptail &>/dev/null && { type whiptail &>/dev/null && {
ECHO(){ ECHO(){

View file

@ -1,51 +1,64 @@
SHELL=/bin/bash .ONESHELL:
SHELL=/bin/makefile-bash-wrapper.sh
# the include of the Makefile.app-config defines the Makefile
# variables $(BUILDTOOLS), $(ANDROID_JAR) and $(PACKAGE)
# which depend on the configuration and are necessary to have the Makefile work
# the rule whose target is Makefile.app-config will trigger a reload of this include as ncessary
# (as explained https://make.mad-scientist.net/papers/advanced-auto-dependency-generation/#include)
include Makefile.app-config
# symlink # symlink
./app.apk: ./result/app.apk ./app.apk: ./result/app.apk
ln -sfrv ./result/app.apk ./app.apk ln -sfrv ./result/app.apk ./app.apk
# zipalign and sign again (second signing) # zipalign and sign again (second signing)
./result/app.apk : ./result/signed.apk app-config.sh ./result/app.apk : ./result/signed.apk app-config.sh ./keystore
source app-config.sh; $${ANDROID_SDK_ROOT}/$$(tr ';' '/' < android-sdk/.installed.buildtools.version.current)/zipalign -v -f 4 $< $@ $(BUILDTOOLS)/zipalign -v -f 4 $< $@
source app-config.sh; $${ANDROID_SDK_ROOT}/$$(tr ';' '/' < android-sdk/.installed.buildtools.version.current)/apksigner sign \ $(BUILDTOOLS)/apksigner sign --ks keystore --key-pass pass:armena --ks-pass pass:armena $@
--ks ToyKey.keystore --key-pass pass:armena --ks-pass pass:armena $@
# sign the apk file (first sign) # sign the apk file (first sign)
./result/signed.apk : ./result/unsigned.apk ./ToyKey.keystore ./result ./result/signed.apk : ./result/unsigned.apk ./keystore
jarsigner -verbose -keystore ./ToyKey.keystore -storepass armena -keypass armena -signedjar $@ $< helljniKey jarsigner -verbose -keystore ./keystore -storepass armena -keypass armena -signedjar $@ $< helljniKey
# make a "keystore" for the cryptographic signing stuff # make a "keystore" for the cryptographic signing stuff
./ToyKey.keystore : ./keystore :
keytool -genkeypair -validity 1000 -dname "CN=alexander,O=Android,C=JPN" -keystore $@ \ keytool -genkeypair -validity 1000 -dname "CN=alexander,O=Android,C=JPN" -keystore $@ \
-storepass armena -keypass armena -alias helljniKey -keyalg RSA -v -storepass armena -keypass armena -alias helljniKey -keyalg RSA -v
# aapt "package" together the dalvik/hex stuff (and "assets" and "res") # aapt "package" together the dalvik/hex stuff (and "assets" and "res")
./result/unsigned.apk : ./bin/classes.dex ./result ./assets ./bin ./AndroidManifest.xml ./result/unsigned.apk : ./result/bin/classes.dex ./assets ./AndroidManifest.xml
rm -rvf "$@" rm -rvf "$@"
source app-config.sh; $${ANDROID_SDK_ROOT}/$$(tr ';' '/' < android-sdk/.installed.buildtools.version.current)/aapt package \ $(BUILDTOOLS)/aapt package \
-v -u -f -M ./AndroidManifest.xml -S ./res \ -v -u -f -M ./AndroidManifest.xml -S ./res \
-I $${ANDROID_SDK_ROOT}/$$(tr ';' '/' < android-sdk/.installed.platforms.version.current)/android.jar -A ./assets -F $@ ./bin -I $(ANDROID_JAR) -A ./assets -F $@ ./result/bin
# convert "java class"es files (i.e bytecode to dalvic/d8 android thing # convert "java class"es files (i.e bytecode) to dalvic/d8 android thing
./bin/classes.dex : ./obj/package ./obj/package/AppActivity.class ./bin ./result/bin/classes.dex : ./obj/$(PACKAGE)/AppActivity.class
ls ./obj/package/*.class mkdir -p ./result/bin
source app-config.sh; $${ANDROID_SDK_ROOT}/$$(tr ';' '/' < android-sdk/.installed.buildtools.version.current)/d8 $$(realpath --relative-to=. $<)/*.class \ $(BUILDTOOLS)/d8 ./obj/$(PACKAGE)/*.class \
--lib $${ANDROID_SDK_ROOT}/$$(tr ';' '/' < android-sdk/.installed.platforms.version.current)/android.jar --output bin --lib $(ANDROID_JAR) --output ./result/bin
# compile (javac) the class from # compile (javac) the class from
./obj/package/AppActivity.class : ./src/package/AppActivity.java ./src/package/R.java ./obj/package ./obj/$(PACKAGE)/AppActivity.class : ./src/$(PACKAGE)/AppActivity.java ./src/$(PACKAGE)/R.java
javac -d ./obj -classpath $${ANDROID_SDK_ROOT}/$$(tr ';' '/' < android-sdk/.installed.platforms.version.current)/android.jar \ mkdir -p ./obj/$(PACKAGE)
-sourcepath ./src $$(realpath --relative-to=/src $<) javac -d ./obj -classpath $(ANDROID_JAR) -sourcepath ./src $<
# generate teh AppActivity.java (template)
./src/package/AppActivity.java: ./src/package app-config.sh
./.Makefile.scripts/make--AppActivity.java.sh > $@
# make the resources "R.java" thing # make the resources "R.java" thing
./src/package/R.java : $(shell find ./res -type f) app-config.sh ./src/package ./AndroidManifest.xml ./android-sdk/installed ./src/$(PACKAGE)/R.java : $(shell find ./res -type f) app-config.sh ./AndroidManifest.xml ./android-sdk/installed | ./src/$(PACKAGE)
source app-config.sh; $${ANDROID_SDK_ROOT}/$$(tr ';' '/' < android-sdk/.installed.buildtools.version.current)/aapt package \ $(BUILDTOOLS)/aapt package \
-v -f -m -S ./res -J ./src -M ./AndroidManifest.xml \ -v -f -m -S ./res -J ./src -M ./AndroidManifest.xml \
-I $${ANDROID_SDK_ROOT}/$$(tr ';' '/' < android-sdk/.installed.platforms.version.current)/android.jar -I $(ANDROID_JAR)
# generate the AppActivity.java (template
# the "|" denotes an "order-only" prerequiste (as in https://stackoverflow.com/a/58040049/1711186)
./src/$(PACKAGE)/AppActivity.java: app-config.sh | ./src/$(PACKAGE)
./.Makefile.scripts/make--AppActivity.java.sh > $@
./src/$(PACKAGE):
mkdir -p $@
# install the necessary android sdks # install the necessary android sdks
./android-sdk/installed: app-config.sh ./android-sdk/installed: app-config.sh
@ -55,19 +68,24 @@ SHELL=/bin/bash
./AndroidManifest.xml: app-config.sh ./AndroidManifest.xml: app-config.sh
./.Makefile.scripts/make--AndroidManifest.xml ./.Makefile.scripts/make--AndroidManifest.xml
# recipe to make directories (if) needed Makefile.app-config: app-config.sh Makefile
./result ./bin ./assets ./src/ ./obj: source app-config.sh; \
mkdir -p "$@" tee $@ << MAKEFILE_APP_CONFIG
BUILDTOOLS:=$${ANDROID_SDK_ROOT}/$$(tr ';' '/' < android-sdk/.installed.buildtools.version.current)
# make symlinksa and directories (to cater for the "helpful" java thing, to use folders for package names and yes we need a package name :( ) ANDROID_JAR:=$${ANDROID_SDK_ROOT}/$$(tr ';' '/' < android-sdk/.installed.platforms.version.current)/android.jar
./src/package: app-config.sh PACKAGE:=$$(echo "$$APP_PACKAGE" | tr '.' '/')
set -x; source app-config.sh; PKGDIR=$$(echo "$$APP_PACKAGE" | tr '.' '/'); mkdir -p src/$$PKGDIR; rm -rf $@ ; ln -sfrv src/$$PKGDIR $@ MAKEFILE_APP_CONFIG
./obj/package: app-config.sh
source app-config.sh; PKGDIR=$$(echo "$$APP_PACKAGE" | tr '.' '/'); mkdir -p obj/$$PKGDIR; rm -rf $@; ln -sfrv obj/$$PKGDIR $@
# use whiptail textgui to make configuration (android API level, app-name, app-label etc...)
app-config.sh: app-config.sh:
./.Makefile.scripts/make--app-config.sh ./.Makefile.scripts/make--app-config.sh
# rule to effectuate a cleanup
clean:
rm -rf obj/* result/*
# this rule's purpose is to run "by force" no matter what, doing nothing
# as listed prerequisite to another rule it causes that rule to be made/run
# unconditionally every time
FORCE: FORCE:
@true @true

View file

@ -4,7 +4,37 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta content="width=device-width,initial-scale=1.0" name="viewport"> <meta content="width=device-width,initial-scale=1.0" name="viewport">
</head> </head>
<style>
@keyframes wobble {
0% {
transform: scale(0.1);
opacity:0.0
}
100% {
transform: scale(1.0);
opacity:1.0
}
}
</style>
<body> <body>
<h1> SUPER</h1> <h1>Webview</h1>
<script>
window.addEventListener("error",(error)=>{
document.body.innerHTML = "<h1>error</h1><pre>" +
error.filename +
"\nline:" + error.lineno +
"\n"+error.message +"</pre>";
},false);
window.addEventListener("load",()=>{
var count = localStorage.getItem("app-opened-count")|| 0;
count++;
localStorage.setItem("app-opened-count",count);
var h2 = document.createElement("h2");
h2.textContent = "Javascript works! (app was opened " + count + " times)";
h2.style.animation="wobble 1s ease-in-out 0s 1 forwards normal running"
document.body.appendChild(h2);
},false);
</script>
</body> </body>
</html> </html>

0
app/obj/.gitkeep Normal file
View file

View file

@ -1,11 +1,11 @@
#!/bin/sh #!/bin/sh
set -ex set -e
CONTAINERRUNTIMES='docker podman nerdctl' CONTAINERRUNTIMES='docker podman nerdctl'
for CONTAINERRUNTIME in $CONTAINERRUNTIMES / for CONTAINERRUNTIME in $CONTAINERRUNTIMES /
do do
type $CONTAINERRUNTIME 2>/dev/null && break type $CONTAINERRUNTIME >/dev/null 2>/dev/null && break
test "$CONTAINERRUNTIME" = / && { test "$CONTAINERRUNTIME" = / && {
echo "install a container runtime (e.g ${CONTAINERRUNTIMES//\ /\/})" >&2 echo "install a container runtime (e.g ${CONTAINERRUNTIMES//\ /\/})" >&2
exit 2 exit 2
@ -15,7 +15,7 @@ done
HASHES='md5sum cksum sha1sum base64 uuencode' HASHES='md5sum cksum sha1sum base64 uuencode'
for HASH in $HASHES / for HASH in $HASHES /
do do
type $HASH 2>/dev/null && break type $HASH >/dev/null 2>/dev/null && break
test "$HASH" = / && { test "$HASH" = / && {
echo "install checksum (e.g ${HASHES//\ /\/})" >&2 echo "install checksum (e.g ${HASHES//\ /\/})" >&2
exit 3 exit 3
@ -26,32 +26,46 @@ DockerfileContent(){
cat << 'DOCKERFILEEOF' cat << 'DOCKERFILEEOF'
FROM debian:latest FROM debian:latest
RUN apt-get update -y && apt-get install -y make openjdk-17-jdk-headless unzip zip wget curl whiptail RUN apt-get update -y && apt-get install -y make openjdk-17-jdk-headless unzip zip wget curl whiptail
ENTRYPOINT ["/bin/bash","-c","make"]
ENV JAVA_HOME="/usr/lib/jvm/java-17-openjdk-amd64/" ENV JAVA_HOME="/usr/lib/jvm/java-17-openjdk-amd64/"
ENV ANDROID_SDK_ROOT="/app/android-sdk" ENV ANDROID_SDK_ROOT="/app/android-sdk"
ENV BUILD_TOOLS_LATEST="$ANDROID_SDK_ROOT/cmdline-tools/latest" ENV BUILD_TOOLS_LATEST="$ANDROID_SDK_ROOT/cmdline-tools/latest"
ENV PATH="$BUILD_TOOLS_LATEST/bin:$PATH" ENV PATH="$BUILD_TOOLS_LATEST/bin:$PATH"
ENV LIBRARY_PATH="$LIBRARY_PATH:$BUILD_TOOLS_LATEST/lib" ENV LIBRARY_PATH="$LIBRARY_PATH:$BUILD_TOOLS_LATEST/lib"
CMD ["make","--trace"]
RUN <<EOF
cat > /bin/makefile-bash-wrapper.sh << 'WRAPPER'
#!/bin/bash
printf $'\033[0;32m''#----------------------------------------\n'$'\033[0m' >&2
bash "$@"
printf '\n\n\n\n' >&2
WRAPPER
chmod u+x /bin/makefile-bash-wrapper.sh
EOF
DOCKERFILEEOF DOCKERFILEEOF
} }
diff Dockerfile <(DockerfileContent) 2>/dev/null > /dev/null || { diff Dockerfile <(DockerfileContent) 2>/dev/null > /dev/null || {
test -f Dockerfile && {
read -p 'reset/start Dockerfile[Y/n]' YES read -p 'reset/start Dockerfile[Y/n]' YES
test "$YES" = "n" && { echo "aborting..." >&2; exit 1; } test "$YES" = "n" && { echo "aborting..." >&2; exit 1; }
}
DockerfileContent > Dockerfile DockerfileContent > Dockerfile
} }
IMAGE=android-app:"$($HASH Dockerfile | tr -cd '[a-zA-Z0-9]' | head -c 12)" IMAGE=build-android-app:"$($HASH Dockerfile | tr -cd '[a-zA-Z0-9]' | head -c 12)"
docker image inspect "$IMAGE" >/dev/null 2>/dev/null || { docker image inspect "$IMAGE" >/dev/null 2>/dev/null || {
$CONTAINERRUNTIME build --tag "$IMAGE" . $CONTAINERRUNTIME build --tag "$IMAGE" .
} }
#(optional) tag the latest image build
docker tag $IMAGE build-android-app:latest
$CONTAINERRUNTIME run --name build-android-app-$(date +%F--%H-%M-%S) \ time $CONTAINERRUNTIME run --name build-android-app-$(date +%F--%H-%M-%S) \
--workdir=/app \ --workdir=/app \
--env LINES=10 \
--env COLUMNS=$COLUMNS \
--hostname build-android-app \ --hostname build-android-app \
--volume ./app:/app \ --volume ./app:/app \
-it \ -it \
--rm \ --rm \
"$IMAGE" "$IMAGE" "$@"