Replace React Native frontend with FSUI integration

This commit is contained in:
moonpower
2026-04-04 22:08:46 +02:00
parent 4d520d1ccd
commit 01a308dd44
68 changed files with 3753 additions and 40832 deletions
-24
View File
@@ -2,15 +2,6 @@ plugins {
id 'com.android.application'
}
apply from: file('../react-native-plugin.gradle')
ext {
hermesEnabled = true
react = [
enableHermes: true
]
}
android {
namespace 'com.nanodata.armsx'
compileSdk rootProject.ext.compileSdkVersion
@@ -70,23 +61,8 @@ android {
}
}
react {
root = file('..')
reactNativeDir = file('../node_modules/react-native')
cliFile = file('../node_modules/react-native/cli.js')
entryFile = file('../mobile/index.js')
}
def nativeModulesAppGradle = file('../node_modules/@react-native-community/cli-platform-android/native_modules.gradle')
if (nativeModulesAppGradle.isFile()) {
apply from: nativeModulesAppGradle
applyNativeModulesAppBuildGradle(project)
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'com.facebook.react:react-android:0.76.0'
implementation 'com.facebook.react:hermes-android:0.76.0'
}
def repoRootDir = rootProject.projectDir.parentFile
+5 -16
View File
@@ -1,36 +1,25 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.nanodata.armsx">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name="android.app.Application"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:usesCleartextTraffic="true"
android:theme="@style/AppTheme">
<activity
android:name=".OverlayActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:name=".EmulatorActivity"
android:exported="true"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize">
android:screenOrientation="sensorLandscape"
android:resizeableActivity="false"
android:theme="@style/AppTheme.NoOverlay">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".EmulatorActivity"
android:exported="false"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:launchMode="singleTask"
android:screenOrientation="sensorLandscape"
android:resizeableActivity="false"
android:theme="@style/AppTheme.NoOverlay" />
</application>
</manifest>
@@ -1,75 +0,0 @@
package com.nanodata.armsx;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import java.util.ArrayList;
import java.util.List;
public class ARMSXModule extends ReactContextBaseJavaModule {
public static final String NAME = "ARMSXModule";
public ARMSXModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@NonNull
@Override
public String getName() {
return NAME;
}
@ReactMethod
public void loadEmu(@Nullable ReadableArray args, Promise promise) {
Activity host = getCurrentActivity();
if (host == null) {
promise.reject("no_activity", "Activity not available");
return;
}
forceLandscapeInternal(host);
Intent intent = new Intent(host, EmulatorActivity.class);
intent.putExtra(EmulatorActivity.EXTRA_NATIVE_ARGS, readableArrayToStrings(args));
host.startActivity(intent);
promise.resolve(true);
}
@ReactMethod
public void forceLandscape(Promise promise) {
Activity host = getCurrentActivity();
if (host == null) {
promise.reject("no_activity", "Activity not available");
return;
}
forceLandscapeInternal(host);
promise.resolve(true);
}
private void forceLandscapeInternal(@NonNull Activity host) {
host.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
}
private @Nullable String[] readableArrayToStrings(@Nullable ReadableArray array) {
if (array == null) {
return null;
}
List<String> values = new ArrayList<>();
for (int i = 0; i < array.size(); i++) {
if (!array.isNull(i)) {
values.add(array.getString(i));
}
}
return values.isEmpty() ? null : values.toArray(new String[0]);
}
}
@@ -1,28 +0,0 @@
package com.nanodata.armsx;
import androidx.annotation.NonNull;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ARMSXPackage implements ReactPackage {
@NonNull
@Override
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new ARMSXModule(reactContext));
return modules;
}
@NonNull
@Override
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
@@ -1,135 +0,0 @@
package com.nanodata.armsx;
import android.content.Intent;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactInstanceManagerBuilder;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactRootView;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;
import java.util.ArrayList;
import java.util.List;
public class OverlayActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
private ReactRootView reactRootView;
private ReactInstanceManager reactInstanceManager;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mountReactSurface();
}
private void mountReactSurface() {
if (reactRootView != null && reactInstanceManager != null) {
setContentView(reactRootView);
return;
}
try {
reactRootView = new ReactRootView(this);
ReactInstanceManagerBuilder builder = ReactInstanceManager.builder()
.setApplication(getApplication())
.setCurrentActivity(this)
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED);
List<ReactPackage> packages = new ArrayList<>();
packages.add(new MainReactPackage());
packages.add(new ARMSXPackage());
for (ReactPackage reactPackage : packages) {
builder.addPackage(reactPackage);
}
if (BuildConfig.DEBUG) {
builder.setJSMainModulePath("mobile/index");
} else {
builder.setBundleAssetName("index.android.bundle");
}
reactInstanceManager = builder.build();
reactRootView.startReactApplication(reactInstanceManager, "ARMSXOverlay", null);
setContentView(reactRootView);
} catch (Throwable throwable) {
TextView fallback = new TextView(this);
fallback.setGravity(Gravity.CENTER);
fallback.setText("React Native failed to load. Connect Metro and reload.");
setContentView(fallback);
}
}
@Override
protected void onResume() {
super.onResume();
if (reactInstanceManager != null) {
reactInstanceManager.onHostResume(this, this);
}
}
@Override
protected void onPause() {
super.onPause();
if (reactInstanceManager != null) {
reactInstanceManager.onHostPause(this);
}
}
@Override
protected void onStop() {
super.onStop();
if (!isChangingConfigurations()) {
teardownReact();
}
}
@Override
protected void onDestroy() {
teardownReact();
super.onDestroy();
}
private void teardownReact() {
if (reactRootView != null) {
reactRootView.unmountReactApplication();
reactRootView = null;
}
if (reactInstanceManager != null) {
reactInstanceManager.onHostDestroy(this);
reactInstanceManager.destroy();
reactInstanceManager = null;
}
}
@Override
public void invokeDefaultOnBackPressed() {
teardownReact();
finish();
}
@Override
public void onBackPressed() {
if (reactInstanceManager != null) {
reactInstanceManager.onBackPressed();
} else {
super.onBackPressed();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (reactInstanceManager != null) {
reactInstanceManager.onActivityResult(this, requestCode, resultCode, data);
}
}
}
-3
View File
@@ -14,8 +14,6 @@ plugins {
id 'com.android.library' version '8.5.2' apply false
}
apply plugin: 'com.facebook.react.rootproject'
ext {
minSdkVersion = 26
targetSdkVersion = 34
@@ -28,7 +26,6 @@ allprojects { project ->
repositories {
google()
mavenCentral()
maven { url "$rootDir/../node_modules/react-native/android" }
}
configurations.all { config ->
-1
View File
@@ -1 +0,0 @@
apply plugin: "com.facebook.react"
-8
View File
@@ -4,7 +4,6 @@ pluginManagement {
google()
mavenCentral()
}
includeBuild("../node_modules/@react-native/gradle-plugin")
}
dependencyResolutionManagement {
@@ -12,15 +11,8 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url("$rootDir/../node_modules/react-native/android") }
}
}
rootProject.name = "ARMSX"
include(":app")
def nativeModulesSettingsFile = file('../node_modules/@react-native-community/cli-platform-android/native_modules.gradle')
if (nativeModulesSettingsFile.isFile()) {
apply from: nativeModulesSettingsFile
applyNativeModulesSettingsGradle(settings)
}