Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[🐛 🔥] RN 0.70 database TypeError: undefined is not an object (evaluating '_SharedEventEmitter.default._subscriber.getSubscriptionsForType') [released for v15 and v14] #6534

Closed
5 of 10 tasks
efstathiosntonas opened this issue Sep 14, 2022 · 18 comments
Labels
plugin: database Firebase Realtime Database type: bug New bug report Workflow: Needs Review Pending feedback or review from a maintainer.

Comments

@efstathiosntonas
Copy link
Contributor

efstathiosntonas commented Sep 14, 2022

Issue

After upgrading react-native to 0.70.0 and react-native-firebase to 15.4.0 Database module throws TypeError: undefined is not an object (evaluating '_SharedEventEmitter.default._subscriber.getSubscriptionsForType') and the culprit is this line. It doesn't throw all the time though. It happens in both iOS (16) and Android 12.

@mikehardy if you need any additional info let me know.

Just some ref.on and ref.off (I think these are causing the isssue):

useEffect(() => {
    const callback = (snapshot: FirebaseDatabaseTypes.DataSnapshot) => {
      setValue(snapshot.exists() ? snapshot.val() : undefined);
      setLoading(false);
    };
    const ref = database().ref(path);
    ref.on("value", callback, (error: any) => {
      notify(error, "error", "Error while invoking useDatabaseField", ref);
      console.log(error.message);
      setLoading(false);
    });
    return () => {
      // @ts-ignore
      ref.off("value", callback);
      setValue(undefined);
      setLoading(true);
    };
  }, [path]);

Describe your issue here
Calling ref.off or ref.on throws the error above.

Project Files

Javascript

Click To Expand

package.json:

    "@react-native-firebase/analytics": "^15.4.0",
    "@react-native-firebase/app": "^15.4.0",
    "@react-native-firebase/auth": "^15.4.0",
    "@react-native-firebase/database": "^15.4.0",
    "@react-native-firebase/dynamic-links": "^15.4.0",
    "@react-native-firebase/firestore": "^15.4.0",
    "@react-native-firebase/functions": "^15.4.0",
    "@react-native-firebase/messaging": "^15.4.0",
    "@react-native-firebase/storage": "^15.4.0",

firebase.json for react-native-firebase v6:

# N/A

iOS

Click To Expand

ios/Podfile:

  • I'm not using Pods
  • I'm using Pods and my Podfile looks like:
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'

platform :ios, '12.4'
#install! 'cocoapods', :deterministic_uuids => false

# Convert all permission pods into static libraries
pre_install do |installer|
  Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
  installer.pod_targets.each do |pod|
    if pod.name.eql?('RNPermissions') || pod.name.start_with?('Permission-')
      def pod.build_type;
        # Uncomment the line corresponding to your CocoaPods version
         Pod::BuildType.static_library # >= 1.9
        # Pod::Target::BuildType.static_library # < 1.9
      end
    end
  end
end

target 'XXXXXX' do
  config = use_native_modules!
  #use_frameworks!
  use_frameworks! :linkage => :static
  # Flags change depending on the env values.
  flags = get_default_flags()

    use_react_native!(
      :path => config[:reactNativePath],
      # to enable hermes on iOS, change `false` to `true` and then install pods
      :hermes_enabled => true,
     :fabric_enabled => flags[:fabric_enabled],
     # :flipper_configuration => FlipperConfiguration.enabled,
     # An absolute path to your application root.
     :app_path => "#{Pod::Config.instance.installation_root}/.."
    )

  permissions_path = '../node_modules/react-native-permissions/ios'

  pod 'Permission-Camera', :path => "#{permissions_path}/Camera"
  pod 'Permission-Microphone', :path => "#{permissions_path}/Microphone"
  pod 'Permission-LocationWhenInUse', :path => "#{permissions_path}/LocationWhenInUse"

  # Required by latest firebase versions
  # See https://github.com/invertase/react-native-firebase/issues/6332#issuecomment-1189734581
  pod 'Firebase', :modular_headers => true
  pod 'FirebaseCore', :modular_headers => true
  pod 'FirebaseCoreInternal', :modular_headers => true
  pod 'FirebaseStorageInternal', :modular_headers => true
  pod 'FirebaseCoreExtension', :modular_headers => true
  pod 'FirebaseAppCheckInterop', :modular_headers => true
  pod 'FirebaseAuthInterop', :modular_headers => true
  pod 'FirebaseMessagingInterop', :modular_headers => true
  pod 'GTMSessionFetcher', :modular_headers => true
  pod 'FirebaseAppCheckInterop', :modular_headers => true
  pod 'FirebaseAuthInterop', :modular_headers => true
  pod 'GoogleUtilities', :modular_headers => true
  $RNFirebaseAsStaticFramework = true

  pod 'react-native-image-crop-tools', :path => '../node_modules/react-native-image-crop-tools'

  post_install do |installer|
    react_native_post_install(installer)

     # # to build for the simulator on Apple M1
    # installer.pods_project.targets.each do |target|
    #   target.build_configurations.each do |config|
    #     # disables arm64 builds for the simulator
    #     config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64'
    #   end
    # end

    #find_and_replace("Pods/RCT-Folly/folly/synchronization/DistributedMutex-inl.h",
    #"atomic_notify_one(state)", "folly::atomic_notify_one(state)")

    #find_and_replace("Pods/RCT-Folly/folly/synchronization/DistributedMutex-inl.h",
    #"atomic_wait_until(&state, previous | data, deadline)", "folly::atomic_wait_until(&state, previous | data, deadline)")

     installer.pods_project.build_configurations.each do |config|
        if config.name == 'Release'
          config.build_settings['SWIFT_COMPILATION_MODE'] = 'wholemodule'
          end
          end
  end
end

AppDelegate.m:

// N/A


Android

Click To Expand

Have you converted to AndroidX?

  • my application is an AndroidX application?
  • I am using android/gradle.settings jetifier=true for Android compatibility?
  • I am using the NPM package jetifier for react-native compatibility?

android/build.gradle:

buildscript {
    ext {
        buildToolsVersion = "31.0.0"
        minSdkVersion = 24
        compileSdkVersion = 31
        targetSdkVersion = 31
        supportLibVersion = "29.0.0"
        kotlinVersion = "1.6.10"
        ndkVersion = "21.4.7075529"
    }
//     ext {
//            set('react-native', [
//                        versions: [
//                          // Overriding Library SDK Versions
//                          firebase: [
//                            // Override Firebase SDK Version
//                            bom           : "30.3.0"
//                          ]
//                        ],
//                      ])
//        }
    repositories {
       google()
       mavenCentral()
       }
    dependencies {
        classpath("com.android.tools.build:gradle:7.2.1")
        classpath("com.facebook.react:react-native-gradle-plugin")
        classpath("de.undercouch:gradle-download-task:5.0.1")
        classpath 'com.google.gms:google-services:4.3.13'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
        classpath "com.bugsnag:bugsnag-android-gradle-plugin:7.+"
    }
}

allprojects {
     buildToolsVersion
     repositories {
         maven {
             // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
             url("$rootDir/../node_modules/react-native/android")
         }
         maven {
             // Android JSC is installed from npm
             url("$rootDir/../node_modules/jsc-android/dist")
         }
         mavenCentral {
             // We don't want to fetch react-native from Maven Central as there are
             // older versions over there.
             content {
                 excludeGroup "com.facebook.react"
             }
         }
         google()
         configurations.all {
             resolutionStrategy {
                 force "com.facebook.soloader:soloader:0.10.3"
             }
         }
         maven { url 'https://www.jitpack.io' }
         jcenter() {
                     content {
                         includeModule("com.yqritc", "android-scalablevideoview")
              }
         }
    }
}

android/app/build.gradle:

apply plugin: "com.android.application"
apply plugin: 'com.google.gms.google-services'

import com.android.build.OutputFile

def useIntlJsc = false

/**
 * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
 * and bundleReleaseJsAndAssets).
 * These basically call `react-native bundle` with the correct arguments during the Android build
 * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
 * bundle directly from the development server. Below you can see all the possible configurations
 * and their defaults. If you decide to add a configuration block, make sure to add it before the
 * `apply from: "../../node_modules/react-native/react.gradle"` line.
 *
 * project.ext.react = [
 *   // the name of the generated asset file containing your JS bundle
 *   bundleAssetName: "index.android.bundle",
 *
 *   // the entry file for bundle generation
 *   entryFile: "index.android.js",
 *
 *   // whether to bundle JS and assets in debug mode
 *   bundleInDebug: false,
 *
 *   // whether to bundle JS and assets in release mode
 *   bundleInRelease: true,
 *
 *   // whether to bundle JS and assets in another build variant (if configured).
 *   // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
 *   // The configuration property can be in the following formats
 *   //         'bundleIn${productFlavor}${buildType}'
 *   //         'bundleIn${buildType}'
 *   // bundleInFreeDebug: true,
 *   // bundleInPaidRelease: true,
 *   // bundleInBeta: true,
 *
 *   // whether to disable dev mode in custom build variants (by default only disabled in release)
 *   // for example: to disable dev mode in the staging build type (if configured)
 *   devDisabledInStaging: true,
 *   // The configuration property can be in the following formats
 *   //         'devDisabledIn${productFlavor}${buildType}'
 *   //         'devDisabledIn${buildType}'
 *
 *   // the root of your project, i.e. where "package.json" lives
 *   root: "../../",
 *
 *   // where to put the JS bundle asset in debug mode
 *   jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
 *
 *   // where to put the JS bundle asset in release mode
 *   jsBundleDirRelease: "$buildDir/intermediates/assets/release",
 *
 *   // where to put drawable resources / React Native assets, e.g. the ones you use via
 *   // require('./image.png')), in debug mode
 *   resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
 *
 *   // where to put drawable resources / React Native assets, e.g. the ones you use via
 *   // require('./image.png')), in release mode
 *   resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
 *
 *   // by default the gradle tasks are skipped if none of the JS files or assets change; this means
 *   // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
 *   // date; if you have any other folders that you want to ignore for performance reasons (gradle
 *   // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
 *   // for example, you might want to remove it from here.
 *   inputExcludes: ["android/**", "ios/**"],
 *
 *   // override which node gets called and with what additional arguments
 *   nodeExecutableAndArgs: ["node"],
 *
 *   // supply additional arguments to the packager
 *   extraPackagerArgs: []
 * ]
 */

project.ext.react = [
        enableHermes: true,
        bundleInDebug: true
]

apply from: "../../node_modules/react-native/react.gradle"


/**
 * Set this to drawtrue to create two separate APKs instead of one:
 *   - An APK that only works on ARM devices
 *   - An APK that only works on x86 devices
 * The advantage is the size of the APK is reduced by about 4MB.
 * Upload all the APKs to the Play Store and people will download
 * the correct one based on the CPU architecture of their device.
 */
def enableSeparateBuildPerCPUArchitecture = false

/**
 * Run Proguard to shrink the Java bytecode in release builds.
 */
def enableProguardInReleaseBuilds = false

/**
 * The preferred build flavor of JavaScriptCore.
 *
 * For example, to use the international variant, you can use:
 * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
 *
 * The international variant includes ICU i18n library and necessary data
 * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
 * give correct results when using with locales other than en-US.  Note that
 * this variant is about 6MiB larger per architecture than default.
 */
def jscFlavor = 'org.webkit:android-jsc:+'
/**
 * Whether to enable the Hermes VM.
 *
 * This should be set on project.ext.react and mirrored here.  If it is not set
 * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
 * and the benefits of using Hermes will therefore be sharply reduced.
 */
def enableHermes = project.ext.react.get("enableHermes", true)

/**
 * Architectures to build native code for.
 */
def reactNativeArchitectures() {
    def value = project.getProperties().get("reactNativeArchitectures")
    return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
}

def safeExtGet(prop, fallback) {
    rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}

def FACEBOOK_SDK_VERSION = safeExtGet('facebookSdkVersion', '13+')

android {
    ndkVersion rootProject.ext.ndkVersion
    compileSdkVersion rootProject.ext.compileSdkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }

    signingConfigs {
        signing {
            keyAlias 'key'
            keyPassword 'Aa123456'
            storeFile file('../keystores/release.keystore')
            storePassword 'Aa123456'
        }
    }
    packagingOptions {
        pickFirst '**/armeabi-v7a/libc++_shared.so'
        pickFirst '**/x86/libc++_shared.so'
        pickFirst '**/arm64-v8a/libc++_shared.so'
        pickFirst '**/x86_64/libc++_shared.so'
        pickFirst '**/x86/libjsc.so'
        pickFirst '**/armeabi-v7a/libjsc.so'
    }

    defaultConfig {
        applicationId "com.XXXXX"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 2590
        versionName "1.9.7"
        multiDexEnabled true
        ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
        missingDimensionStrategy 'react-native-camera', 'general'
        buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()

        if (isNewArchitectureEnabled()) {
                    // We configure the CMake build only if you decide to opt-in for the New Architecture.
                    externalNativeBuild {
                        cmake {
                            arguments "-DPROJECT_BUILD_DIR=$buildDir",
                                "-DREACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
                                "-DREACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
                                "-DNODE_MODULES_DIR=$rootDir/../node_modules",
                                "-DANDROID_STL=c++_shared"
                        }
                    }
                    if (!enableSeparateBuildPerCPUArchitecture) {
                        ndk {
                            abiFilters (*reactNativeArchitectures())
                        }
                    }
                }
    }

 if (isNewArchitectureEnabled()) {
        // We configure the NDK build only if you decide to opt-in for the New Architecture.
        externalNativeBuild {
            cmake {
                path "$projectDir/src/main/jni/CMakeLists.txt"
            }
        }
        def reactAndroidProjectDir = project(':ReactAndroid').projectDir
        def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
            dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
            from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
            into("$buildDir/react-ndk/exported")
        }
        def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
            dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
            from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
            into("$buildDir/react-ndk/exported")
        }
        afterEvaluate {
            // If you wish to add a custom TurboModule or component locally,
            // you should uncomment this line.
            // preBuild.dependsOn("generateCodegenArtifactsFromSchema")
            preDebugBuild.dependsOn(packageReactNdkDebugLibs)
            preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)

            // Due to a bug inside AGP, we have to explicitly set a dependency
            // between configureCMakeDebug* tasks and the preBuild tasks.
            // This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
            configureCMakeRelWithDebInfo.dependsOn(preReleaseBuild)
            configureCMakeDebug.dependsOn(preDebugBuild)
            reactNativeArchitectures().each { architecture ->
                tasks.findByName("configureCMakeDebug[${architecture}]")?.configure {
                    dependsOn("preDebugBuild")
                }
                tasks.findByName("configureCMakeRelWithDebInfo[${architecture}]")?.configure {
                    dependsOn("preReleaseBuild")
                }
            }
        }
    }

    splits {
        abi {
            reset()
            enable enableSeparateBuildPerCPUArchitecture
            universalApk false  // If true, also generate a universal APK
            include (*reactNativeArchitectures())
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            signingConfig signingConfigs.signing
        }
        debug {
            signingConfig signingConfigs.signing
        }
    }
    // applicationVariants are e.g. debug, release
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            // For each separate APK per architecture, set a unique version code as described here:
            // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
            def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
            def abi = output.getFilter(OutputFile.ABI)
            if (abi != null) {  // null for the universal-debug, universal-release variants
                output.versionCodeOverride =
                        defaultConfig.versionCode * 1048576 + versionCodes.get(abi)
            }
        }
    }
    subprojects {
        project.configurations.all {
            afterEvaluate {project ->
                if (project.hasProperty("android")) {
                    android {
                        compileSdkVersion rootProject.ext.compileSdkVersion
                        buildToolsVersion rootProject.ext.buildToolsVersion
                    }
                }
            }
            resolutionStrategy.eachDependency { details ->
                if (details.requested.group == 'com.android.support'
                        && !details.requested.name.contains('multidex') ) {
                    details.useVersion rootProject.ext.buildToolsVersion
                }
            }
        }
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    //noinspection GradleDynamicVersion
    implementation "com.facebook.react:react-native:+"  // From node_modules
    implementation "com.facebook.android:facebook-android-sdk:${FACEBOOK_SDK_VERSION}"
    implementation "androidx.core:core-splashscreen:1.0.0"
    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
    implementation 'androidx.appcompat:appcompat:1.4.2'
    implementation 'com.facebook.fresco:webpsupport:2.6.0'
    // Optionally, to display animated WebP images, you have to add:
    implementation 'com.facebook.fresco:animated-webp:2.6.0'
    //noinspection GradleDynamicVersion
    implementation 'com.facebook.soloader:soloader:0.10.3+'
    implementation 'me.leolin:ShortcutBadger:1.1.21@aar'
    implementation 'com.facebook.fresco:animated-gif:2.6.0'
    implementation 'androidx.multidex:multidex:2.0.1'

    debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
        exclude group:'com.facebook.fbjni'
    }

    debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
        exclude group:'com.facebook.flipper'
        exclude group:'com.squareup.okhttp3', module:'okhttp'
    }

    debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
        exclude group:'com.facebook.flipper'
    }

    if (enableHermes) {
            //noinspection GradleDynamicVersion
            implementation("com.facebook.react:hermes-engine:+") { // From node_modules
                exclude group:'com.facebook.fbjni'
            }
        } else {
            implementation jscFlavor
        }
}

if (isNewArchitectureEnabled()) {
    // If new architecture is enabled, we let you build RN from source
    // Otherwise we fallback to a prebuilt .aar bundled in the NPM package.
    // This will be applied to all the imported transtitive dependency.
    configurations.all {
        resolutionStrategy.dependencySubstitution {
            substitute(module("com.facebook.react:react-native"))
                    .using(project(":ReactAndroid"))
                    .because("On New Architecture we're building React Native from source")
            substitute(module("com.facebook.react:hermes-engine"))
                    .using(project(":ReactAndroid:hermes-engine"))
                    .because("On New Architecture we're building Hermes from source")
        }
    }
}

// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
    from configurations.implementation
    into 'libs'
}

project.ext.vectoricons = [
     iconFontNames: [
        'MaterialIcons.ttf',
        'Feather.ttf',
        'Entypo.ttf',
        'AntDesign.ttf',
        'MaterialCommunityIcons.ttf',
        'Ionicons.ttf',
        'FontAwesome5_Solid.ttf',
        'FontAwesome5_Regular.ttf',
        'FontAwesome.ttf',
        'Zocial.ttf'
     ]
]

apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
apply plugin: "com.bugsnag.android.gradle"
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
bugsnag {
    uploadReactNativeMappings = true // enables upload of React Native source maps,
    retryCount = 5
    overwrite = true
}

def isNewArchitectureEnabled() {
    // To opt-in for the New Architecture, you can either:
    // - Set `newArchEnabled` to true inside the `gradle.properties` file
    // - Invoke gradle with `-newArchEnabled=true`
    // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
    return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
}

android/settings.gradle:

rootProject.name = 'XXXXX'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')


includeBuild('../node_modules/react-native-gradle-plugin')
if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
    include(":ReactAndroid")
    project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
    include(":ReactAndroid:hermes-engine")
    project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine')
}

MainApplication.java:

package com.XXXXXX;

import android.app.Application;
import android.content.Context;
import com.bugsnag.android.Bugsnag;
import com.facebook.react.PackageList;
import androidx.multidex.MultiDex;
import com.facebook.CallbackManager;
import com.facebook.appevents.AppEventsLogger;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactApplication;
import com.th3rdwave.safeareacontext.SafeAreaContextPackage;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.config.ReactFeatureFlags;
import com.XXXXXX.newarchitecture.MainApplicationReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import com.microsoft.codepush.react.CodePush;

import java.util.Arrays;
import java.util.List;
import java.lang.reflect.InvocationTargetException;

public class MainApplication extends Application implements ReactApplication {

    private static CallbackManager mCallbackManager = CallbackManager.Factory.create();

    protected static CallbackManager getCallbackManager() {
        return mCallbackManager;
    }

    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {

        @Override
        protected String getJSBundleFile() {
            return CodePush.getJSBundleFile();
        }

        @Override
        public boolean getUseDeveloperSupport() {
            return BuildConfig.DEBUG;
        }


        @Override
        protected List<ReactPackage> getPackages() {
            @SuppressWarnings("UnnecessaryLocalVariable")
            List<ReactPackage> packages = new PackageList(this).getPackages();
            packages.addAll(Arrays.<ReactPackage>asList(
             new SafeAreaContextPackage()
            ));
            return packages;
        }

        @Override
        protected String getJSMainModuleName() {
            return "index";
        }
    };

      private final ReactNativeHost mNewArchitectureNativeHost =
          new MainApplicationReactNativeHost(this);


    @Override
    public ReactNativeHost getReactNativeHost() {
      if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
         return mNewArchitectureNativeHost;
       } else {
         return mReactNativeHost;
       }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        // If you opted-in for the New Architecture, we enable the TurboModule system
        ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
        SoLoader.init(this, /* native exopackage */ false);
        AppEventsLogger.activateApp(this);
        initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
        Bugsnag.start(this);
    }

    /**
     * Loads Flipper in React Native templates.
     *
     * @param context
     */
    private static void initializeFlipper(
            Context context, ReactInstanceManager reactInstanceManager) {
        if (BuildConfig.DEBUG) {
            try {
          /*
           We use reflection here to pick up the class that initializes Flipper,
          since Flipper library is not available in release mode
          */
                Class<?> aClass = Class.forName("com.XXXXXXX.ReactNativeFlipper");
                aClass
                .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
                .invoke(null, context, reactInstanceManager);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }
}

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          package="com.XXXXXX">

    <queries>
        <provider android:authorities="com.facebook.katana.provider.PlatformProvider" /> <!-- allows app to access Facebook app features -->
        <provider android:authorities="com.facebook.orca.provider.PlatformProvider" /> <!-- allows sharing to Messenger app -->
    </queries>

    <queries>
        <intent>
            <action android:name="android.media.action.IMAGE_CAPTURE" />
        </intent>
        <intent>
            <action android:name="android.intent.action.GET_CONTENT" />
            <data android:mimeType="image/*" />
        </intent>
        <intent>
            <action android:name="android.intent.action.PICK" />
            <data android:mimeType="image/*" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="http" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="https" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="mailto" />
        </intent>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="tel:" />
        </intent>
        <intent>
            <action android:name="android.intent.action.CHOOSER" />
        </intent>
    </queries>

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>
    <uses-permission android:name="android.permission.VIBRATE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

    <application
            android:name=".MainApplication"
            android:allowBackup="false"
            android:fullBackupContent="false"
            android:requestLegacyExternalStorage="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:theme="@style/BootTheme"
            tools:ignore="GoogleAppIndexingWarning|LockedOrientationActivity">
        <meta-data android:name="com.bugsnag.android.API_KEY"
                   android:value="xxxx"/>
        <meta-data android:name="com.bugsnag.android.ENABLED_RELEASE_STAGES"
                   android:value="production"/>
        <meta-data     android:name="com.google.firebase.messaging.default_notification_icon"
                       android:resource="@drawable/ic_notification" />
        <activity
                android:name=".MainActivity"
            android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
                android:launchMode="singleTask"
                android:label="@string/app_name"
                android:screenOrientation="nosensor"
            android:windowSoftInputMode="adjustResize"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <meta-data
                android:name="com.facebook.sdk.ApplicationId"
                android:value="@string/facebook_app_id" />
        <meta-data android:name="com.facebook.sdk.AutoLogAppEventsEnabled"
                   android:value="false"/>
        <meta-data android:name="com.facebook.sdk.ClientToken" android:value="@string/facebook_client_token"/>
        <activity
                android:name="com.facebook.FacebookActivity"
                android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
                android:label="@string/app_name" />
        <activity
                android:name="com.facebook.CustomTabActivity"
                android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="@string/fb_login_protocol_scheme" />
            </intent-filter>
        </activity>
    </application>
</manifest>


Environment

Click To Expand

react-native info output:

 OUTPUT GOES HERE
  • Platform that you're experiencing the issue on:
    • iOS
    • Android
    • iOS but have not tested behavior on Android
    • Android but have not tested behavior on iOS
    • Both
  • react-native-firebase version you're using that has this issue:
    • 15.4.0
  • Firebase module(s) you're using that has the issue:
    • Database
  • Are you using TypeScript?
    • Y & 4.8.3


Click To Expand and see Android 12 screenshot

Screenshot_20220914_090755

@efstathiosntonas efstathiosntonas added help: needs-triage Issue needs additional investigation/triaging. type: bug New bug report labels Sep 14, 2022
@efstathiosntonas
Copy link
Contributor Author

efstathiosntonas commented Sep 14, 2022

@mikehardy maybe because Meta re-writed EventEmitter.js in this commit?

edit: Yeah, this might be the reason, this is the commit prior the above one where _subscriber exists

@mikehardy
Copy link
Collaborator

Oh no, last time they did that (across the 64/65 boundary if I recall) it was pretty messy for us internally. I'll have to look into it unless you beat me to it. Thanks for posting up the commit hash, that helps

@efstathiosntonas
Copy link
Contributor Author

@mikehardy it seems it's really complex and I don't have full picture of react-native-firebase internals so I won't touch it.

@mikehardy mikehardy added Type: React Native Workflow: Needs Review Pending feedback or review from a maintainer. labels Sep 14, 2022
@mikehardy
Copy link
Collaborator

mikehardy commented Sep 14, 2022

To be honest - and this is shared mostly for developer commiseration / humor - I thought I had a full picture of react-native-firebase internals until the last time they rewrote EventEmitter. I did not 😆 - after repairing the damage I think I did though.

262452d

Investigating a solution now, it may be that we need to do the listener accounting ourselves / internally instead of previous style where we deferred to upstream superclass / react-native internals

@efstathiosntonas
Copy link
Contributor Author

@mikehardy good luck this time 😆😆😆😆😆

@mikehardy
Copy link
Collaborator

mikehardy commented Sep 14, 2022

With apologies I don't have time to test this but you have actually committed to this repo so I am going to boldly assume you are willing to roll up your sleeves and dive in a bit? Hopefully correct 💪

This is the important line for new code: facebook/react-native@e5c5dcd?diff=split#diff-0a3d564bafb3892ce96f82c6fe19b293cd3e15fe1f14d2577c03326cf9bc5cf8R127

That's a demonstration of how you can introspect on the new-style registry of listeners, though they are only exposing a listener count, while we need to get the actual listeners.

So my thinking for a repair is:

  • check if ._registry exists on our emitter
    • if it does, we are react-native 0.70+, use "new logic" (to be defined)
    • if it does not, use our old battle-tested abuse of react-native internals

Okay, what's the new logic? Do what listenerCount does, but instead of just returning size or zero and discarding the set, make a new array from the set and return that

That results in something like this as the new function:

  removeListenerRegistrations(listener, registrations) {
    if (!Array.isArray(registrations)) {
      return [];
    }
    const removed = [];

    for (let i = 0, len = registrations.length; i < len; i++) {
      const registration = registrations[i];
      let subscriptions;

      // EventEmitter in react-native < 0.70 had a `_subscriber` property with a method for subscriptions by type...
      if (SharedEventEmitter._subscriber) {
        subscriptions = SharedEventEmitter._subscriber.getSubscriptionsForType(registration);
      } else {
        // ...react-native 0.70 now stores subscribers as a map of Sets by type in `_registry`
        const registrySubscriptionsSet = SharedEventEmitter._registry[registration];
        if (registrySubscriptionsSet) {
          subscriptions = Array.from(registrySubscriptionsSet;
        }
      }

      if (subscriptions) {
        for (let j = 0, l = subscriptions.length; j < l; j++) {
          const subscription = subscriptions[j];
          // The subscription may have been removed during this event loop.
          // its listener matches the listener in method parameters
          if (subscription && subscription.listener === listener) {
            subscription.remove();
            removed.push(registration);
            this.removeRegistration(registration);
          }
        }
      }
    }

    return removed;
  }

If you patch that in (use patch-package of course...) I think it will work, and if so, that's the PR...

@efstathiosntonas
Copy link
Contributor Author

efstathiosntonas commented Sep 14, 2022

sure man, will patch it now and come back, it's gonna take a while since I rolled back to 0.68

@mikehardy
Copy link
Collaborator

On the plus side - patching it prior to moving forward is actually really good to know! It has to work on 0.68 as well - the idea is it is backwards and forwards compatible

@efstathiosntonas
Copy link
Contributor Author

@mikehardy error went away. Thanks man.

Here's the patch for anyone else that encountered this:
@react-native-firebase+database+15.4.0.patch

diff --git a/node_modules/@react-native-firebase/database/lib/DatabaseSyncTree.js b/node_modules/@react-native-firebase/database/lib/DatabaseSyncTree.js
index 29c3057..59d4653 100644
--- a/node_modules/@react-native-firebase/database/lib/DatabaseSyncTree.js
+++ b/node_modules/@react-native-firebase/database/lib/DatabaseSyncTree.js
@@ -161,7 +161,18 @@ class DatabaseSyncTree {
 
     for (let i = 0, len = registrations.length; i < len; i++) {
       const registration = registrations[i];
-      const subscriptions = SharedEventEmitter._subscriber.getSubscriptionsForType(registration);
+      let subscriptions;
+
+      // EventEmitter in react-native < 0.70 had a `_subscriber` property with a method for subscriptions by type...
+      if (SharedEventEmitter._subscriber) {
+        subscriptions = SharedEventEmitter._subscriber.getSubscriptionsForType(registration);
+      } else {
+        // ...react-native 0.70 now stores subscribers as a map of Sets by type in `_registry`
+        const registrySubscriptionsSet = SharedEventEmitter._registry[registration];
+        if (registrySubscriptionsSet) {
+          subscriptions = Array.from(registrySubscriptionsSet);
+        }
+      }
 
       if (subscriptions) {
         for (let j = 0, l = subscriptions.length; j < l; j++) {

@efstathiosntonas
Copy link
Contributor Author

@mikehardy will roll back and test on 0.68

@efstathiosntonas
Copy link
Contributor Author

efstathiosntonas commented Sep 14, 2022

@mikehardy patch works fine on @react-native-firebase/database: "14.11.1" and react native 0.68.3, let me know if you want to test against 15.4.0 (I don't think we need to though)

@mikehardy
Copy link
Collaborator

I really appreciate all the testing - that has been a huge help - I agree 15.4.0 should work unchanged, there were no changes in that file in the releases between 14.11.1 and 15.4.0.

I'll form up a PR as soon as I get a chance but it might be a day or so, I've got an unrelated deadline I'm working towards which is why I couldn't test it in the first place 😅

@mikehardy mikehardy added Resolution: Solution Provided plugin: database Firebase Realtime Database and removed help: needs-triage Issue needs additional investigation/triaging. labels Sep 14, 2022
@mikehardy mikehardy changed the title [🐛 🔥] RN 0.70 TypeError: undefined is not an object (evaluating '_SharedEventEmitter.default._subscriber.getSubscriptionsForType') [🐛 🔥] RN 0.70 database TypeError: undefined is not an object (evaluating '_SharedEventEmitter.default._subscriber.getSubscriptionsForType') [patch included! just needs PR+release) Sep 14, 2022
@efstathiosntonas
Copy link
Contributor Author

@mikehardy no worries, I might make a PR a little bit later.

@mikehardy
Copy link
Collaborator

Just kicked off the release process for this one - v15.5.0 should be out in a moment with your PR included, thanks again

@mikehardy mikehardy changed the title [🐛 🔥] RN 0.70 database TypeError: undefined is not an object (evaluating '_SharedEventEmitter.default._subscriber.getSubscriptionsForType') [patch included! just needs PR+release) [🐛 🔥] RN 0.70 database TypeError: undefined is not an object (evaluating '_SharedEventEmitter.default._subscriber.getSubscriptionsForType') [released for v15 and v14] Sep 17, 2022
@mikehardy
Copy link
Collaborator

For anyone that sees this, I've included it in a "courtesy release" of the v14 version series, as I know there are a lot of people still working through problems with the new use_frameworks requirement on v15.

If you pull the semver major v14 series or npm dist tag version-14 you'll see a new v14.11.2 release that has this fix.

@efstathiosntonas
Copy link
Contributor Author

Thanks @mikehardy!

@efstathiosntonas
Copy link
Contributor Author

@muzzamil76 it’s really bad to mix different versions, you’re using 14.11.1 and the patch was included in 14.11.2, check this comment

@mikehardy
Copy link
Collaborator

As for version mixing - here's our policy (TL;DR: do not mix them) - https://invertase.io/blog/react-native-firebase-versioning

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plugin: database Firebase Realtime Database type: bug New bug report Workflow: Needs Review Pending feedback or review from a maintainer.
Projects
None yet
Development

No branches or pull requests

2 participants