mirror of
https://github.com/ARMSX2/ARMSX1.git
synced 2026-08-24 16:53:35 -07:00
feat(android): add support for building SDL2/libarmsx for Android
- Updated .gitignore to include Android native libraries and dependencies. - Modified android/app/build.gradle to register a new task for preparing native binaries. - Enhanced build.sh to support building SDL2/libarmsx for Android, including NDK setup and BIOS handling. - Refactored iOS AppDelegate to integrate RNOverlayController and EmulatorRunner for better overlay management. - Introduced EmulatorRunner class to handle the emulator lifecycle and argument passing. - Created RNOverlayController to manage the React Native overlay, including mounting and unmounting logic. - Updated Xcode project files to reflect new source files and dependencies.
This commit is contained in:
+6
-4
@@ -28,7 +28,9 @@ snap/
|
||||
psxe.app
|
||||
.DS_Store
|
||||
*/.DS_Store
|
||||
node_modules
|
||||
ios/HostApp/Pods/*
|
||||
ios/HostApp/build/*
|
||||
helpers/*
|
||||
node_modules
|
||||
ios/HostApp/Pods/*
|
||||
ios/HostApp/build/*
|
||||
helpers/*
|
||||
android/app/src/main/jniLibs/
|
||||
android/native-deps/
|
||||
|
||||
@@ -65,6 +65,7 @@ android {
|
||||
java.srcDirs += ['../../third_party/SDL/android-project/app/src/main/java']
|
||||
res.srcDirs += ['src/main/res', '../../third_party/SDL/android-project/app/src/main/res']
|
||||
assets.srcDirs += ['src/main/assets']
|
||||
jniLibs.srcDirs += ['src/main/jniLibs']
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,3 +88,21 @@ dependencies {
|
||||
implementation 'com.facebook.react:react-android:0.76.0'
|
||||
implementation 'com.facebook.react:hermes-android:0.76.0'
|
||||
}
|
||||
|
||||
def repoRootDir = rootProject.projectDir.parentFile
|
||||
def nativeOutput = file("$projectDir/src/main/jniLibs/arm64-v8a/libarmsx.so")
|
||||
|
||||
tasks.register("prepareNativeBinaries") {
|
||||
group = "native"
|
||||
description = "Build SDL2/libarmsx via build.sh android."
|
||||
inputs.file(new File(repoRootDir, "build.sh"))
|
||||
outputs.file(nativeOutput)
|
||||
doLast {
|
||||
exec {
|
||||
workingDir repoRootDir
|
||||
commandLine "./build.sh", "android"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
preBuild.dependsOn(tasks.named("prepareNativeBinaries"))
|
||||
|
||||
@@ -8,6 +8,7 @@ set -e
|
||||
# ./build.sh ios -> build iOS dylib using iPhone SDK + ios/Frameworks/SDL2.xcframework
|
||||
# ./build.sh macosapp -> build desktop exe and bundle armsx.app
|
||||
# ./build.sh wasm -> build WebAssembly target to bin/wasm using emscripten
|
||||
# ./build.sh android -> build SDL2/libarmsx for Android and stage under android/app/src/main/jniLibs
|
||||
|
||||
MODE="$1"
|
||||
|
||||
@@ -57,6 +58,115 @@ elif [ "$MODE" = "shared" ]; then
|
||||
make clean
|
||||
SDL_STATIC=0 make shared
|
||||
|
||||
elif [ "$MODE" = "android" ]; then
|
||||
ANDROID_NDK_ROOT="${ANDROID_NDK_ROOT:-${ANDROID_NDK_HOME:-${NDK_HOME:-}}}"
|
||||
if [ -z "${ANDROID_NDK_ROOT}" ]; then
|
||||
echo "ANDROID_NDK_ROOT (or ANDROID_NDK_HOME / NDK_HOME) must be set to a valid NDK path."
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -d "${ANDROID_NDK_ROOT}" ]; then
|
||||
echo "Android NDK path ${ANDROID_NDK_ROOT} does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ANDROID_ABI="${ANDROID_ABI:-arm64-v8a}"
|
||||
ANDROID_API="${ANDROID_API:-26}"
|
||||
ANDROID_PLATFORM="android-${ANDROID_API}"
|
||||
|
||||
case "${ANDROID_ABI}" in
|
||||
arm64-v8a)
|
||||
ANDROID_TRIPLE="aarch64-linux-android"
|
||||
;;
|
||||
armeabi-v7a)
|
||||
ANDROID_TRIPLE="armv7a-linux-androideabi"
|
||||
;;
|
||||
x86_64)
|
||||
ANDROID_TRIPLE="x86_64-linux-android"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported ANDROID_ABI '${ANDROID_ABI}'."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
HOST_OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
HOST_ARCH="$(uname -m)"
|
||||
case "${HOST_ARCH}" in
|
||||
arm64|aarch64)
|
||||
HOST_ARCH_TAG="arm64"
|
||||
;;
|
||||
x86_64)
|
||||
HOST_ARCH_TAG="x86_64"
|
||||
;;
|
||||
*)
|
||||
HOST_ARCH_TAG="${HOST_ARCH}"
|
||||
;;
|
||||
esac
|
||||
|
||||
HOST_TAG="${HOST_OS}-${HOST_ARCH_TAG}"
|
||||
TOOLCHAIN_DIR="${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/${HOST_TAG}"
|
||||
if [ ! -d "${TOOLCHAIN_DIR}" ]; then
|
||||
# Fallback to the first available prebuilt toolchain
|
||||
TOOLCHAIN_DIR="$(ls -d "${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/"* 2>/dev/null | head -n 1)"
|
||||
if [ -z "${TOOLCHAIN_DIR}" ]; then
|
||||
echo "Unable to locate LLVM toolchain inside ${ANDROID_NDK_ROOT}."
|
||||
exit 1
|
||||
fi
|
||||
HOST_TAG="$(basename "${TOOLCHAIN_DIR}")"
|
||||
fi
|
||||
|
||||
echo "Using Android NDK at ${ANDROID_NDK_ROOT} (toolchain ${HOST_TAG}, ABI ${ANDROID_ABI}, API ${ANDROID_API})"
|
||||
|
||||
SDL_BUILD_ROOT="build/android/sdl"
|
||||
SDL_INSTALL_DIR="${SDL_BUILD_ROOT}/install"
|
||||
mkdir -p "${SDL_BUILD_ROOT}"
|
||||
|
||||
cmake -S third_party/SDL -B "${SDL_BUILD_ROOT}" \
|
||||
-DANDROID=ON \
|
||||
-DANDROID_ABI="${ANDROID_ABI}" \
|
||||
-DANDROID_PLATFORM="${ANDROID_PLATFORM}" \
|
||||
-DANDROID_STL=c++_shared \
|
||||
-DCMAKE_SYSTEM_NAME=Android \
|
||||
-DCMAKE_ANDROID_NDK="${ANDROID_NDK_ROOT}" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_SHARED_LIBS=ON \
|
||||
-DSDL_STATIC=OFF \
|
||||
-DSDL_TEST=OFF \
|
||||
-DCMAKE_INSTALL_PREFIX="${SDL_INSTALL_DIR}"
|
||||
|
||||
cmake --build "${SDL_BUILD_ROOT}" --config Release
|
||||
cmake --install "${SDL_BUILD_ROOT}" --config Release
|
||||
|
||||
SDL_LIB_PATH="${SDL_INSTALL_DIR}/lib"
|
||||
SDL_INCLUDE_PATH="${SDL_INSTALL_DIR}/include/SDL2"
|
||||
SDL_SHARED_LIB="${SDL_LIB_PATH}/libSDL2.so"
|
||||
if [ ! -f "${SDL_SHARED_LIB}" ]; then
|
||||
echo "SDL shared library not found at ${SDL_SHARED_LIB}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
JNI_LIB_DIR="android/app/src/main/jniLibs/${ANDROID_ABI}"
|
||||
SDL_HEADER_STAGE="android/native-deps/SDL2/include"
|
||||
mkdir -p "${JNI_LIB_DIR}"
|
||||
rm -rf "${SDL_HEADER_STAGE}"
|
||||
mkdir -p "${SDL_HEADER_STAGE}"
|
||||
cp -R "${SDL_INCLUDE_PATH}/." "${SDL_HEADER_STAGE}/"
|
||||
|
||||
TOOLCHAIN_BIN="${TOOLCHAIN_DIR}/bin"
|
||||
CC="${TOOLCHAIN_BIN}/${ANDROID_TRIPLE}${ANDROID_API}-clang"
|
||||
CXX="${TOOLCHAIN_BIN}/${ANDROID_TRIPLE}${ANDROID_API}-clang++"
|
||||
export CC
|
||||
export CXX
|
||||
|
||||
SDL_CFLAGS="-D_REENTRANT -DANDROID -I${SDL_INCLUDE_PATH}"
|
||||
SDL_LIBS="-L${SDL_LIB_PATH} -lSDL2 -llog -landroid -lGLESv3 -lEGL -lOpenSLES -lm -lc++_shared"
|
||||
|
||||
make clean
|
||||
SDL_STATIC=0 SDL_CFLAGS="${SDL_CFLAGS}" SDL_LIBS_DYNAMIC="${SDL_LIBS}" make shared
|
||||
|
||||
cp "${SDL_SHARED_LIB}" "${JNI_LIB_DIR}/"
|
||||
cp bin/libarmsx.so "${JNI_LIB_DIR}/"
|
||||
|
||||
elif [ "$MODE" = "wasm" ]; then
|
||||
make clean
|
||||
if command -v emmake >/dev/null 2>&1; then
|
||||
|
||||
@@ -7,16 +7,17 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1085901F2ED1CE5200D77FB1 /* bios.bin in Resources */ = {isa = PBXBuildFile; fileRef = 1085901E2ED1CE5200D77FB1 /* bios.bin */; };
|
||||
0F9A2930A40B75845584BE6B /* RNOverlayController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0D4D51B594CEA0DA332E5D3E /* RNOverlayController.mm */; };
|
||||
3464725A44F4A69FBE2AB974 /* libarmsx.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 653A133BDB61BD1059CFAF23 /* libarmsx.dylib */; };
|
||||
3A83F5253BCB4AD47A6742B1 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F686B87C80EB4D3204CDEEC0 /* main.m */; };
|
||||
4193FB5FD92D4849FE747E3C /* libPods-ARMSX.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6AC80B70529AD04509472C06 /* libPods-ARMSX.a */; };
|
||||
48352C131E8B0327373C61EC /* SDL2.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 518B2258235B15B15373B04A /* SDL2.xcframework */; };
|
||||
5480B78F3661F4CB9446657C /* libarmsx.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 653A133BDB61BD1059CFAF23 /* libarmsx.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
7435C97274E9B2668E6C9C86 /* SDL2.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 518B2258235B15B15373B04A /* SDL2.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
8BC157B9E48AA3D81793AA6A /* ARMSXModule.m in Sources */ = {isa = PBXBuildFile; fileRef = B35E8D4127C001F1E6F6F2AF /* ARMSXModule.m */; };
|
||||
B16F42A290ECFF7DF154F24F /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9484FEBF96C002F04D73B70C /* AppDelegate.mm */; };
|
||||
CB535A71335895F3B1AFB7E3 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = EB192CCB1425D7B15B24E93A /* PrivacyInfo.xcprivacy */; };
|
||||
EFAA42EF186BC1A6B4315DDF /* libPods-ARMSX.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B15244F288D2AB7C06E0752A /* libPods-ARMSX.a */; };
|
||||
D01D643FB3D4148C346B6200 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 150B82E62E95502476AFB049 /* PrivacyInfo.xcprivacy */; };
|
||||
E46372898534C89975BD3888 /* EmulatorRunner.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6CFA7D190974AD439774FB40 /* EmulatorRunner.mm */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -36,21 +37,24 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
019479875FC7433ACB65A02E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||
1085901E2ED1CE5200D77FB1 /* bios.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = bios.bin; path = ../../bios.bin; sourceTree = "<group>"; };
|
||||
03BD4A1BC72E3DE47140D96E /* EmulatorRunner.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EmulatorRunner.h; sourceTree = "<group>"; };
|
||||
0D4D51B594CEA0DA332E5D3E /* RNOverlayController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = RNOverlayController.mm; sourceTree = "<group>"; };
|
||||
150B82E62E95502476AFB049 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
1760EE6722F9E2BEDFDCCC6D /* armsx_bridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = armsx_bridge.h; sourceTree = "<group>"; };
|
||||
2EC8F1F7ACC46D5FABC3595C /* Pods-ARMSX.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ARMSX.release.xcconfig"; path = "Target Support Files/Pods-ARMSX/Pods-ARMSX.release.xcconfig"; sourceTree = "<group>"; };
|
||||
518B2258235B15B15373B04A /* SDL2.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = SDL2.xcframework; path = ../Frameworks/SDL2.xcframework; sourceTree = "<group>"; };
|
||||
64E02E161FEB892FC40F8BE1 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
653A133BDB61BD1059CFAF23 /* libarmsx.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libarmsx.dylib; path = ../Frameworks/libarmsx.dylib; sourceTree = "<group>"; };
|
||||
67F12B2E9A249BA431A15C7C /* Pods-ARMSX.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ARMSX.debug.xcconfig"; path = "Target Support Files/Pods-ARMSX/Pods-ARMSX.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
6AC80B70529AD04509472C06 /* libPods-ARMSX.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ARMSX.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
6CFA7D190974AD439774FB40 /* EmulatorRunner.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = EmulatorRunner.mm; sourceTree = "<group>"; };
|
||||
6E26D0ECD2CD966E5EA1C326 /* Pods-ARMSX.release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Pods-ARMSX.release.xcconfig"; sourceTree = "<group>"; };
|
||||
87BA3EE4597141AA97A5557D /* ARMSX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ARMSX.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9484FEBF96C002F04D73B70C /* AppDelegate.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AppDelegate.mm; sourceTree = "<group>"; };
|
||||
996CB57F5DD4B88A0931BB95 /* ARMSXModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ARMSXModule.h; sourceTree = "<group>"; };
|
||||
B15244F288D2AB7C06E0752A /* libPods-ARMSX.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ARMSX.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B35E8D4127C001F1E6F6F2AF /* ARMSXModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ARMSXModule.m; sourceTree = "<group>"; };
|
||||
C65B43834B690E6C938FFCEB /* Pods-ARMSX.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ARMSX.debug.xcconfig"; path = "Target Support Files/Pods-ARMSX/Pods-ARMSX.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
D5E6D32A2F0405EA658F4F9F /* RNOverlayController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNOverlayController.h; sourceTree = "<group>"; };
|
||||
E3FAF87D7E4A2345FC43CA68 /* Pods-ARMSX.debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Pods-ARMSX.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
EB192CCB1425D7B15B24E93A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
F150862C7055ADDBB5B57CF1 /* Pods-ARMSX.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ARMSX.release.xcconfig"; path = "Target Support Files/Pods-ARMSX/Pods-ARMSX.release.xcconfig"; sourceTree = "<group>"; };
|
||||
F686B87C80EB4D3204CDEEC0 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@@ -61,7 +65,7 @@
|
||||
files = (
|
||||
48352C131E8B0327373C61EC /* SDL2.xcframework in Frameworks */,
|
||||
3464725A44F4A69FBE2AB974 /* libarmsx.dylib in Frameworks */,
|
||||
EFAA42EF186BC1A6B4315DDF /* libPods-ARMSX.a in Frameworks */,
|
||||
4193FB5FD92D4849FE747E3C /* libPods-ARMSX.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -73,7 +77,7 @@
|
||||
children = (
|
||||
653A133BDB61BD1059CFAF23 /* libarmsx.dylib */,
|
||||
518B2258235B15B15373B04A /* SDL2.xcframework */,
|
||||
B15244F288D2AB7C06E0752A /* libPods-ARMSX.a */,
|
||||
6AC80B70529AD04509472C06 /* libPods-ARMSX.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -81,13 +85,12 @@
|
||||
48D57A41DAF59CF0D443A086 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1085901E2ED1CE5200D77FB1 /* bios.bin */,
|
||||
B6E3FD0B464E641CA58C9EA3 /* Pods-ARMSX */,
|
||||
D0581165A1AB8CE875BD92E0 /* Sources */,
|
||||
473DBC863A1B097C0DD3710F /* Frameworks */,
|
||||
9B7D6BDFE7232B2E5D8A379F /* Products */,
|
||||
EB192CCB1425D7B15B24E93A /* PrivacyInfo.xcprivacy */,
|
||||
A221D24E0608A650E479FF55 /* Pods */,
|
||||
150B82E62E95502476AFB049 /* PrivacyInfo.xcprivacy */,
|
||||
A03BFBC5506510D43087F66D /* Pods */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -99,12 +102,13 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A221D24E0608A650E479FF55 /* Pods */ = {
|
||||
A03BFBC5506510D43087F66D /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67F12B2E9A249BA431A15C7C /* Pods-ARMSX.debug.xcconfig */,
|
||||
F150862C7055ADDBB5B57CF1 /* Pods-ARMSX.release.xcconfig */,
|
||||
C65B43834B690E6C938FFCEB /* Pods-ARMSX.debug.xcconfig */,
|
||||
2EC8F1F7ACC46D5FABC3595C /* Pods-ARMSX.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -126,8 +130,12 @@
|
||||
1760EE6722F9E2BEDFDCCC6D /* armsx_bridge.h */,
|
||||
996CB57F5DD4B88A0931BB95 /* ARMSXModule.h */,
|
||||
B35E8D4127C001F1E6F6F2AF /* ARMSXModule.m */,
|
||||
03BD4A1BC72E3DE47140D96E /* EmulatorRunner.h */,
|
||||
6CFA7D190974AD439774FB40 /* EmulatorRunner.mm */,
|
||||
019479875FC7433ACB65A02E /* Info.plist */,
|
||||
F686B87C80EB4D3204CDEEC0 /* main.m */,
|
||||
D5E6D32A2F0405EA658F4F9F /* RNOverlayController.h */,
|
||||
0D4D51B594CEA0DA332E5D3E /* RNOverlayController.mm */,
|
||||
);
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
@@ -139,13 +147,13 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 1A8EEE030E970E82EC7B77F8 /* Build configuration list for PBXNativeTarget "ARMSX" */;
|
||||
buildPhases = (
|
||||
EFC8122B20E4CF7480A3496D /* [CP] Check Pods Manifest.lock */,
|
||||
317B2A99C6743282DB0B4378 /* [CP] Check Pods Manifest.lock */,
|
||||
21709ABD74D1031F0389C4EC /* Sources */,
|
||||
D6910F21954EF81975654CFA /* Frameworks */,
|
||||
8F7F79E31569D7CF1ACBC707 /* Embed Frameworks */,
|
||||
469D63DB0DB7A815B1CF8164 /* Resources */,
|
||||
DBCAE27636921EA4F4D6F40B /* [CP] Embed Pods Frameworks */,
|
||||
15CF2083A041D419876ECE72 /* [CP] Copy Pods Resources */,
|
||||
CC0F3B60AB5121E52FB88488 /* Resources */,
|
||||
A1F84CFC47166FD1D4F87D5C /* [CP] Embed Pods Frameworks */,
|
||||
A2B4EFBBBDD2A4D81A6CEE13 /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -185,53 +193,18 @@
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
469D63DB0DB7A815B1CF8164 /* Resources */ = {
|
||||
CC0F3B60AB5121E52FB88488 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1085901F2ED1CE5200D77FB1 /* bios.bin in Resources */,
|
||||
CB535A71335895F3B1AFB7E3 /* PrivacyInfo.xcprivacy in Resources */,
|
||||
D01D643FB3D4148C346B6200 /* PrivacyInfo.xcprivacy in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
15CF2083A041D419876ECE72 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-ARMSX/Pods-ARMSX-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-ARMSX/Pods-ARMSX-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ARMSX/Pods-ARMSX-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
DBCAE27636921EA4F4D6F40B /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-ARMSX/Pods-ARMSX-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-ARMSX/Pods-ARMSX-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ARMSX/Pods-ARMSX-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
EFC8122B20E4CF7480A3496D /* [CP] Check Pods Manifest.lock */ = {
|
||||
317B2A99C6743282DB0B4378 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -253,6 +226,40 @@
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
A1F84CFC47166FD1D4F87D5C /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-ARMSX/Pods-ARMSX-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-ARMSX/Pods-ARMSX-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ARMSX/Pods-ARMSX-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
A2B4EFBBBDD2A4D81A6CEE13 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-ARMSX/Pods-ARMSX-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-ARMSX/Pods-ARMSX-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ARMSX/Pods-ARMSX-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@@ -262,6 +269,8 @@
|
||||
files = (
|
||||
8BC157B9E48AA3D81793AA6A /* ARMSXModule.m in Sources */,
|
||||
B16F42A290ECFF7DF154F24F /* AppDelegate.mm in Sources */,
|
||||
E46372898534C89975BD3888 /* EmulatorRunner.mm in Sources */,
|
||||
0F9A2930A40B75845584BE6B /* RNOverlayController.mm in Sources */,
|
||||
3A83F5253BCB4AD47A6742B1 /* main.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -271,7 +280,7 @@
|
||||
/* Begin XCBuildConfiguration section */
|
||||
6C84D25B5BF8B28E170A1AC3 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 67F12B2E9A249BA431A15C7C /* Pods-ARMSX.debug.xcconfig */;
|
||||
baseConfigurationReference = C65B43834B690E6C938FFCEB /* Pods-ARMSX.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
@@ -438,7 +447,7 @@
|
||||
};
|
||||
EA79FDBEDBB17F1B501A7D1A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = F150862C7055ADDBB5B57CF1 /* Pods-ARMSX.release.xcconfig */;
|
||||
baseConfigurationReference = 2EC8F1F7ACC46D5FABC3595C /* Pods-ARMSX.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
|
||||
Generated
BIN
Binary file not shown.
@@ -1,6 +1,5 @@
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import <SDL2/SDL.h>
|
||||
#ifndef USE_HERMES
|
||||
#define USE_HERMES 1
|
||||
#endif
|
||||
@@ -9,18 +8,12 @@
|
||||
#else
|
||||
#import <React/RCTAppSetupUtils.h>
|
||||
#endif
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTBundleURLProvider.h>
|
||||
#import <React/RCTRootView.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#import "RNOverlayController.h"
|
||||
#import "EmulatorRunner.h"
|
||||
|
||||
#import "armsx_bridge.h"
|
||||
|
||||
@interface AppDelegate () <RCTBridgeDelegate>
|
||||
@property (nonatomic, assign) BOOL armsxRunning;
|
||||
@property (nonatomic, strong) RCTBridge *reactBridge;
|
||||
@property (nonatomic, strong) RCTRootView *reactRootView;
|
||||
@interface AppDelegate ()
|
||||
@property (nonatomic, strong) RNOverlayController *overlayController;
|
||||
@property (nonatomic, strong) EmulatorRunner *emulatorRunner;
|
||||
@end
|
||||
|
||||
@implementation AppDelegate
|
||||
@@ -56,173 +49,32 @@
|
||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
self.window.backgroundColor = [UIColor blackColor];
|
||||
|
||||
UIViewController *controller = [UIViewController new];
|
||||
controller.view.backgroundColor = [UIColor blackColor];
|
||||
self.window.rootViewController = controller;
|
||||
self.overlayController = [[RNOverlayController alloc] initWithLaunchOptions:launchOptions];
|
||||
self.window.rootViewController = self.overlayController;
|
||||
[self.window makeKeyAndVisible];
|
||||
|
||||
[self attachReactNativeOverlay:launchOptions];
|
||||
[self attachReactNativeOverlay];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)attachReactNativeOverlay:(NSDictionary *)launchOptions {
|
||||
if (!self.window) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self.reactBridge) {
|
||||
self.reactBridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
|
||||
}
|
||||
|
||||
self.reactRootView = [[RCTRootView alloc] initWithBridge:self.reactBridge moduleName:@"ARMSXOverlay" initialProperties:nil];
|
||||
self.reactRootView.backgroundColor = [UIColor blackColor];
|
||||
self.reactRootView.frame = self.window.bounds;
|
||||
self.reactRootView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
|
||||
UIView *targetView = self.window.rootViewController.view ?: self.window;
|
||||
[targetView addSubview:self.reactRootView];
|
||||
- (void)attachReactNativeOverlay {
|
||||
[self.overlayController mountOverlayIfNeeded];
|
||||
}
|
||||
|
||||
- (void)teardownReactSurface {
|
||||
if (self.reactRootView && self.reactRootView.superview) {
|
||||
[self.reactRootView removeFromSuperview];
|
||||
}
|
||||
self.reactRootView = nil;
|
||||
[self.overlayController unmountOverlay];
|
||||
}
|
||||
|
||||
- (void)startSDLWithArgs:(NSArray<NSString *> *)args {
|
||||
if (self.armsxRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self teardownReactSurface];
|
||||
[self forceLandscapeIfNeeded];
|
||||
|
||||
SDL_SetMainReady();
|
||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal");
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS) != 0) {
|
||||
NSLog(@"SDL_Init failed: %s", SDL_GetError());
|
||||
return;
|
||||
if (!self.emulatorRunner) {
|
||||
self.emulatorRunner = [EmulatorRunner new];
|
||||
}
|
||||
|
||||
self.armsxRunning = YES;
|
||||
|
||||
// Run the SDL/armsx entry on the main thread to satisfy UIKit threading requirements
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
@autoreleasepool {
|
||||
NSMutableArray<NSString *> *nativeArgs = [NSMutableArray arrayWithObject:@"armsx"];
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
|
||||
// Look for bios.bin packaged in the bundle (root, Contents/, or resource dir)
|
||||
NSMutableArray<NSString *> *candidatePaths = [NSMutableArray array];
|
||||
NSBundle *bundle = [NSBundle mainBundle];
|
||||
|
||||
NSString *bundleRoot = bundle.bundlePath;
|
||||
NSString *resourceRoot = bundle.resourcePath;
|
||||
|
||||
// Common bundle layouts
|
||||
if (bundleRoot.length) {
|
||||
[candidatePaths addObject:[bundleRoot stringByAppendingPathComponent:@"bios.bin"]];
|
||||
[candidatePaths addObject:[bundleRoot stringByAppendingPathComponent:@"Contents/bios.bin"]];
|
||||
}
|
||||
if (resourceRoot.length) {
|
||||
[candidatePaths addObject:[resourceRoot stringByAppendingPathComponent:@"bios.bin"]];
|
||||
}
|
||||
|
||||
// XcodeGen resources (if the optional BIOS is present)
|
||||
NSString *biosPath = [bundle pathForResource:@"bios" ofType:@"bin"];
|
||||
if (biosPath.length) {
|
||||
[candidatePaths insertObject:biosPath atIndex:0];
|
||||
}
|
||||
|
||||
biosPath = nil;
|
||||
|
||||
for (NSString *candidate in candidatePaths) {
|
||||
if ([fm fileExistsAtPath:candidate]) {
|
||||
biosPath = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// As a last resort, try SDL's base path
|
||||
if (!biosPath.length) {
|
||||
char *basePathC = SDL_GetBasePath();
|
||||
if (basePathC) {
|
||||
NSString *basePath = [NSString stringWithUTF8String:basePathC];
|
||||
SDL_free(basePathC);
|
||||
NSString *fallback = [basePath stringByAppendingPathComponent:@"bios.bin"];
|
||||
if ([fm fileExistsAtPath:fallback]) {
|
||||
biosPath = fallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If found, copy to a writable pref path to avoid any translocation issues
|
||||
if (biosPath.length && [fm fileExistsAtPath:biosPath]) {
|
||||
char *prefPathC = SDL_GetPrefPath("nanodata", "armsx");
|
||||
NSString *prefBase = prefPathC ? [NSString stringWithUTF8String:prefPathC] : nil;
|
||||
if (prefPathC) {
|
||||
SDL_free(prefPathC);
|
||||
}
|
||||
|
||||
NSString *writableBios = prefBase ? [prefBase stringByAppendingPathComponent:@"bios.bin"] : nil;
|
||||
NSError *copyErr = nil;
|
||||
|
||||
// Clean existing copy to avoid stale/corrupt data
|
||||
if (writableBios.length && [fm fileExistsAtPath:writableBios]) {
|
||||
[fm removeItemAtPath:writableBios error:nil];
|
||||
}
|
||||
|
||||
if (writableBios.length && [fm copyItemAtPath:biosPath toPath:writableBios error:©Err]) {
|
||||
biosPath = writableBios;
|
||||
NSLog(@"Using bundled BIOS copied to writable path %@", biosPath);
|
||||
} else if (writableBios.length) {
|
||||
NSLog(@"Failed to copy BIOS to writable location (%@). Using bundle path. Error: %@", writableBios, copyErr);
|
||||
}
|
||||
}
|
||||
|
||||
if (biosPath.length && [fm fileExistsAtPath:biosPath]) {
|
||||
[nativeArgs addObject:@"--bios"];
|
||||
[nativeArgs addObject:biosPath];
|
||||
NSLog(@"Passing BIOS path to libarmsx: %@", biosPath);
|
||||
} else {
|
||||
NSLog(@"No bundled BIOS found; libarmsx will rely on user-provided settings/CLI.");
|
||||
}
|
||||
|
||||
if (args.count) {
|
||||
[nativeArgs addObjectsFromArray:args];
|
||||
}
|
||||
|
||||
std::vector<std::string> args;
|
||||
std::vector<const char *> argv;
|
||||
|
||||
for (NSString *s in nativeArgs) {
|
||||
args.emplace_back([s UTF8String]);
|
||||
}
|
||||
|
||||
for (const auto &s : args)
|
||||
argv.push_back(s.c_str());
|
||||
|
||||
argv.push_back(nullptr);
|
||||
|
||||
// Let the dylib create its own SDL window/renderer
|
||||
external_main((int)args.size(), argv.data(), NULL, NULL);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
|
||||
#if DEBUG
|
||||
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
|
||||
#else
|
||||
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(UIApplication *)application {
|
||||
self.armsxRunning = NO;
|
||||
[self.emulatorRunner startWithArgs:args ?: @[]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface EmulatorRunner : NSObject
|
||||
|
||||
@property (nonatomic, assign, readonly, getter=isRunning) BOOL running;
|
||||
|
||||
- (void)startWithArgs:(NSArray<NSString *> *)args;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,128 @@
|
||||
#import "EmulatorRunner.h"
|
||||
|
||||
#import <SDL2/SDL.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#import "armsx_bridge.h"
|
||||
|
||||
@interface EmulatorRunner ()
|
||||
@property (nonatomic, assign, readwrite, getter=isRunning) BOOL running;
|
||||
@end
|
||||
|
||||
@implementation EmulatorRunner
|
||||
|
||||
- (void)startWithArgs:(NSArray<NSString *> *)args {
|
||||
if (self.running) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_SetMainReady();
|
||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal");
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS) != 0) {
|
||||
NSLog(@"SDL_Init failed: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
self.running = YES;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
@autoreleasepool {
|
||||
NSMutableArray<NSString *> *nativeArgs = [NSMutableArray arrayWithObject:@"armsx"];
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
|
||||
NSMutableArray<NSString *> *candidatePaths = [NSMutableArray array];
|
||||
NSBundle *bundle = [NSBundle mainBundle];
|
||||
|
||||
NSString *bundleRoot = bundle.bundlePath;
|
||||
NSString *resourceRoot = bundle.resourcePath;
|
||||
|
||||
if (bundleRoot.length) {
|
||||
[candidatePaths addObject:[bundleRoot stringByAppendingPathComponent:@"bios.bin"]];
|
||||
[candidatePaths addObject:[bundleRoot stringByAppendingPathComponent:@"Contents/bios.bin"]];
|
||||
}
|
||||
if (resourceRoot.length) {
|
||||
[candidatePaths addObject:[resourceRoot stringByAppendingPathComponent:@"bios.bin"]];
|
||||
}
|
||||
|
||||
NSString *biosPath = [bundle pathForResource:@"bios" ofType:@"bin"];
|
||||
if (biosPath.length) {
|
||||
[candidatePaths insertObject:biosPath atIndex:0];
|
||||
}
|
||||
|
||||
biosPath = nil;
|
||||
|
||||
for (NSString *candidate in candidatePaths) {
|
||||
if ([fm fileExistsAtPath:candidate]) {
|
||||
biosPath = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!biosPath.length) {
|
||||
char *basePathC = SDL_GetBasePath();
|
||||
if (basePathC) {
|
||||
NSString *basePath = [NSString stringWithUTF8String:basePathC];
|
||||
SDL_free(basePathC);
|
||||
NSString *fallback = [basePath stringByAppendingPathComponent:@"bios.bin"];
|
||||
if ([fm fileExistsAtPath:fallback]) {
|
||||
biosPath = fallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (biosPath.length && [fm fileExistsAtPath:biosPath]) {
|
||||
char *prefPathC = SDL_GetPrefPath("nanodata", "armsx");
|
||||
NSString *prefBase = prefPathC ? [NSString stringWithUTF8String:prefPathC] : nil;
|
||||
if (prefPathC) {
|
||||
SDL_free(prefPathC);
|
||||
}
|
||||
|
||||
NSString *writableBios = prefBase ? [prefBase stringByAppendingPathComponent:@"bios.bin"] : nil;
|
||||
NSError *copyErr = nil;
|
||||
|
||||
if (writableBios.length && [fm fileExistsAtPath:writableBios]) {
|
||||
[fm removeItemAtPath:writableBios error:nil];
|
||||
}
|
||||
|
||||
if (writableBios.length && [fm copyItemAtPath:biosPath toPath:writableBios error:©Err]) {
|
||||
biosPath = writableBios;
|
||||
NSLog(@"Using bundled BIOS copied to writable path %@", biosPath);
|
||||
} else if (writableBios.length) {
|
||||
NSLog(@"Failed to copy BIOS to writable location (%@). Using bundle path. Error: %@", writableBios, copyErr);
|
||||
}
|
||||
}
|
||||
|
||||
if (biosPath.length && [fm fileExistsAtPath:biosPath]) {
|
||||
[nativeArgs addObject:@"--bios"];
|
||||
[nativeArgs addObject:biosPath];
|
||||
NSLog(@"Passing BIOS path to libarmsx: %@", biosPath);
|
||||
} else {
|
||||
NSLog(@"No bundled BIOS found; libarmsx will rely on user-provided settings/CLI.");
|
||||
}
|
||||
|
||||
if (args.count) {
|
||||
[nativeArgs addObjectsFromArray:args];
|
||||
}
|
||||
|
||||
std::vector<std::string> argvStorage;
|
||||
std::vector<const char *> argv;
|
||||
|
||||
for (NSString *stringArg in nativeArgs) {
|
||||
argvStorage.emplace_back([stringArg UTF8String]);
|
||||
}
|
||||
|
||||
for (const auto &value : argvStorage) {
|
||||
argv.push_back(value.c_str());
|
||||
}
|
||||
|
||||
argv.push_back(nullptr);
|
||||
|
||||
external_main((int)argvStorage.size(), argv.data(), NULL, NULL);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,13 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RNOverlayController : UIViewController
|
||||
|
||||
- (instancetype)initWithLaunchOptions:(NSDictionary *)launchOptions;
|
||||
- (void)mountOverlayIfNeeded;
|
||||
- (void)unmountOverlay;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,66 @@
|
||||
#import "RNOverlayController.h"
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTBundleURLProvider.h>
|
||||
#import <React/RCTRootView.h>
|
||||
|
||||
@interface RNOverlayController () <RCTBridgeDelegate>
|
||||
@property (nonatomic, strong) NSDictionary *launchOptions;
|
||||
@property (nonatomic, strong, nullable) RCTBridge *bridge;
|
||||
@property (nonatomic, strong, nullable) RCTRootView *rootView;
|
||||
@end
|
||||
|
||||
@implementation RNOverlayController
|
||||
|
||||
- (instancetype)initWithLaunchOptions:(NSDictionary *)launchOptions {
|
||||
self = [super initWithNibName:nil bundle:nil];
|
||||
if (self) {
|
||||
_launchOptions = launchOptions ?: @{};
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.view.backgroundColor = [UIColor blackColor];
|
||||
[self mountOverlayIfNeeded];
|
||||
}
|
||||
|
||||
- (void)mountOverlayIfNeeded {
|
||||
if (!self.bridge) {
|
||||
self.bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:self.launchOptions];
|
||||
}
|
||||
|
||||
if (self.rootView) {
|
||||
if (!self.rootView.superview) {
|
||||
[self.view addSubview:self.rootView];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:self.bridge moduleName:@"ARMSXOverlay" initialProperties:nil];
|
||||
rootView.frame = self.view.bounds;
|
||||
rootView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
rootView.backgroundColor = [UIColor blackColor];
|
||||
[self.view addSubview:rootView];
|
||||
self.rootView = rootView;
|
||||
}
|
||||
|
||||
- (void)unmountOverlay {
|
||||
if (self.rootView && self.rootView.superview) {
|
||||
[self.rootView removeFromSuperview];
|
||||
}
|
||||
self.rootView = nil;
|
||||
}
|
||||
|
||||
#pragma mark - RCTBridgeDelegate
|
||||
|
||||
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
|
||||
#if DEBUG
|
||||
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
|
||||
#else
|
||||
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user