-
Notifications
You must be signed in to change notification settings - Fork 11
Description
I tried adding this library to my app using expo sdk 51 (react-native 0.75.5). I got iOS working pretty quickly but i'm struggling with the android integration. I am not using the new architecture.
After a lot of trial and error, i think i figured out that the instructions for integrating the library and .aar
files are for an older version of gradle. The newest versions of react-native and expo are currently using gradle 8.8. So I asked ChatGPT to help me figure out the implementation and i was able to cobble together an expo plugin that would compile the app properly, however after metro would bundle the app, i'd get a runtime error and a react-native red screen:
java.lang.NoClassDefFoundError: Failed resolution of: Lno/fuse/rnunity/RNUnityManager;
Full Stacktrace:
ERROR Your app just crashed. See the error below.
java.lang.NoClassDefFoundError: Failed resolution of: Lno/fuse/rnunity/RNUnityManager;
no.fuse.rnunity.RNUnityPackage.createViewManagers(RNUnityPackage.java:22)
com.facebook.react.ReactInstanceManager.getOrCreateViewManagers(ReactInstanceManager.java:933)
com.swmansion.reanimated.ReanimatedPackage.createUIManager(ReanimatedPackage.java:78)
com.swmansion.reanimated.ReanimatedPackage.getModule(ReanimatedPackage.java:38)
com.facebook.react.BaseReactPackage$ModuleHolderProvider.get(BaseReactPackage.java:156)
com.facebook.react.BaseReactPackage$ModuleHolderProvider.get(BaseReactPackage.java:144)
com.facebook.react.bridge.ModuleHolder.create(ModuleHolder.java:186)
com.facebook.react.bridge.ModuleHolder.getModule(ModuleHolder.java:151)
com.facebook.react.bridge.NativeModuleRegistry.getModule(NativeModuleRegistry.java:148)
com.facebook.react.bridge.CatalystInstanceImpl.getNativeModule(CatalystInstanceImpl.java:469)
com.facebook.react.bridge.CatalystInstanceImpl.getNativeModule(CatalystInstanceImpl.java:445)
com.facebook.react.uimanager.UIManagerHelper.getUIManager(UIManagerHelper.java:88)
com.facebook.react.uimanager.UIManagerHelper.getUIManager(UIManagerHelper.java:46)
com.facebook.react.ReactInstanceManager.attachRootViewToInstance(ReactInstanceManager.java:1231)
com.facebook.react.ReactInstanceManager.setupReactContext(ReactInstanceManager.java:1180)
com.facebook.react.ReactInstanceManager.lambda$runCreateReactContextOnNewThread$1(ReactInstanceManager.java:1143)
com.facebook.react.ReactInstanceManager.$r8$lambda$FD-H2RG7CdgXPtYJUBikxLbd8MA(Unknown Source:0)
com.facebook.react.ReactInstanceManager$$ExternalSyntheticLambda4.run(Unknown Source:4)
android.os.Handler.handleCallback(Handler.java:959)
android.os.Handler.dispatchMessage(Handler.java:100)
com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
android.os.Looper.loopOnce(Looper.java:232)
android.os.Looper.loop(Looper.java:317)
com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:233)
java.lang.Thread.run(Thread.java:1012)
Caused by java.lang.ClassNotFoundException: no.fuse.rnunity.RNUnityManager
java.lang.VMClassLoader.findLoadedClass(Native Method)
java.lang.ClassLoader.findLoadedClass(ClassLoader.java:738)
java.lang.ClassLoader.loadClass(ClassLoader.java:363)
java.lang.ClassLoader.loadClass(ClassLoader.java:312)
no.fuse.rnunity.RNUnityPackage.createViewManagers(RNUnityPackage.java:22)
com.facebook.react.ReactInstanceManager.getOrCreateViewManagers(ReactInstanceManager.java:933)
com.swmansion.reanimated.ReanimatedPackage.createUIManager(ReanimatedPackage.java:78)
com.swmansion.reanimated.ReanimatedPackage.getModule(ReanimatedPackage.java:38)
com.facebook.react.BaseReactPackage$ModuleHolderProvider.get(BaseReactPackage.java:156)
com.facebook.react.BaseReactPackage$ModuleHolderProvider.get(BaseReactPackage.java:144)
com.facebook.react.bridge.ModuleHolder.create(ModuleHolder.java:186)
com.facebook.react.bridge.ModuleHolder.getModule(ModuleHolder.java:151)
com.facebook.react.bridge.NativeModuleRegistry.getModule(NativeModuleRegistry.java:148)
com.facebook.react.bridge.CatalystInstanceImpl.getNativeModule(CatalystInstanceImpl.java:469)
com.facebook.react.bridge.CatalystInstanceImpl.getNativeModule(CatalystInstanceImpl.java:445)
com.facebook.react.uimanager.UIManagerHelper.getUIManager(UIManagerHelper.java:88)
com.facebook.react.uimanager.UIManagerHelper.getUIManager(UIManagerHelper.java:46)
com.facebook.react.ReactInstanceManager.attachRootViewToInstance(ReactInstanceManager.java:1231)
com.facebook.react.ReactInstanceManager.setupReactContext(ReactInstanceManager.java:1180)
com.facebook.react.ReactInstanceManager.lambda$runCreateReactContextOnNewThread$1(ReactInstanceManager.java:1143)
com.facebook.react.ReactInstanceManager.$r8$lambda$FD-H2RG7CdgXPtYJUBikxLbd8MA(Unknown Source:0)
com.facebook.react.ReactInstanceManager$$ExternalSyntheticLambda4.run(Unknown Source:4)
android.os.Handler.handleCallback(Handler.java:959)
android.os.Handler.dispatchMessage(Handler.java:100)
com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
android.os.Looper.loopOnce(Looper.java:232)
android.os.Looper.loop(Looper.java:317)
com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:233)
java.lang.Thread.run(Thread.java:1012)
Caused by java.lang.NoClassDefFoundError: Failed resolution of: Lcom/unity3d/player/IUnityPlayerLifecycleEvents;
no.fuse.rnunity.RNUnityPackage.createViewManagers(RNUnityPackage.java:22)
com.facebook.react.ReactInstanceManager.getOrCreateViewManagers(ReactInstanceManager.java:933)
com.swmansion.reanimated.ReanimatedPackage.createUIManager(ReanimatedPackage.java:78)
com.swmansion.reanimated.ReanimatedPackage.getModule(ReanimatedPackage.java:38)
com.facebook.react.BaseReactPackage$ModuleHolderProvider.get(BaseReactPackage.java:156)
com.facebook.react.BaseReactPackage$ModuleHolderProvider.get(BaseReactPackage.java:144)
com.facebook.react.bridge.ModuleHolder.create(ModuleHolder.java:186)
com.facebook.react.bridge.ModuleHolder.getModule(ModuleHolder.java:151)
com.facebook.react.bridge.NativeModuleRegistry.getModule(NativeModuleRegistry.java:148)
com.facebook.react.bridge.CatalystInstanceImpl.getNativeModule(CatalystInstanceImpl.java:469)
com.facebook.react.bridge.CatalystInstanceImpl.getNativeModule(CatalystInstanceImpl.java:445)
com.facebook.react.uimanager.UIManagerHelper.getUIManager(UIManagerHelper.java:88)
com.facebook.react.uimanager.UIManagerHelper.getUIManager(UIManagerHelper.java:46)
com.facebook.react.ReactInstanceManager.attachRootViewToInstance(ReactInstanceManager.java:1231)
com.facebook.react.ReactInstanceManager.setupReactContext(ReactInstanceManager.java:1180)
com.facebook.react.ReactInstanceManager.lambda$runCreateReactContextOnNewThread$1(ReactInstanceManager.java:1143)
com.facebook.react.ReactInstanceManager.$r8$lambda$FD-H2RG7CdgXPtYJUBikxLbd8MA(Unknown Source:0)
com.facebook.react.ReactInstanceManager$$ExternalSyntheticLambda4.run(Unknown Source:4)
android.os.Handler.handleCallback(Handler.java:959)
android.os.Handler.dispatchMessage(Handler.java:100)
com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
android.os.Looper.loopOnce(Looper.java:232)
android.os.Looper.loop(Looper.java:317)
com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:233)
java.lang.Thread.run(Thread.java:1012)
Caused by java.lang.ClassNotFoundException: Didn't find class "com.unity3d.player.IUnityPlayerLifecycleEvents" on path: DexPathList[[zip file "/data/app/~~85NQTwgEsIMWF74L2osF1Q==/com.myapp.dev-LW0a1EufLb7G6FArPLCz1g==/base.apk"],nativeLibraryDirectories=[/data/app/~~85NQTwgEsIMWF74L2osF1Q==/com.myapp.dev-LW0a1EufLb7G6FArPLCz1g==/lib/arm64, /data/app/~~85NQTwgEsIMWF74L2osF1Q==/com.myapp.dev-LW0a1EufLb7G6FArPLCz1g==/base.apk!/lib/arm64-v8a, /system/lib64, /system_ext/lib64]]
dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:259)
java.lang.ClassLoader.loadClass(ClassLoader.java:379)
java.lang.ClassLoader.loadClass(ClassLoader.java:312)
no.fuse.rnunity.RNUnityPackage.createViewManagers(RNUnityPackage.java:22)
com.facebook.react.ReactInstanceManager.getOrCreateViewManagers(ReactInstanceManager.java:933)
com.swmansion.reanimated.ReanimatedPackage.createUIManager(ReanimatedPackage.java:78)
com.swmansion.reanimated.ReanimatedPackage.getModule(ReanimatedPackage.java:38)
com.facebook.react.BaseReactPackage$ModuleHolderProvider.get(BaseReactPackage.java:156)
com.facebook.react.BaseReactPackage$ModuleHolderProvider.get(BaseReactPackage.java:144)
com.facebook.react.bridge.ModuleHolder.create(ModuleHolder.java:186)
com.facebook.react.bridge.ModuleHolder.getModule(ModuleHolder.java:151)
com.facebook.react.bridge.NativeModuleRegistry.getModule(NativeModuleRegistry.java:148)
com.facebook.react.bridge.CatalystInstanceImpl.getNativeModule(CatalystInstanceImpl.java:469)
com.facebook.react.bridge.CatalystInstanceImpl.getNativeModule(CatalystInstanceImpl.java:445)
com.facebook.react.uimanager.UIManagerHelper.getUIManager(UIManagerHelper.java:88)
com.facebook.react.uimanager.UIManagerHelper.getUIManager(UIManagerHelper.java:46)
com.facebook.react.ReactInstanceManager.attachRootViewToInstance(ReactInstanceManager.java:1231)
com.facebook.react.ReactInstanceManager.setupReactContext(ReactInstanceManager.java:1180)
com.facebook.react.ReactInstanceManager.lambda$runCreateReactContextOnNewThread$1(ReactInstanceManager.java:1143)
com.facebook.react.ReactInstanceManager.$r8$lambda$FD-H2RG7CdgXPtYJUBikxLbd8MA(Unknown Source:0)
com.facebook.react.ReactInstanceManager$$ExternalSyntheticLambda4.run(Unknown Source:4)
android.os.Handler.handleCallback(Handler.java:959)
android.os.Handler.dispatchMessage(Handler.java:100)
com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
android.os.Looper.loopOnce(Looper.java:232)
android.os.Looper.loop(Looper.java:317)
com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:233)
java.lang.Thread.run(Thread.java:1012)
Any clues or ideas on what might be happening here?
For reference, here is the expo config plugin i used to get the app working in react-native 0.74:
plugins/withUnityLibrary.ts
import { AndroidConfig } from "@expo/config-plugins";
import {
ConfigPlugin,
withAppBuildGradle,
withProjectBuildGradle,
withSettingsGradle,
withStringsXml,
withAndroidManifest,
withGradleProperties,
} from "expo/config-plugins";
const withCustomSettingsGradle: ConfigPlugin = (config) => {
return withSettingsGradle(config, (config) => {
if (!config.modResults.contents.includes("unityLibrary")) {
config.modResults.contents += `
include ':unityLibrary'
project(':unityLibrary').projectDir = new File('../unity/android')
`;
}
return config;
});
};
const withCustomAppBuildGradle: ConfigPlugin = (config) => {
return withAppBuildGradle(config, (config) => {
// Add flatDir repository for Unity .aar files
if (!config.modResults.contents.includes("../unity/android")) {
config.modResults.contents = config.modResults.contents.replace(
/repositories\s*{/,
`repositories {
flatDir {
dirs '../unity/android'
}`,
);
}
// Ensure the aar file is added to the existing dependencies block
if (!config.modResults.contents.includes("../unity/android")) {
config.modResults.contents = config.modResults.contents.replace(
/dependencies\s*{/,
`dependencies {
implementation fileTree(dir: '../unity/android', include: ['*.aar'])
`,
);
}
return config;
});
};
const withCustomProjectBuildGradle: ConfigPlugin = (config) => {
return withProjectBuildGradle(config, (config) => {
// Ensure we modify the existing allprojects block instead of creating a new one
config.modResults.contents = config.modResults.contents.replace(
/allprojects\s*{[^}]*repositories\s*{[^}]*}/,
(match) => {
if (!match.includes("flatDir")) {
return match.replace(
/repositories\s*{/,
`repositories {
flatDir {
dirs '../unity/android'
}`
);
}
return match; // No changes if flatDir is already present
}
);
return config;
});
};
const withCustomStringsXml: ConfigPlugin = (config) => {
return withStringsXml(config, (config) => {
config.modResults = AndroidConfig.Strings.setStringItem(
[
{
_: "Game view",
$: {
name: "game_view_content_description",
},
},
{
_: "unity_root",
$: {
name: "unity_root",
},
},
],
config.modResults
);
return config;
});
};
const withCustomAndroidManifest: ConfigPlugin = (config) => {
return withAndroidManifest(config, (config) => {
const app = AndroidConfig.Manifest.getMainApplicationOrThrow(config.modResults);
// Ensure android:extractNativeLibs is set to true in the <application> tag
app.$['android:extractNativeLibs'] = 'true';
// Find the MainActivity entry or add it if missing
let mainActivity = AndroidConfig.Manifest.getMainActivity(config.modResults);
if (!mainActivity) {
mainActivity = {
$: {
'android:name': '.MainActivity',
},
'intent-filter': [],
};
app['activity'] = app['activity'] || [];
app['activity'].push(mainActivity);
}
mainActivity.$['android:hardwareAccelerated'] = 'true';
return config;
});
};
const withCustomGradleProperties: ConfigPlugin = (config) => {
return withGradleProperties(config, (config) => {
const unityStreamingAssets = { key: 'unityStreamingAssets', value: '.unity3d' };
const existingProperty = config.modResults.find((item) => item.key === unityStreamingAssets.key);
if (!existingProperty) {
config.modResults.push(unityStreamingAssets);
}
return config;
});
};
// Main plugin function
export const withUnityLibrary: ConfigPlugin = (config) => {
config = withCustomSettingsGradle(config);
config = withCustomAppBuildGradle(config);
config = withCustomProjectBuildGradle(config);
config = withCustomStringsXml(config);
config = withCustomAndroidManifest(config);
config = withCustomGradleProperties(config);
return config;
};