Android: Bundle in-tree mods into the APK

This commit is contained in:
Luke Street
2026-07-14 09:22:50 -06:00
parent d5fcd79306
commit 8471fa0107
5 changed files with 83 additions and 0 deletions
+4
View File
@@ -205,6 +205,9 @@ jobs:
- name: Build native library
run: cmake --build --preset ${{matrix.preset}} --target dusklight
- name: Build bundled mods
run: cmake --build --preset ${{matrix.preset}} --target dusklight_mods
- name: Stage stripped JNI library
run: ANDROID_STAGE_ABIS="${{matrix.abi}}" platforms/android/scripts/stage-jni-libs.sh
@@ -289,5 +292,6 @@ jobs:
build/install/*.dll
build/install/*.symdb
build/install/res/
build/install/mods/
build/install/debug.7z
build/install/sdk/
+1
View File
@@ -3,3 +3,4 @@ build/
app/build/
local.properties
app/src/main/jniLibs/*/*.so
app/src/main/bundled_mods/
+5
View File
@@ -12,6 +12,11 @@ def syncDuskAssets = tasks.register('syncDuskAssets', Sync) {
into 'res'
exclude '**/.DS_Store'
}
// Staged by platforms/android/scripts/stage-jni-libs.sh
from(new File(projectDir, 'src/main/bundled_mods')) {
into 'mods'
include '*.dusk'
}
into duskGeneratedAssetsDir
}
@@ -27,6 +27,10 @@ import org.libsdl.app.SDLActivity;
import org.libsdl.app.SDLSurface;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
@@ -90,10 +94,55 @@ public class DuskActivity extends SDLActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
extractBundledMods();
super.onCreate(savedInstanceState);
hideSystemBars();
}
// Bundled mod packages ship as APK assets, which the native loader cannot read directly;
// mirror them into internal storage (the loader's CachePath/bundled_mods search dir)
// before SDL_main starts.
private void extractBundledMods() {
File outDir = new File(getFilesDir(), "bundled_mods");
try {
deleteRecursively(outDir); // drop packages removed by an app update
String[] names = getAssets().list("mods");
if (names == null || names.length == 0) {
return;
}
if (!outDir.mkdirs()) {
Log.w(TAG, "Unable to create " + outDir);
return;
}
byte[] buffer = new byte[65536];
for (String name : names) {
if (!name.endsWith(".dusk")) {
continue;
}
try (InputStream in = getAssets().open("mods/" + name);
OutputStream out = new FileOutputStream(new File(outDir, name)))
{
int count;
while ((count = in.read(buffer)) > 0) {
out.write(buffer, 0, count);
}
}
}
} catch (IOException e) {
Log.w(TAG, "Failed to extract bundled mods", e);
}
}
private static void deleteRecursively(File file) {
File[] children = file.listFiles();
if (children != null) {
for (File child : children) {
deleteRecursively(child);
}
}
file.delete();
}
@Override
protected SDLSurface createSDLSurface(Context context) {
return new DuskSurface(context);
@@ -70,3 +70,27 @@ for abi in $ANDROID_STAGE_ABIS; do
esac
copy_lib "$abi" "$src"
done
# Stage bundled mod packages into the app's assets source dir.
MODS_STAGING_DIR="$ROOT_DIR/platforms/android/app/src/main/bundled_mods"
rm -rf "$MODS_STAGING_DIR"
mkdir -p "$MODS_STAGING_DIR"
for abi in $ANDROID_STAGE_ABIS; do
case "$abi" in
arm64-v8a) build_dir="$ROOT_DIR/build/android-arm64" ;;
x86_64) build_dir="$ROOT_DIR/build/android-x86_64" ;;
esac
[[ -d "$build_dir/bundled_mods" ]] || continue
for pkg in "$build_dir/bundled_mods"/*.dusk; do
[[ -f "$pkg" ]] || continue
name="$(basename "$pkg")"
if [[ ! -f "$MODS_STAGING_DIR/$name" ]]; then
cp -f "$pkg" "$MODS_STAGING_DIR/$name"
echo "Staged bundled mod $pkg"
else
stage_dir="$build_dir/mods/${name%.dusk}/${name%.dusk}_stage"
(cd "$stage_dir" && zip -q -r "$MODS_STAGING_DIR/$name" lib)
echo "Appended $abi libraries to bundled mod $name"
fi
done
done