-
Notifications
You must be signed in to change notification settings - Fork 26
Open
Description
App crashes with ClassNotFoundException: expo.modules.ExpoModulesPackageList when integrating Expo bare-minimum template with native Android app
Description
I've been trying for several days to create a simple integration demo between a native Android application and an Expo CLI app created with the bare-minimum template.
I've successfully created the AAR package and included it as a local dependency in my native application. The native app builds successfully, but crashes on startup with an error originating from ReactNativeHostManager initialization.
Error
2025-09-04 13:12:56.079 5655-5655 ExpoModulesPackage com.example.bkt_fe_native_coex_poc E Couldn't get expo package list. (Ask Gemini)
java.lang.ClassNotFoundException: expo.modules.ExpoModulesPackageList
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:597)
at java.lang.Class.forName(Class.java:502)
at expo.modules.ExpoModulesPackage.packageList_delegate$lambda$1(ExpoModulesPackage.kt:23)
at expo.modules.ExpoModulesPackage.$r8$lambda$QFBV9-FY5jLEWS4oBZ76Yb8QIkI(Unknown Source:0)
at expo.modules.ExpoModulesPackage$$ExternalSyntheticLambda0.invoke(D8$$SyntheticClass:0)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at expo.modules.ExpoModulesPackage$Companion.getPackageList(ExpoModulesPackage.kt:21)
at expo.modules.ApplicationLifecycleDispatcher.getCachedListeners(ApplicationLifecycleDispatcher.kt:13)
at expo.modules.ApplicationLifecycleDispatcher.onApplicationCreate(ApplicationLifecycleDispatcher.kt:20)
at com.bmb.demorn.ReactNativeHostManager.initialize(ReactNativeHostManager.kt:154)
at com.example.bkt_fe_native_coex_poc.MainActivity.onCreate(MainActivity.kt:21)
Code
Native MainActivity
import com.bmb.demorn.ReactNativeHostManager
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//ReactNativeHostManager.initialize(this.application)
ReactNativeHostManager.shared.initialize(this.application)
// improved conf Edge-to-Edge
enableEdgeToEdge()
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent {
BktfenativecoexpocTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
BaseScreenLayout(
title = "Demo",
) {
HomeScreen()
}
}
}
}
}
}
ReactNativeHostManager
class ReactNativeHostManager {
companion object {
val shared: ReactNativeHostManager by lazy { ReactNativeHostManager() }
private var reactNativeHost: ReactNativeHost? = null
private var reactHost: ReactHost? = null
}
fun getReactNativeHost(): ReactNativeHost? {
return reactNativeHost
}
fun getReactHost(): ReactHost? {
return reactHost
}
fun initialize(application: Application) {
if (reactNativeHost != null && reactHost != null) {
return
}
SoLoader.init(application, OpenSourceMergedSoMapping)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
load()
}
ApplicationLifecycleDispatcher.onApplicationCreate(application)
val jsMainModuleName = ".expo/.virtual-metro-entry"
val reactApp = object : ReactApplication {
override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper(application,
object : DefaultReactNativeHost(application) {
override fun getPackages(): MutableList<ReactPackage> {
return PackageList(application).packages
}
override fun getJSMainModuleName(): String = jsMainModuleName
override fun getBundleAssetName(): String = "index.android.bundle"
override fun getUseDeveloperSupport() = BuildConfig.DEBUG
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
})
override val reactHost: ReactHost
get() = getDefaultReactHost(application, reactNativeHost)
}
reactNativeHost = reactApp.reactNativeHost
reactHost = reactApp.reactHost
}
}
Library build.gradle.kts
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import org.gradle.jvm.toolchain.JavaLanguageVersion
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
id("com.facebook.react")
id("com.callstack.react.brownfield")
`maven-publish`
}
reactBrownfield {
/**
* This will be available from `com.callstack.react.brownfield` version > 3.0.0
* It takes care of linking expo dependencies like expo-image with your AAR module.
*/
isExpo = true
}
react {
autolinkLibrariesWithApp()
}
android {
namespace = "com.bmb.demorn"
compileSdk = 35
defaultConfig {
minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
buildConfigField("boolean", "IS_NEW_ARCHITECTURE_ENABLED", properties["newArchEnabled"].toString())
buildConfigField("boolean", "IS_HERMES_ENABLED", properties["hermesEnabled"].toString())
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
}
dependencies {
api("com.facebook.react:react-android:0.79.6")
api("com.facebook.react:hermes-android:0.79.6")
implementation("androidx.core:core-ktx:1.17.0")
implementation("androidx.appcompat:appcompat:1.7.1")
implementation("com.google.android.material:material:1.12.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.3.0")
androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0")
}
// ... rest of the build configuration
Build Script
set -e
trap 'echo "Build interrupted"; exit 1' INT
pushd android
./gradlew clean
./gradlew demorn:bundleReleaseAar
./gradlew demorn:bundleDebugAar
echo -e "✅ AARs built successfully: \n android/react-brownfield/build/outputs/aar/react-brownfield-debug.arr \n android/react-brownfield/build/outputs/aar/react-brownfield-release.arr"
./gradlew publishToMavenLocal
echo "✅ AARs published to mavenLocal: com.callstack.react:react-brownfield"
Additional Information
- I followed the guide at https://www.rockjs.dev/docs/brownfield/android strictly and manually (npm create rock gives me errors when generating the AAR package)
- I had to add the following modifications to build.gradle.kts, otherwise the AAR package wouldn't be generated:
afterEvaluate {
tasks.named("releaseSourcesJar") {
dependsOn("copyAutolinkingSources")
dependsOn("generateCodegenArtifactsFromSchema")
}
// Handle debug sources jar if it exists
tasks.findByName("debugSourcesJar")?.let { task ->
task.dependsOn("copyAutolinkingSources")
task.dependsOn("generateCodegenArtifactsFromSchema")
}
}
Environment
- React Native: 0.79.6
- Expo CLI with bare-minimum template
- Android compileSdk: 36
- minSdk: 24
- Kotlin
- New Architecture: Enabled
The error seems to be related to missing expo.modules.ExpoModulesPackageList
class during initialization. Any guidance on how to resolve this would be greatly appreciated.
Metadata
Metadata
Assignees
Labels
No labels