invertase / react-native-firebase

🔥 A well-tested feature-rich modular Firebase implementation for React Native. Supports both iOS & Android platforms for all Firebase services.
https://rnfirebase.io
Other
11.66k stars 2.21k forks source link

🔥[🐛] Unable to reach callable cloud function - an internal error has occurred, DEADLINE_EXCEEDED, could not connect to the server #6263

Closed jadonhansen closed 2 years ago

jadonhansen commented 2 years ago

Issue

I am trying to call a firebase cloud function from my react-native app:

import { firebase } from "@react-native-firebase/functions";
import { FIREBASE_IOS_PURCHASE_SUB, FIREBASE_ANDROID_PURCHASE_SUB } from "@env";

    const purchaseSubscription = async () => {
        const payload = Platform.OS === "android" ? { purchaseToken: "yes" } : { transactionReceipt: { original_transaction_id: "yes" } };
        const functionName = Platform.OS === "android" ? FIREBASE_ANDROID_PURCHASE_SUB : FIREBASE_IOS_PURCHASE_SUB;

        try {
            const funcs = firebase.app().functions('europe-west1');
                         // comment below line out if you want to contact deployed function rather
            if (__DEV__) funcs.useEmulator('localhost', 5001);
            const { data } = await funcs.httpsCallable(functionName)(payload);

            console.log('Backend function return data: ', data);

            if (data && data !== null) {
                            // do stuff here
            } else {
                Alert.alert("Oops!", `Something went wrong while saving your purchase to our database. Please contact support.`);
            }
        } catch (error) {
            Alert.alert("Oops!", `Something went wrong while saving your purchase to our database: \n${error}\nPlease contact support.`);
        }
    }

The errors produced are various, depending on which platform and real device/emulator is being used. Here are the consistent errors I noted down, which are caught in a try-catch block when trying to call my cloud function.

Android emulator:

Android real device emulator:

iOS emulator:

iOS real device emulator:

*real device emulator: meaning a real mobile device tethered to the laptop running a dev build.


Project Files

Javascript

Click To Expand

#### `package.json`: ```json { "scripts": { "start": "react-native start", "android": "react-native run-android", "ios": "react-native run-ios", "web": "expo start --web", "eject": "expo eject" }, "dependencies": { "@react-native-async-storage/async-storage": "~1.15.0", "@react-native-community/masked-view": "^0.1.11", "@react-native-firebase/analytics": "^14.9.4", "@react-native-firebase/app": "^14.9.4", "@react-native-firebase/app-check": "^14.9.4", "@react-native-firebase/auth": "^14.9.4", "@react-native-firebase/crashlytics": "^14.9.4", "@react-native-firebase/firestore": "^14.9.4", "@react-native-firebase/functions": "^14.9.4", "@react-navigation/bottom-tabs": "^5.11.15", "@react-navigation/native": "^5.9.8", "@react-navigation/stack": "^5.14.9", "expo": "^44.0.0", "expo-haptics": "~11.1.0", "expo-in-app-purchases": "~12.1.0", "expo-linking": "~3.0.0", "expo-location": "~14.0.1", "expo-network": "~4.1.0", "expo-splash-screen": "~0.14.1", "expo-status-bar": "~1.2.0", "expo-updates": "~0.11.6", "react": "17.0.1", "react-dom": "17.0.1", "react-native": "0.64.3", "react-native-chart-kit": "^6.11.0", "react-native-dotenv": "^3.2.0", "react-native-elements": "^3.4.2", "react-native-gesture-handler": "~2.1.0", "react-native-maps": "0.29.4", "react-native-notifier": "^1.7.1", "react-native-reanimated": "^2.3.1", "react-native-restart": "0.0.22", "react-native-safe-area-context": "3.3.2", "react-native-screens": "~3.10.1", "react-native-snap-carousel": "^3.9.1", "react-native-svg": "12.1.1", "react-native-vector-icons": "^9.1.0", "react-native-web": "0.17.1" }, "devDependencies": { "@babel/core": "^7.12.9", "metro-react-native-babel-preset": "^0.66.2" }, "private": true, "name": "weatherly", "version": "1.0.0" } ``` #### `firebase.json` for react-native-firebase v6: ```json { "react-native": { "crashlytics_debug_enabled": false, "crashlytics_javascript_exception_handler_chaining_enabled": false } } ```

iOS

Click To Expand

#### `ios/Podfile`: - [ ] I'm not using Pods - [x] I'm using Pods and my Podfile looks like: ```ruby require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking") require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods") require File.join(File.dirname(`node --print "require.resolve('@react-native-community/cli-platform-ios/package.json')"`), "native_modules") platform :ios, '12.0' require 'json' podfile_properties = JSON.parse(File.read('./Podfile.properties.json')) rescue {} target 'Weatherly' do use_expo_modules! config = use_native_modules! use_react_native!( :path => config[:reactNativePath], :hermes_enabled => podfile_properties['expo.jsEngine'] == 'hermes' ) # Uncomment to opt-in to using Flipper # # if !ENV['CI'] # use_flipper!('Flipper' => '0.75.1', 'Flipper-Folly' => '2.5.3', 'Flipper-RSocket' => '1.3.1') # post_install do |installer| # flipper_post_install(installer) # end # end pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons' post_install do |installer| react_native_post_install(installer) # Workaround `Cycle inside FBReactNativeSpec` error for react-native 0.64 # Reference: https://github.com/software-mansion/react-native-screens/issues/842#issuecomment-812543933 installer.pods_project.targets.each do |target| if (target.name&.eql?('FBReactNativeSpec')) target.build_phases.each do |build_phase| if (build_phase.respond_to?(:name) && build_phase.name.eql?('[CP-User] Generate Specs')) target.build_phases.move(build_phase, 0) end end end end end end ``` #### `AppDelegate.m`: ```objc #import "AppDelegate.h" // firebase config #import #import #import #import #import #if defined(FB_SONARKIT_ENABLED) && __has_include() #import #import #import #import #import #import static void InitializeFlipper(UIApplication *application) { FlipperClient *client = [FlipperClient sharedClient]; SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults]; [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]]; [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]]; [client addPlugin:[FlipperKitReactPlugin new]]; [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]]; [client start]; } #endif @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // firebase config if ([FIRApp defaultApp] == nil) { [FIRApp configure]; } #if defined(FB_SONARKIT_ENABLED) && __has_include() InitializeFlipper(application); #endif RCTBridge *bridge = [self.reactDelegate createBridgeWithDelegate:self launchOptions:launchOptions]; RCTRootView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"main" initialProperties:nil]; rootView.backgroundColor = [UIColor whiteColor]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIViewController *rootViewController = [self.reactDelegate createRootViewController]; rootViewController.view = rootView; self.window.rootViewController = rootViewController; [self.window makeKeyAndVisible]; [super application:application didFinishLaunchingWithOptions:launchOptions]; return YES; } - (NSArray> *)extraModulesForBridge:(RCTBridge *)bridge { // If you'd like to export some custom RCTBridgeModules that are not Expo modules, add them here! return @[]; } - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #ifdef DEBUG return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; #else return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif } // Linking API - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options { return [RCTLinkingManager application:application openURL:url options:options]; } // Universal Links - (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray> * _Nullable))restorationHandler { return [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler]; } @end ```


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`: ```groovy // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { ext { buildToolsVersion = "29.0.3" minSdkVersion = 21 compileSdkVersion = 30 targetSdkVersion = 30 } repositories { google() mavenCentral() jcenter() } dependencies { classpath("com.android.tools.build:gradle:4.1.0") // added for firebase config classpath 'com.google.gms:google-services:4.3.10' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { mavenLocal() maven { // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm url(new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), "../android")) } maven { // Android JSC is installed from npm url(new File(["node", "--print", "require.resolve('jsc-android/package.json')"].execute(null, rootDir).text.trim(), "../dist")) } google() mavenCentral() jcenter() maven { url 'https://www.jitpack.io' } } } ``` #### `android/app/build.gradle`: ```groovy apply plugin: "com.android.application" apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' import com.android.build.OutputFile /** * 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. If none specified and * // "index.android.js" exists, it will be used. Otherwise "index.js" is * // default. Can be overridden with ENTRY_FILE environment variable. * entryFile: "index.android.js", * * // https://reactnative.dev/docs/performance#enable-the-ram-format * bundleCommand: "ram-bundle", * * // 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: false, cliPath: new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/cli.js", hermesCommand: new File(["node", "--print", "require.resolve('hermes-engine/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/%OS-BIN%/hermesc", composeSourceMapsPath: new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/scripts/compose-source-maps.js", ] apply from: new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), "../react.gradle") // for react-native-vector-icons project.ext.vectoricons = [ iconFontNames: [ 'Feather.ttf', 'FontAwesome.ttf', 'FontAwesome5_Brands.ttf', 'FontAwesome5_Regular.ttf', 'FontAwesome5_Solid.ttf', 'Ionicons.ttf' ] ] apply from: "../../node_modules/react-native-vector-icons/fonts.gradle" /** * Set this to true 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", false); android { compileSdkVersion rootProject.ext.compileSdkVersion compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } defaultConfig { applicationId 'com.jadonhansen.weatherly' minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 51 versionName "1.8.0" } splits { abi { reset() enable enableSeparateBuildPerCPUArchitecture universalApk false // If true, also generate a universal APK include "armeabi-v7a", "x86", "arm64-v8a", "x86_64" } } signingConfigs { debug { storeFile file('debug.keystore') storePassword 'android' keyAlias 'androiddebugkey' keyPassword 'android' } release { if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) { storeFile file(MYAPP_UPLOAD_STORE_FILE) storePassword MYAPP_UPLOAD_STORE_PASSWORD keyAlias MYAPP_UPLOAD_KEY_ALIAS keyPassword MYAPP_UPLOAD_KEY_PASSWORD } } } buildTypes { debug { signingConfig signingConfigs.release } release { /* Add the firebaseCrashlytics extension (by default, * it's disabled to improve build speeds) and set * nativeSymbolUploadEnabled to true along with a pointer to native libs. */ firebaseCrashlytics { nativeSymbolUploadEnabled true unstrippedNativeLibsDir 'build/intermediates/merged_native_libs/release/out/lib' } // Caution! In production, you need to generate your own keystore file. // see https://reactnative.dev/docs/signed-apk-android. signingConfig signingConfigs.release minifyEnabled enableProguardInReleaseBuilds proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } } // 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: // https://developer.android.com/studio/build/configure-apk-splits.html 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 = versionCodes.get(abi) * 1048576 + defaultConfig.versionCode } } } } dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) //noinspection GradleDynamicVersion implementation "com.facebook.react:react-native:+" // From node_modules def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true"; def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true"; def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true"; // If your app supports Android versions before Ice Cream Sandwich (API level 14) // All fresco packages should use the same version if (isGifEnabled || isWebpEnabled) { implementation 'com.facebook.fresco:fresco:2.0.0' implementation 'com.facebook.fresco:imagepipeline-okhttp3:2.0.0' } if (isGifEnabled) { // For animated gif support implementation 'com.facebook.fresco:animated-gif:2.0.0' } if (isWebpEnabled) { // For webp support implementation 'com.facebook.fresco:webpsupport:2.0.0' if (isWebpAnimatedEnabled) { // Animated webp support implementation 'com.facebook.fresco:animated-webp:2.0.0' } } implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" // added below for firebase config. Add any other firebase products here implementation platform('com.google.firebase:firebase-bom:30.0.2') implementation 'com.google.firebase:firebase-analytics' // added below for App Check (firebase) for emulator builds implementation 'com.google.firebase:firebase-appcheck-debug:16.0.0-beta02' // enable App Check (firebase) implementation 'com.google.firebase:firebase-appcheck-safetynet:16.0.0' 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) { debugImplementation files(new File(["node", "--print", "require.resolve('hermes-engine/package.json')"].execute(null, rootDir).text.trim(), "../android/hermes-debug.aar")) releaseImplementation files(new File(["node", "--print", "require.resolve('hermes-engine/package.json')"].execute(null, rootDir).text.trim(), "../android/hermes-release.aar")) } else { implementation jscFlavor } } // 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.compile into 'libs' } apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute(null, rootDir).text.trim(), "../native_modules.gradle"); applyNativeModulesAppBuildGradle(project) ``` #### `android/settings.gradle`: ```groovy rootProject.name = 'Weatherly' apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle"); useExpoModules() apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute(null, rootDir).text.trim(), "../native_modules.gradle"); applyNativeModulesSettingsGradle(settings) include ':app' ``` #### `MainApplication.java`: ```java package com.jadonhansen.weatherly; import android.app.Application; import android.content.Context; import android.content.res.Configuration; import androidx.annotation.NonNull; import com.facebook.react.PackageList; import com.facebook.react.ReactApplication; import com.oblador.vectoricons.VectorIconsPackage; import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; import com.facebook.react.shell.MainReactPackage; import com.facebook.soloader.SoLoader; import expo.modules.ApplicationLifecycleDispatcher; import expo.modules.ReactNativeHostWrapper; import com.facebook.react.bridge.JSIModulePackage; import com.swmansion.reanimated.ReanimatedJSIModulePackage; import java.lang.reflect.InvocationTargetException; import java.util.List; public class MainApplication extends Application implements ReactApplication { private final ReactNativeHost mReactNativeHost = new ReactNativeHostWrapper( this, new ReactNativeHost(this) { @Override public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } @Override protected List getPackages() { @SuppressWarnings("UnnecessaryLocalVariable") List packages = new PackageList(this).getPackages(); // Packages that cannot be autolinked yet can be added manually here, for example: // packages.add(new MyReactNativePackage()); return packages; } @Override protected String getJSMainModuleName() { return "index"; } @Override protected JSIModulePackage getJSIModulePackage() { return new ReanimatedJSIModulePackage(); } }); @Override public ReactNativeHost getReactNativeHost() { return mReactNativeHost; } @Override public void onCreate() { super.onCreate(); SoLoader.init(this, /* native exopackage */ false); initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); ApplicationLifecycleDispatcher.onApplicationCreate(this); } @Override public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig); } /** * Loads Flipper in React Native templates. Call this in the onCreate method * with something like initializeFlipper(this, * getReactNativeHost().getReactInstanceManager()); * * @param context * @param reactInstanceManager */ 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.jadonhansen.weatherly.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(); } } } } ``` #### `AndroidManifest.xml`: ```xml ```


Environment

Click To Expand

**`react-native info` output:** ``` System: OS: macOS 12.3.1 CPU: (4) x64 Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz Memory: 24.59 MB / 8.00 GB Shell: 5.8 - /bin/zsh Binaries: Node: 14.18.0 - /usr/local/bin/node Yarn: Not Found npm: 6.14.15 - /usr/local/bin/npm Watchman: 4.9.0 - /usr/local/bin/watchman Managers: CocoaPods: 1.11.2 - /usr/local/bin/pod SDKs: iOS SDK: Platforms: DriverKit 21.4, iOS 15.4, macOS 12.3, tvOS 15.4, watchOS 8.5 Android SDK: API Levels: 29, 30, 31 Build Tools: 29.0.2, 30.0.3 System Images: android-24 | Google Play Intel x86 Atom, android-26 | Google Play Intel x86 Atom, android-27 | Google Play Intel x86 Atom, android-28 | Google Play Intel x86 Atom, android-29 | Google Play Intel x86 Atom, android-30 | Google APIs Intel x86 Atom Android NDK: Not Found IDEs: Android Studio: 2021.1 AI-211.7628.21.2111.8092744 Xcode: 13.3.1/13E500a - /usr/bin/xcodebuild Languages: Java: 13.0.2 - /usr/bin/javac npmPackages: @react-native-community/cli: Not Found react: 17.0.1 => 17.0.1 react-native: 0.64.3 => 0.64.3 react-native-macos: Not Found npmGlobalPackages: *react-native*: Not Found ``` - **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 - [x] Both - **`react-native-firebase` version you're using that has this issue:** - `"@react-native-firebase/app": "^14.9.4"` - **`Firebase` module(s) you're using that has the issue:** - `@react-native-firebase/functions` - **Are you using `TypeScript`?** - `No


mikehardy commented 2 years ago

:thinking: - I can say that the use case of running the same instance (native execution context, including however many javascript-level bundle hot refresh / reloads) and attempting to switch from emulated to non-emulated is likely not supported. It definitely doesn't work for example in firestore or storage or real time database - I hesitate only a little with functions as it may be possible to make it work but in general I think not, and your testing seems to bear that out.

So if we strip out those cells of the matrix where going back and forth to the firebase emulator was the failure, I think we're left with

  1. Android emulator:

a- deployed function: Error: java.util.concurrent.ExecutionException: 1 out of 2 underlying tasks b- firebase emulator: Error: java.util.concurrent.ExecutionException: 1 out of 2 underlying tasks

  1. Android real device, debug build:

a- deployed function: Able to reach function b- firebase emulator: DEADLINE_EXCEEDED

  1. iOS emulator:

a- deployed function: Able to trigger function b- firebase emulator: Able to reach function, all good

  1. iOS real device, debug build:

a- deployed function: Error: An internal error has occurred, print and inspect the error details for more information b- firebase emulator: Error: Could not connect to the server.

So, for 1a/1b, adb logcat should have more details. 2b can be so many things... https://github.com/firebase/firebase-admin-node/issues/349 for instance - troubleshooting here should involve replacing your function with a simple hello world type function that does not attempt to mutate other state, to prove that functions is working between client and server (or firebase emulator). The result of that test will determine if you need to chase networking items / firewalls etc, or if you need to chase down issues with your function implementation and it's expectations of behavior from rest of system

4a- when you open the .xcworkspace file in Xcode and run it, you get a log of the app's execution and it should show the error. If Expo makes this impossible somehow, I think you can also use Console.app but the output is outrageously noisy - the error will be in there just hard to find. It will have the details though 4b - sounds like a networking issue

Hopefully this allows you to move forward a bit at least?

jadonhansen commented 2 years ago

Cool thanks Mike, will go ahead with trying the above and report back my findings

jadonhansen commented 2 years ago

@mikehardy Did some more testing with the above knowledge and came up with two theories - yesterday the logs showed that firebase app check wasn't able to send verified tokens through, mostly because I hadn't set it up properly. So I completely removed app check from the project (don't need it right now) and the deployed function requests started going through. However, I don't think this was the actual problem... Second scenario, today I did the same tests and requests were unable to reach the deployed functions. Weird, checking the logs again I noticed the login/auth requests were also not going through properly (even though this has been working for months) so I tried logging in and out multiple times in my app and eventually was able to retrieve the authed users data from firestore without a problem. Immediately after, I triggered the event to send a request and it came through to the deployed function... so it seems like firebase functions, and firestore, is a bit sensitive to network latency. Even though I am on a generally good network..?

Also, quick question: do you know if I need the 'cloud functions API' in GCP enabled for my app's API key? Currently it is a restricted key, so not sure whether I need 'cloud functions API' to be added?

jadonhansen commented 2 years ago

Just tested on my real iPhone device running debug build: the user's authed state and firestore doc had been cached so the user(me) may think they made a proper firebase request to get the updated data, instead it had been cached. So I tried triggering the firebase function... did not work, got one of the above errors. I logged out and then logged back in and seeing that it had retrieved the latest data, and therefore it had made a proper network connection with the server. I then triggered the firebase function again and it worked! So... how can one force the client to connect to the server and keep trying despite firebase's best efforts to cache?

mikehardy commented 2 years ago

Interesting results! I wonder if this is actually your auth token expiring and not refreshing correctly via the auth refresh token. That has happened before and hangs up most things. It has a few causes.

Last time this happened I believe it turned out to be a Google Cloud Platform API that was not enabled correctly for projects Previously it appears that using a VPN can interfere with google cloud located Apparently SSL certificate pinning may cause it as well

This is just a hunch - and it may be the totally wrong path, if so I apologize for any wasted time, however it seems so similar I thought it worth posting and the possible root causes here are easy to verify at least, I think - more info with details: https://github.com/invertase/react-native-firebase/issues/5522

jadonhansen commented 2 years ago

I looked pretty deep into that issue you linked and found a lot of people suggesting to re-download the google-services.json and GoogleService-Info.plist file from firebase. I did so and found that quite a few fields had been added to the json. Did a clean build for Android and iOS app and tested with emulators, requests to the functions went through perfectly fine.

I did find this error in the Android logcat: getToken() called while client was disconnected! but that was during app initialisation so not too sure what to make of it.

Going to test a bunch more before I close this issue, will keep you updated

jadonhansen commented 2 years ago
gcp

The above screenshot is showing what API's were used while testing on the Android emulator for the past hour only. If I go further back the Token API still shows 100% errors... the issue seems solved but this is showing something else? Hence more testing

jadonhansen commented 2 years ago
gcp

The above screenshot is showing what API's were used while testing on the Android emulator for the past hour only. If I go further back the Token API still shows 100% errors... the issue seems solved but this is showing something else? Hence more testing

Correction, the above is for iOS. Token Service API seems to only be invoked with iOS builds but isn't causing any runtime errors for me client side. So, seeing as though the I am able to call the backend functions now I think I can close this issue.

Thanks @mikehardy for the direction, unfortunately was a lame fix of replacing the firebase .json files :)

mikehardy commented 2 years ago

Ha - no worries. This stuff is pretty complicated and when the easy fix actually works, I'll take it! Good luck with your project