NativeModules empty object
See original GitHub issueUpdate
A lot of people facing this problem do not go through all the comments and so I am mentioning my conclusion here. It is not a permanent solution and thus this issue cannot be closed yet, but this is A solution for people who want to continue developing their native modules while the react-native team figure out a solution.
Turns out, turning on debug mode once fixes the problem. Strange…
When we turn on debug mode, it uses Chrome’s V8 engine instead which works without a problem. If that’s the case, fiddling around with the js-core version will make it work in non-debug mode too.
Original
I tried to recreate the Native Modules for Android guide on React Native’s documentation, NativeModules was an empty object. I found a 3 years old Github repo explaining Native Modules on a rather old version of React (https://github.com/promptworks/ReactNativeBridgeExample) which works. I could not find anything wrong in my code. Either I am doing something very silly or there is a bug in the codebase.
React Native version:
react: 16.9.0 react-native: 0.61.2 react-native-cli: 2.0.1
Steps To Reproduce
- Create a new react native project using react-cli
- Follow the steps mention in https://facebook.github.io/react-native/docs/native-modules-android.html for the Toast module
or
- Add Kotlin support to your project and create files as described below (full Kotlin code provided)
Describe what you expected to happen: NativeModules to have the exported functions instead of being an empty object.
Snack, code example, screenshot, or link to a repository:
Here I provide code for a Kotlin project trying to count the number of clicks. Everything compiles correctly.
Note
I tried without Kotlin as well, exactly copying code from the official React docs but with the same results
Code
gradle.properties:
android.useAndroidX=true
android.enableJetifier=false
app/build.gradle:
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.facebook.react:react-native:+" // From node_modules
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.71"
if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
}
StateModule.kt:
package com.statemanagertest.state
import com.facebook.react.bridge.*
import kotlin.collections.HashMap
class StateModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
private val constants : HashMap<String, Any> = hashMapOf("clicks" to 0)
companion object {
lateinit var reactContext: ReactApplicationContext
}
init {
reactContext = context
}
override fun getName(): String {
return "StateExample"
}
override fun getConstants(): HashMap<String, Any> {
return constants
}
@ReactMethod
fun whenClicked(callback: Callback) {
val curValAny = constants["clicks"]
val curVal = if (curValAny is Int) curValAny else 0
constants["clicks"] = curVal + 1
callback.invoke()
}
}
StatePackage.kt:
package com.statemanagertest.state
import android.view.View
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.JavaScriptModule
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ReactShadowNode
import com.facebook.react.uimanager.ViewManager
class StatePackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): MutableList<NativeModule> {
return mutableListOf(StateModule(reactContext))
}
override fun createViewManagers(reactContext: ReactApplicationContext): MutableList<ViewManager<View, ReactShadowNode<*>>> {
return mutableListOf()
}
fun createJSModules(): List<Class<out JavaScriptModule>> {
return listOf()
}
}
MainApplication.kt:
package com.statemanagertest
import android.app.Application
import android.content.Context
import com.facebook.react.ReactApplication
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.soloader.SoLoader
import java.lang.reflect.InvocationTargetException
import com.facebook.react.shell.MainReactPackage
import com.statemanagertest.state.StatePackage
class MainApplication : Application(), ReactApplication {
private val mReactNativeHost = object : ReactNativeHost(this) {
override fun getUseDeveloperSupport(): Boolean {
return BuildConfig.DEBUG
}
override fun getPackages(): List<ReactPackage> {
return listOf(
MainReactPackage(),
StatePackage()
)
}
override fun getJSMainModuleName(): String {
return "index"
}
}
override fun getReactNativeHost(): ReactNativeHost {
return mReactNativeHost
}
override fun onCreate() {
super.onCreate()
SoLoader.init(this, /* native exopackage */ false)
initializeFlipper(this) // Remove this line if you don't want Flipper enabled
}
private fun initializeFlipper(context: Context) {
if (BuildConfig.DEBUG) {
try {
val aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper")
aClass.getMethod("initializeFlipper", Context::class.java).invoke(null, context)
} catch (e: ClassNotFoundException) {
e.printStackTrace()
} catch (e: NoSuchMethodException) {
e.printStackTrace()
} catch (e: IllegalAccessException) {
e.printStackTrace()
} catch (e: InvocationTargetException) {
e.printStackTrace()
}
}
}
}
App.js:
import React, { Component } from 'react';
import {
SafeAreaView,
StyleSheet,
Text,
Button,
NativeModules
} from 'react-native';
class App extends Component {
constructor() {
super();
console.log("vvk::NativeModules:", NativeModules)
}
render() {
return (
<>
<SafeAreaView style={styles.container}>
<Text style={styles.text}>Clicks: {0}</Text>
<Button title="Click" onPress={() => {console.log(NativeModules)}}/>
</SafeAreaView>
</>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: "stretch",
margin: 20,
},
text: {
textAlign: 'center',
padding: 20,
fontSize: 20
}
});
export default App;
Issue Analytics
- State:
- Created 4 years ago
- Reactions:13
- Comments:36 (2 by maintainers)
Top GitHub Comments
Still reproduced in
"react-native": "0.63.2"
I had this problem and I fixed it by changing the MainApplication.java file with the segment
If there is any packages that you need to add that require manual linking, the right way to do it is like this:
packages.add(new INSERTPACKAGENAMEHERE());
This above is what React Native 0.60 adds in. Because everything is now linked automatically, you don’t need to import modules like
new MainReactPackage()
This is what my file looked like before
Hope this helps.