Adding first APK build
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
package de.ladkau.questshock;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import org.libsdl.app.SDLActivity;
|
||||
|
||||
/**
|
||||
* Everything here runs before super.onCreate() (which is what loads the
|
||||
* native libraries and eventually calls Shockolate's own main()) - see
|
||||
* android/engine-patches/ for why: engine/ itself is never modified, so
|
||||
* this Java-side setup is the only place left to prepare
|
||||
* /sdcard/questshock/ the way Shockolate's plain relative-path file I/O
|
||||
* ("res/data/...", confirmed via grep - none of it goes through SDL_RWops,
|
||||
* so Android's asset-manager fallback for SDL_RWFromFile doesn't apply
|
||||
* here) expects to find it.
|
||||
*/
|
||||
public class QuestShockActivity extends SDLActivity {
|
||||
private static final String TAG = "QuestShock";
|
||||
private static final int PERMISSION_REQUEST_STORAGE = 1;
|
||||
private static final String GAME_DIR = "/sdcard/questshock";
|
||||
|
||||
// Loaded here (rather than waiting for SDLActivity's own
|
||||
// getLibraries()/loadLibraries(), which only runs from super.onCreate())
|
||||
// purely to get nativeChdir() below - Android's dynamic linker resolves
|
||||
// "main"'s own dependencies (SDL2, SDL2_mixer, fluidsynth) from the
|
||||
// APK's native library directory regardless of Java-side load order, so
|
||||
// loading it early here is safe. SDLActivity loading "main" again later
|
||||
// is a harmless no-op (System.loadLibrary is idempotent per
|
||||
// ClassLoader).
|
||||
static {
|
||||
System.loadLibrary("main");
|
||||
}
|
||||
|
||||
// See android/app/src/main/cpp/questshock_native.c - android.system.Os
|
||||
// has no public chdir() (confirmed against the actual API 34 stub jar).
|
||||
private static native void nativeChdir(String path);
|
||||
|
||||
private Bundle mSavedInstanceState;
|
||||
|
||||
@Override
|
||||
protected String[] getLibraries() {
|
||||
return new String[] {
|
||||
"SDL2",
|
||||
"SDL2_mixer",
|
||||
"fluidsynth",
|
||||
"main"
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
mSavedInstanceState = savedInstanceState;
|
||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(this,
|
||||
new String[] { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE },
|
||||
PERMISSION_REQUEST_STORAGE);
|
||||
return;
|
||||
}
|
||||
setUpGameDirAndContinue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
if (requestCode == PERMISSION_REQUEST_STORAGE) {
|
||||
setUpGameDirAndContinue();
|
||||
return;
|
||||
}
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
private void setUpGameDirAndContinue() {
|
||||
File gameDir = new File(GAME_DIR);
|
||||
if (!gameDir.exists() && !gameDir.mkdirs()) {
|
||||
Log.e(TAG, "Could not create " + GAME_DIR + " - res/data and res/sound will not be found");
|
||||
}
|
||||
|
||||
// Extract our own bundled build artifacts (shaders, the soundfont,
|
||||
// and the "get assets" instructions) - never the proprietary game
|
||||
// data, which the user must supply themselves (see
|
||||
// res/GET_ASSETS_QUEST.txt). Only done once: if res/GET_ASSETS_QUEST.txt
|
||||
// is already there, assume a previous run already extracted everything.
|
||||
File marker = new File(gameDir, "GET_ASSETS_QUEST.txt");
|
||||
if (!marker.exists()) {
|
||||
copyAssetDir("shaders", new File(gameDir, "shaders"));
|
||||
copyAssetFile("res/soundfont.sf2", new File(gameDir, "res/soundfont.sf2"));
|
||||
copyAssetFile("GET_ASSETS_QUEST.txt", marker);
|
||||
}
|
||||
|
||||
// chdir() is process-wide, not per-thread - already in effect for
|
||||
// every thread (including the one that will run Shockolate's own
|
||||
// SDL_main) by the time super.onCreate() below starts it.
|
||||
nativeChdir(GAME_DIR);
|
||||
|
||||
super.onCreate(mSavedInstanceState);
|
||||
}
|
||||
|
||||
private void copyAssetFile(String assetPath, File dest) {
|
||||
if (dest.exists()) {
|
||||
return;
|
||||
}
|
||||
File parent = dest.getParentFile();
|
||||
if (parent != null) {
|
||||
parent.mkdirs();
|
||||
}
|
||||
AssetManager assets = getAssets();
|
||||
try (InputStream in = assets.open(assetPath);
|
||||
OutputStream out = new FileOutputStream(dest)) {
|
||||
byte[] buf = new byte[64 * 1024];
|
||||
int n;
|
||||
while ((n = in.read(buf)) > 0) {
|
||||
out.write(buf, 0, n);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Could not extract asset " + assetPath + " to " + dest, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyAssetDir(String assetDir, File destDir) {
|
||||
AssetManager assets = getAssets();
|
||||
String[] entries;
|
||||
try {
|
||||
entries = assets.list(assetDir);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Could not list asset dir " + assetDir, e);
|
||||
return;
|
||||
}
|
||||
if (entries == null || entries.length == 0) {
|
||||
return;
|
||||
}
|
||||
destDir.mkdirs();
|
||||
for (String entry : entries) {
|
||||
copyAssetFile(assetDir + "/" + entry, new File(destDir, entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user