question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

NativeModules empty object

See original GitHub issue

Update

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

  1. Create a new react native project using react-cli
  2. Follow the steps mention in https://facebook.github.io/react-native/docs/native-modules-android.html for the Toast module

or

  1. 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:open
  • Created 4 years ago
  • Reactions:13
  • Comments:36 (2 by maintainers)

github_iconTop GitHub Comments

10reactions
whalemarecommented, Aug 2, 2020

Still reproduced in "react-native": "0.63.2"

9reactions
emachtacommented, Jan 13, 2020

I had this problem and I fixed it by changing the MainApplication.java file with the segment

    @Override
    protected List<ReactPackage> getPackages() {
      @SuppressWarnings("UnnecessaryLocalVariable")
      List<ReactPackage> packages = new PackageList(this).getPackages();
      // Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new INSERTPACKAGENAMEHERE());
      return packages;
    }

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

           return Arrays.<ReactPackage>asList(
              new MainReactPackage(),
       );

Hope this helps.

Read more comments on GitHub >

github_iconTop Results From Across the Web

React Native NativeModules Empty Object - Stack Overflow
It's for a React Native app. No matter what I try, the module returns undefined. NativeModules always appears to be an empty object....
Read more >
getting empty object in react native NativeModules - Reddit
Hey, I'm learning about native modules and following documentation. But I'm getting empty object when I console `NativeModules` and null ...
Read more >
Importing NativeModules gives me an empty object even ...
[Solved]-Importing NativeModules gives me an empty object even though my native module is properly created and registered-React Native. Search. score:2.
Read more >
iOS custom native module - React Made Native Easy
TypeError: null is not an object(evaluating '_reactNative.NativeModules.Device.getDeviceName'). I am testing on iPhone 11 emulator. Plus, I also re-installed ...
Read more >
iOS Native Modules
When a native module method is invoked in JavaScript, React Native converts the arguments from JS objects to their Objective-C/Swift object ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found