react-native-firebase icon indicating copy to clipboard operation
react-native-firebase copied to clipboard

:fire:[🐛] Android Secondary App - Remote config not fetching

Open stevenvp opened this issue 3 years ago • 13 comments

Issue

The remote config fetching works perfectly fine when using the default firebase app. When using a secondary firebase app, the fetching is not occurring.

While logging, the app is correctly linked with the secondary firebase app. When using the fetch & activate methods, no errors are thrown. But while logging the status, it is kept at no_fetch_yet.

Output of logs === Remote config initialized === - fetchTimeMillis: -1 - lastFetchStatus: no_fetch_yet - settings: {"fetchTimeMillis":60000,"minimumFetchIntervalMillis":43200000}

firebase.app('DEV').remoteConfig.getAll output

  • First startup of the app directly with DEV firebase app Returns an empty json object

  • First startup of the app with the DEFAULT firebase app and then restarting the app with the DEV firebase app Returns the previously fetched config from the DEFAULT app while using the DEV instance.

Project Files

package.json:

{
  "name": "ReactNativeProject",
  "version": "5.5.1",
  "engines": {
    "node": "12.x"
  },
  "private": true,
  "scripts": {
    "postinstall": "patch-package && npx jetify",
    "start": "react-native start"
  },
  "dependencies": {
    "@adobe/react-native-acpanalytics": "1.3.0",
    "@adobe/react-native-acpcore": "1.5.1",
    "@react-native-community/art": "^1.2.0",
    "@react-native-community/async-storage": "^1.6.2",
    "@react-native-community/netinfo": "^4.7.0",
    "@react-native-community/push-notification-ios": "1.2.0",
    "@react-native-community/slider": "2.0.7",
    "@react-native-firebase/analytics": "^12.8.0",
    "@react-native-firebase/app": "^12.8.0",
    "@react-native-firebase/crashlytics": "^12.8.0",
    "@react-native-firebase/messaging": "^12.8.0",
    "@react-native-firebase/remote-config": "^12.8.0",
    "@welldone-software/why-did-you-render": "^6.1.1",
    "Base64": "^1.1.0",
    "axios": "0.18.1",
    "axios-auth-refresh": "^1.0.7",
    "axios-retry": "^3.1.2",
    "babel-plugin-idx": "^2.4.0",
    "date-fns": "^2.7.0",
    "date-fns-tz": "^1.0.10",
    "deep-object-diff": "^1.1.0",
    "filesize": "^5.0.3",
    "humps": "^2.0.1",
    "i18n-js": "^3.3.0",
    "idx": "^2.5.6",
    "iso8601-duration": "^1.2.0",
    "lodash": "^4.17.11",
    "pako": "^2.0.3",
    "patch-package": "^6.4.7",
    "postinstall-postinstall": "^2.0.0",
    "react": "17.0.1",
    "react-native": "0.64.2",
    "react-native-appsflyer": "6.2.42",
    "react-native-background-fetch": "^2.8.0",
    "react-native-config": "^1.4.2",
    "react-native-device-info": "5.3.1",
    "react-native-exception-handler": "^2.10.8",
    "react-native-flash-message": "^0.1.23",
    "react-native-fs": "2.15.2",
    "react-native-gesture-handler": "^1.10.3",
    "react-native-get-random-values": "^1.4.0",
    "react-native-iap": "^6.2.3",
    "react-native-image-zoom-viewer": "^2.2.27",
    "react-native-inappbrowser-reborn": "^3.0.0",
    "react-native-inset-shadow": "^1.0.2",
    "react-native-keyboard-aware-scroll-view": "^0.9.4",
    "react-native-localize": "^1.4.3",
    "react-native-mail": "^4.1.0",
    "react-native-modal": "^12.0.2",
    "react-native-orientation-locker": "^1.1.6",
    "react-native-pager-view": "^6.0.0-rc.0",
    "react-native-progress": "^4.1.2",
    "react-native-push-notification": "^8.1.1",
    "react-native-rate": "^1.1.10",
    "react-native-safe-area-context": "^3.1.8",
    "react-native-safe-area-view": "^2.0.0",
    "react-native-scalable-image": "^1.1.0",
    "react-native-screens": "^1.0.0 || ^1.0.0-alpha",
    "react-native-svg": "^9.13.6",
    "react-native-webview": "^11.6.4",
    "react-native-zip-archive": "^5.0.6",
    "react-navigation": "^4.0.10",
    "react-navigation-stack": "^1.7.3",
    "react-redux": "^7.1.0",
    "recyclerlistview": "^2.0.12",
    "redux": "^4.0.2",
    "redux-act": "^1.7.7",
    "redux-devtools-extension": "^2.13.8",
    "redux-persist": "^5.10.0",
    "redux-persist-filesystem-storage": "^2.2.0",
    "redux-saga": "^1.0.5",
    "reselect": "^4.0.0",
    "rn-material-ui-textfield": "^1.0.3",
    "shallow-equal": "^1.2.0",
    "styled-components": "^4.4.1",
    "uuid": "^8.1.0",
    "yarn": "^1.19.2"
  },
  "devDependencies": {
    "@babel/core": "^7.12.9",
    "@babel/runtime": "^7.12.5",
    "@react-native-community/eslint-config": "^2.0.0",
    "@storybook/addon-actions": "5.1.9",
    "@storybook/addon-info": "5.1.9",
    "@storybook/addon-knobs": "5.1.9",
    "@storybook/addon-links": "5.1.9",
    "@storybook/addon-ondevice-knobs": "5.1.9",
    "@storybook/addon-storyshots": "5.1.9",
    "@storybook/addons": "5.1.9",
    "@storybook/react-native": "5.1.9",
    "@storybook/react-native-server": "5.1.9",
    "@storybook/theming": "^6.2.8",
    "@types/axios": "^0.14.0",
    "@types/humps": "^1.1.3",
    "@types/i18n-js": "^3.0.1",
    "@types/jest": "^24.9.1",
    "@types/lodash": "^4.14.136",
    "@types/node": "^12.20.15",
    "@types/react": "^16.14.10",
    "@types/react-native": "^0.60.31",
    "@types/react-native-mail": "^3.0.0",
    "@types/react-native-material-textfield": "^0.16.0",
    "@types/react-native-push-notification": "^3.0.9",
    "@types/react-navigation": "^3.0.7",
    "@types/react-redux": "^7.1.1",
    "@types/react-test-renderer": "^16.9.5",
    "@types/redux-logger": "^3.0.7",
    "@types/redux-persist": "^4.3.1",
    "@types/rn-fetch-blob": "^1.2.1",
    "@types/sinon": "^7.5.2",
    "@types/storybook__addon-knobs": "^5.0.2",
    "@types/storybook__addon-storyshots": "^4.0.2",
    "@types/storybook__react": "^4.0.2",
    "@types/styled-components": "^4.4.3",
    "@types/uuid": "^3.4.9",
    "axios-mock-adapter": "^1.17.0",
    "babel-jest": "^26.6.3",
    "babel-loader": "^8.0.6",
    "babel-plugin-transform-remove-console": "^6.9.4",
    "eslint": "^7.14.0",
    "husky": ">=1",
    "jest": "^24.8.0",
    "jetifier": "^1.6.8",
    "lint-staged": ">=8",
    "metro-react-native-babel-preset": "^0.64.0",
    "prettier": "1.18.2",
    "react-docgen-typescript-loader": "^3.1.0",
    "react-dom": "16.8.6",
    "react-native-asset": "github://femiveys/react-native-asset.git#d052f2371aa035017379031f7709d4fb5a71cd0f",
    "react-storybook-addon-props-combinations": "^1.1.0",
    "react-test-renderer": "17.0.1",
    "redux-logger": "^3.0.6",
    "redux-saga-test-plan": "^4.0.1",
    "sinon": "^7.5.0",
    "ts-jest": "^24.0.2",
    "tslint": "^6.1.3",
    "tslint-config-prettier": "^1.18.0",
    "tslint-config-standard": "^8.0.1",
    "tslint-plugin-prettier": "^2.0.1",
    "tslint-react": "^4.2.0",
    "tslint-react-native": "^0.0.7",
    "typescript": "^4.2.3"
  },
  "resolutions": {
    "react-native-safe-area-view": "^2.0.0"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{ts, tsx, css, json, md}": [
      "prettier --write",
      "git add"
    ],
    "*.{ts, tsx}": [
      "yarn lint --fix",
      "git add"
    ]
  }
}

TypeScript

Click To Expand

React Native remote config usage

import firebase from '@react-native-firebase/app';
import remoteConfig from '@react-native-firebase/remote-config';
import { config } from '../config';

class RemoteConfigBaseService {
  private useDev: boolean = false;

  private get appRemoteConfig(): any {
    const firebaseEnvironment = this.useDev ? 'DEV' : '[DEFAULT]';

    return firebase.app(firebaseEnvironment).remoteConfig();
  }

  public async init(useDev: boolean = false) {
    try {
      this.useDev = useDev;

      // Not sure why this check is needed, but otherwise the initializeApp
      // method throws an error
      // Firebase App named 'DEV' already exists
      // but this is the only place where the init happens and the init method is only called once
      if (!firebase.apps.some(app => app.name === 'DEV')) {
        await firebase.initializeApp(
          {
            appId: 'appId',
            apiKey: 'apiKey',
            databaseURL: '',
            projectId: 'projectId',
            storageBucket: 'storageBucket',
            clientId: 'clientId',
            messagingSenderId: 'messagingSenderId',
          },
          'DEV',
        );
      }

      // necessary to enable the remoteConfig module inside the firebase app
      remoteConfig();

      await this.appRemoteConfig.setConfigSettings({
        minimumFetchIntervalMillis: 60 * 1000,
        fetchTimeMillis: 8 * 1000, // Timeout fetching after 8s
      });

      await this.appRemoteConfig.setDefaults({
        fetch: JSON.stringify(config.defaultParams),
      });

      await this.appRemoteConfig.fetch();
      await this.appRemoteConfig.activate();

      const printStatus = `
        === Remote config initialized ===
        - fetchTimeMillis: ${this.appRemoteConfig.fetchTimeMillis}
        - lastFetchStatus: ${this.appRemoteConfig.lastFetchStatus}
        - settings: ${JSON.stringify(this.appRemoteConfig.settings)}
      `;

      console.log(printStatus);

      const params = JSON.parse(
        this.appRemoteConfig.getValue('params').asString(),
      );

      console.log('params ', params);
    } catch (e) {
      console.log('Remote config - Error occurred while initializing ', e);
    }
  }

  public async getParams(): TParams[] {
    try {
      console.log(this.appRemoteConfig.getAll());

      const params = JSON.parse(
        this.appRemoteConfig.getValue('params').asString(),
      );

      console.log('params ', params);

      return params;
    } catch (e) {
      return config.defaultParams;
    }
  }
}

export const RemoteConfigService = new RemoteConfigBaseService();

firebase.json for react-native-firebase v6:

{
  "crashlytics_auto_collection_enabled": true,
  "crashlytics_debug_enabled": true,
  "crashlytics_ndk_enabled": false,
  "react-native": {
    "messaging_android_headless_task_timeout": 180000
  }
}

Android

Click To Expand

Have you converted to AndroidX?

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

android/build.gradle:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    ext {
        buildToolsVersion = "31.0.0"
        minSdkVersion = 21
        compileSdkVersion = 31
        targetSdkVersion = 31
        ndkVersion = "20.1.5948944"
    }
    repositories {
        google()
        jcenter()
        maven {
            url 'https://maven.fabric.io/public'
        }
    }
    dependencies {
        classpath("com.android.tools.build:gradle:4.1.0")
        classpath 'com.google.gms:google-services:4.2.0'
        classpath 'io.fabric.tools:gradle:1.28.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("$rootDir/../node_modules/react-native/android")
        }
        maven {
            // Android JSC is installed from npm
            url("$rootDir/../node_modules/jsc-android/dist")
        }

        google()
        jcenter()
        maven { url 'https://www.jitpack.io' }
    }
}

android/app/build.gradle:

buildscript {
  repositories {
  }

  dependencies {
  }
}

apply plugin: "com.android.application"
apply plugin: 'io.fabric'

repositories {
}

project.ext.envConfigFiles = [
    debug: "clients/debug.env",
    release: "clients/release.env",
]

apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"

import com.android.build.OutputFile

project.ext.react = [
    enableHermes: false,  // clean and rebuild if changing
]

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

def enableSeparateBuildPerCPUArchitecture = false

def enableProguardInReleaseBuilds = false

def jscFlavor = 'org.webkit:android-jsc:+'

def enableHermes = project.ext.react.get("enableHermes", false);

android {
    ndkVersion rootProject.ext.ndkVersion

    compileSdkVersion rootProject.ext.compileSdkVersion
    flavorDimensions "default"

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    defaultConfig {
        applicationId "com.reactnative"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        resValue "string", "build_config_package", "com.reactnative"
        multiDexEnabled true
        ndk {
            abiFilters "armeabi-v7a", "armeabi", "x86", "arm64-v8a", "x86_64"
       }
       // react-native-iap: we only use the Google Play flavor
       missingDimensionStrategy 'store', 'play'
    }
    splits {
        abi {
            reset()
            enable enableSeparateBuildPerCPUArchitecture
            universalApk false  // If true, also generate a universal APK
            include "armeabi-v7a", "armeabi", "x86", "arm64-v8a", "x86_64"
        }
    }
    packagingOptions {
       pickFirst 'lib/x86/libc++_shared.so'
       pickFirst 'lib/x86/libjsc.so'
       pickFirst 'lib/x86_64/libjsc.so'
       pickFirst 'lib/arm64-v8a/libjsc.so'
       pickFirst 'lib/arm64-v8a/libc++_shared.so'
       pickFirst 'lib/x86_64/libc++_shared.so'
       pickFirst 'lib/armeabi-v7a/libc++_shared.so'
       pickFirst 'lib/armeabi-v7a/libjsc.so'
    }
    signingConfigs {
        
    }
    buildTypes {
        debug {
            debuggable true
        }
        release {
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }
    flavorDimensions "client", "env"
    productFlavors {
        
    }

    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
            def abi = output.getFilter(OutputFile.ABI)
            if (abi != null) {
                output.versionCodeOverride =
                        defaultConfig.versionCode * 1000 + versionCodes.get(abi)
            }
        }
    }

    dexOptions {
        javaMaxHeapSize "4g"
    } 
}

dependencies {
    implementation project(':react-native-push-notification')
    implementation project(':react-native-background-fetch')
    implementation project(':react-native-orientation-locker')
    implementation project(':react-native-gesture-handler')
    implementation project(':react-native-config')
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'com.android.support:multidex:1.0.3'
    implementation "com.facebook.react:react-native:+"
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
    implementation project(':reactnativereplicareader')

    // JSC from node_modules
    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) {
        def hermesPath = "../../node_modules/hermes-engine/android/";
        debugImplementation files(hermesPath + "hermes-debug.aar")
        releaseImplementation files(hermesPath + "hermes-release.aar")
    } else {
        implementation jscFlavor
    }
}

task copyDownloadableDepsToLibs(type: Copy) {
    from configurations.compile
    into 'libs'
}

apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

apply plugin: 'com.google.gms.google-services'

android/settings.gradle:

rootProject.name = 'reactnative'
include ':@adobe_react-native-acpcore'
project(':@adobe_react-native-acpcore').projectDir = new File(rootProject.projectDir, '../node_modules/@adobe/react-native-acpcore/android')
include ':@adobe_react-native-acpanalytics'
project(':@adobe_react-native-acpanalytics').projectDir = new File(rootProject.projectDir, '../node_modules/@adobe/react-native-acpanalytics/android')
include ':rn-fetch-blob'
project(':rn-fetch-blob').projectDir = new File(rootProject.projectDir, '../node_modules/rn-fetch-blob/android')
include ':react-native-push-notification'
project(':react-native-push-notification').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-push-notification/android')
include ':react-native-background-fetch'
project(':react-native-background-fetch').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-background-fetch/android')
include ':react-native-orientation-locker'
project(':react-native-orientation-locker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-orientation-locker/android')
include ':react-native-gesture-handler'
project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android')
include ':react-native-config'
project(':react-native-config').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-config/android')
include ':react-native-art'
project(':react-native-art').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/art/android')
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'

MainApplication.java:

package com.reactnative;

import android.app.Activity;
import android.content.Context;
import android.app.Application;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;

import androidx.appcompat.app.AppCompatDelegate;
import androidx.multidex.MultiDex;

import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.adobe.marketing.mobile.reactnative.RCTACPCorePackage;
import com.adobe.marketing.mobile.reactnative.analytics.RCTACPAnalyticsPackage;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException;
import com.adobe.marketing.mobile.reactnative.RCTACPCorePackage;
import com.adobe.marketing.mobile.AdobeCallback;
import com.adobe.marketing.mobile.MobileCore; // import MobileCore
import com.adobe.marketing.mobile.Identity;
import com.adobe.marketing.mobile.Lifecycle;
import com.adobe.marketing.mobile.Signal;
import com.adobe.marketing.mobile.WrapperType;
import com.adobe.marketing.mobile.LoggingMode;
import com.adobe.marketing.mobile.InvalidInitException;
import com.adobe.marketing.mobile.Analytics;

import com.reactnativereplicareader.RCTReplicaReaderPackage;

import java.util.Arrays;
import java.util.List;

public class MainApplication extends Application implements ReactApplication {

  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    @Override
    public boolean getUseDeveloperSupport() {
      return BuildConfig.DEBUG;
    }

    @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 MyReactNativePackage());
      packages.add(new RCTReplicaReaderPackage());
      return packages;
    }

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

  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }

  @Override
  public void onCreate() {
    setTheme(R.style.AppTheme);
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);

    if(BuildConfig.LOAD_ADOBE_SDK == "true"){
      MobileCore.setApplication(this);
      MobileCore.setLogLevel(LoggingMode.ERROR);
      MobileCore.setWrapperType(WrapperType.REACT_NATIVE);
      try {
        Identity.registerExtension();
        Lifecycle.registerExtension();
        Signal.registerExtension();
        Analytics.registerExtension();
        MobileCore.start(new AdobeCallback() {
          @Override
          public void call(Object o) {
            MobileCore.configureWithAppID(BuildConfig.ADOBE_ID);
          }
        });
      } catch (InvalidInitException e) {
        Log.e("MainApplication", String.format("Error while registering extensions %s", e.getLocalizedMessage()));
      }

      registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
        @Override
        public void onActivityCreated(Activity activity, Bundle bundle) { /*no-op*/ }

        @Override
        public void onActivityStarted(Activity activity) { /*no-op*/ }

        @Override
        public void onActivityResumed(Activity activity) {
          MobileCore.setApplication(MainApplication.this);
          MobileCore.lifecycleStart(null);
        }

        @Override
        public void onActivityPaused(Activity activity) {
          MobileCore.lifecyclePause();
        }

        @Override
        public void onActivityStopped(Activity activity) { /*no-op*/ }

        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { /*no-op*/ }

        @Override
        public void onActivityDestroyed(Activity activity) { /*no-op*/ }
      });
    }
  }

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

  /**
   * 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.rndiffapp.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:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.reactnative">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:allowBackup="false"
      android:theme="@style/AppTheme.Launcher"
      android:usesCleartextTraffic="true"
      android:hardwareAccelerated="true"
      >
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_icon"
            android:resource="@mipmap/ic_notification" />
        <meta-data  android:name="com.dieam.reactnativepushnotification.notification_channel_name"
            android:value="YOUR NOTIFICATION CHANNEL NAME"/>
        <meta-data  android:name="com.dieam.reactnativepushnotification.notification_channel_description"
            android:value="YOUR NOTIFICATION CHANNEL DESCRIPTION"/>
        <!-- Change the resource name to your App's accent color - or any other color you want -->
        <!-- <meta-data  android:name="com.dieam.reactnativepushnotification.notification_color"
            android:resource="@android:color/white"/> -->
        <receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher" />
        <receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
        <receiver android:name = "com.amazon.device.iap.ResponseReceiver"
            android:permission = "com.amazon.inapp.purchasing.Permission.NOTIFY" >
            <intent-filter>
            <action android:name = "com.amazon.inapp.purchasing.NOTIFY" android:permission = "com.amazon.inapp.purchasing.Permission.NOTIFY"/>
            </intent-filter>
        </receiver>
        <service android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationRegistrationService"/>
        <service
            android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
        android:launchMode="singleTask"
        android:windowSoftInputMode="adjustResize">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
      </activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
    </application>

</manifest>


Environment

Click To Expand

react-native info output:

System:
    OS: macOS 11.4
    CPU: (8) arm64 Apple M1
    Memory: 87.48 MB / 16.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 16.3.0 - ~/.nvm/versions/node/v16.3.0/bin/node
    Yarn: 1.22.10 - ~/.nvm/versions/node/v16.3.0/bin/yarn
    npm: 7.15.1 - ~/.nvm/versions/node/v16.3.0/bin/npm
    Watchman: 4.9.0 - /opt/local/bin/watchman
  Managers:
    CocoaPods: 1.11.2 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 15.0, DriverKit 20.4, macOS 11.3, tvOS 15.0, watchOS 8.0
    Android SDK: Not Found
  IDEs:
    Android Studio: 4.2 AI-202.7660.26.42.7486908
    Xcode: 13.0/13A233 - /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.2 => 0.64.2 
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found
  • Platform that you're experiencing the issue on:
    • [ ] iOS
    • [x] Android
    • [ ] iOS but have not tested behavior on Android
    • [ ] Android but have not tested behavior on iOS
    • [ ] Both
  • Firebase module(s) you're using that has the issue:
    • "@react-native-firebase/analytics": "^12.8.0"
    • "@react-native-firebase/app": "^12.8.0"
    • "@react-native-firebase/crashlytics": "^12.8.0"
    • "@react-native-firebase/messaging": "^12.8.0"
    • "@react-native-firebase/remote-config": "^12.8.0"
  • Are you using TypeScript?
    • Y v4.2.3

stevenvp avatar Oct 05 '21 15:10 stevenvp

Hmm - on a glance your firebase dependencies look mostly up to date but:

        classpath("com.android.tools.build:gradle:4.1.0")
        classpath 'com.google.gms:google-services:4.2.0'
        classpath 'io.fabric.tools:gradle:1.28.1'
  • you should use 4.1.2 at least I believe, and google-services is in 4.3.10 - leave yourself a comment in the file with this URL so you can keep versions up to date https://firebase.google.com/support/release-notes/android
  • your crashlytics migration looks incomplete, is that on purpose? You still have fabric on your classpath and used via plugin? Should be crashlytics at this point https://rnfirebase.io/crashlytics/android-setup
  • multidex is meaningless on android API21+, your minSdkVersion is 21 so you should remove your Multidex implementation from dependencies and MainApplication
  • appcompat is on 1.3.1 https://developer.android.com/jetpack/androidx/releases/appcompat

Unfortunately for this issue, none of that really matters. I've never used remote-config for a secondary app so this isn't a use case of mine, sorry.

Does this happen on iOS and android? Is there anything remotely relevant in either of the upstream SDK issues lists https://github.com/firebase/firebase-android-sdk/ / https://github.com/firebase/firebase-ios-sdk/ or stack overflow? Without personal experience or an App.js we can drop in to test (https://stackoverflow.com/help/minimal-reproducible-example) I'm not even sure where the problem is (your code, our wrapper module, underlying SDKs...)

mikehardy avatar Oct 05 '21 16:10 mikehardy

The problem is only occurring on Android. On iOS the secondary app is working fine. When looking at the example code of react-native-firebase, the implementation should be fine.

https://rnfirebase.io/app/usage#secondary-apps https://rnfirebase.io/remote-config/usage

The issue was also occurring on older react-native-firebase versions, I was wondering if we should do anything extra for android. When using the DEV environments google-services.json, it fetches correctly.

stevenvp avatar Oct 06 '21 07:10 stevenvp

I was wondering if we should do anything extra for android.

Unknown, I asked several other questions apart from ios vs android although that's great to know - indicates backend is working, and firebase-ios-sdk appears okay, which allows a focus of the effort on the android pathway here and firebase-android-sdk.

mikehardy avatar Oct 06 '21 16:10 mikehardy

I've created a minimal reproducible project which will be handy for investigating the issue.

The problem is still occurring, you will see that on iOS the values are being retrieved correctly while on android the value is never coming back from the secondary app. When fetching with the primary app first, it will even return that value when using the secondary app.

https://github.com/stevenvp/remote-config-secondary-app-example

stevenvp avatar Oct 08 '21 09:10 stevenvp

Same problem here. I have two projects on Firebase (prod and dev). I've created the prod's project before dev. I'm getting prod configs correctly. However, when I change the google-services file to dev, I'm still getting prod values.

DaviGn avatar Nov 04 '21 13:11 DaviGn

Sorry to hear this is affecting you @DaviGn - the issue itself is obviously still open and @stevenvp did fantastic work creating a reproduction but I haven't had time to dig in yet and may not for a little while longer yet. This is wide open for anyone else that wants to dive in, in other words

mikehardy avatar Nov 04 '21 14:11 mikehardy

After many tests, I realized that values in values.xml on path android\app\build\generated\res\google-services\debug\values\values.xml weren't beeing refreshed. I don't if it's a Google Service or react-native-firebase bug, but now it's working, I changed the values manually.

DaviGn avatar Nov 04 '21 19:11 DaviGn

well, there are a lot of firebase options ;-) - but I think if you mean "is that where the FirebaseApp options are serialized to send across to the native side, then yes.

Thing is, we do other testing with secondary apps and the initialization works - we are sending things through, and the FirebaseApp is the secondary:

mike@osxvm-little:~/work/Invertase/react-native-firebase (@mikehardy/android12 *) % grep -ri secondary packages/**/e2e
packages/app/e2e/app.e2e.js:    should.equal(firebase.app('secondaryFromNative')._nativeInitialized, true);
packages/app/e2e/app.e2e.js:    should.equal(firebase.app('secondaryFromNative').name, 'secondaryFromNative');
packages/app/e2e/app.constants.e2e.js:      // secondaryFromNative + default
packages/auth/e2e/auth.e2e.js:        .auth(firebase.app('secondaryFromNative'))
packages/auth/e2e/auth.e2e.js:        .app.name.should.equal('secondaryFromNative');
packages/auth/e2e/auth.e2e.js:      firebase.app('secondaryFromNative').auth().app.name.should.equal('secondaryFromNative');
packages/database/e2e/database.e2e.js:        .database(firebase.app('secondaryFromNative'))
packages/database/e2e/database.e2e.js:        .app.name.should.eql('secondaryFromNative');
packages/database/e2e/database.e2e.js:      firebase.app('secondaryFromNative').database().app.name.should.eql('secondaryFromNative');
packages/database/e2e/database.e2e.js:      .database(firebase.app('secondaryFromNative'))
packages/database/e2e/database.e2e.js:      .app.name.should.eql('secondaryFromNative');
packages/database/e2e/database.e2e.js:    firebase.app('secondaryFromNative').database().app.name.should.eql('secondaryFromNative');
packages/firestore/e2e/DocumentReference/isEqual.e2e.js:      firebase.firestore(firebase.app('secondaryFromNative')).doc(`${COLLECTION}/baz`),
packages/firestore/e2e/WriteBatch/set.e2e.js:      const app2 = firebase.app('secondaryFromNative');
packages/firestore/e2e/WriteBatch/delete.e2e.js:      const app2 = firebase.app('secondaryFromNative');
packages/firestore/e2e/WriteBatch/update.e2e.js:      const app2 = firebase.app('secondaryFromNative');
packages/firestore/e2e/firestore.e2e.js:        .firestore(firebase.app('secondaryFromNative'))
packages/firestore/e2e/firestore.e2e.js:        .app.name.should.equal('secondaryFromNative');
packages/firestore/e2e/firestore.e2e.js:      firebase.app('secondaryFromNative').firestore().app.name.should.equal('secondaryFromNative');
packages/firestore/e2e/Query/isEqual.e2e.js:    const q1 = firebase.firestore(firebase.app('secondaryFromNative')).collection(subCol);
packages/ml/e2e/ml.e2e.js:      firebase.ml(firebase.app('secondaryFromNative')).app.name.should.equal('secondaryFromNative');
packages/ml/e2e/ml.e2e.js:      firebase.app('secondaryFromNative').ml().app.name.should.equal('secondaryFromNative');
packages/remote-config/e2e/config.e2e.js:        .firestore(firebase.app('secondaryFromNative'))
packages/remote-config/e2e/config.e2e.js:        .app.name.should.equal('secondaryFromNative');
packages/remote-config/e2e/config.e2e.js:        .app('secondaryFromNative')
packages/remote-config/e2e/config.e2e.js:        .app.name.should.equal('secondaryFromNative');
packages/storage/e2e/storage.e2e.js:        .storage(firebase.app('secondaryFromNative'))
packages/storage/e2e/storage.e2e.js:        .app.name.should.equal('secondaryFromNative');
packages/storage/e2e/storage.e2e.js:      firebase.app('secondaryFromNative').storage().app.name.should.equal('secondaryFromNative');

https://github.com/invertase/react-native-firebase/blob/4871131c3587e138398719ef5537731ee4fbe90a/packages/remote-config/e2e/config.e2e.js?#L26-L37

https://github.com/invertase/react-native-firebase/runs/4093905857?check_suite_focus=true#step:21:1598

So...the secondary app itself may be initialized and seen through the remote-config module, but clearly it's not loading the actual remote-config values from the secondary app.

I just scanned all the java code in packages/remote-config and it appears we are passing appName through everywhere and using that everywhere to get the correct native FirebaseApp and then the correct FirebaseRemoteConfig instance.

This seems like it might be a native issue in the underlying firebase-android-sdk - I wonder if it is possible to repro starting from https://github.com/firebase/quickstart-android/tree/master/config

mikehardy avatar Nov 04 '21 19:11 mikehardy

the XML writing is the province of google-services-plugin: https://developers.google.com/android/guides/google-services-plugin https://github.com/google/play-services-plugins/#google-services-plugin

mikehardy avatar Nov 04 '21 19:11 mikehardy

Am I correct in thinking if you do ./gradlew clean in the android directory then rebuild this works then?

mikehardy avatar Nov 04 '21 19:11 mikehardy

Maybe it works, I'll try it, thanks. I'll make a script in package.json to do it every time I build the app.

DaviGn avatar Nov 04 '21 19:11 DaviGn

Having the same issue here.

The ./gradle clean seems to work only when the secondary app instance is active in the app. Switching back to the primary app is working as well. But when you switch back to the secondary, you have to do the clean again.

Also noticed it works best when stopping the Metro instance and even removing the application from the device to perform a fresh installation.

JakobLierman avatar Nov 22 '21 08:11 JakobLierman

Hello 👋, to help manage issues we automatically close stale issues. This issue has been automatically marked as stale because it has not had activity for quite some time. Has this issue been fixed, or does it still require the community's attention?

This issue will be closed in 15 days if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Apr 18 '22 18:04 stale[bot]

Hello 👋, to help manage issues we automatically close stale issues.

This issue has been automatically marked as stale because it has not had activity for quite some time.Has this issue been fixed, or does it still require attention?

This issue will be closed in 15 days if no further activity occurs.

Thank you for your contributions.

github-actions[bot] avatar Dec 05 '22 19:12 github-actions[bot]

I have the exact same problem, rechecked api tokens/client id to make sure they were right, remote config simply will not fetch on Android using secondary firebase instances, the fact that it's impossible to get debug logs aside from lastFetchedStatus does not help.

arthurgeron-work avatar Dec 07 '22 17:12 arthurgeron-work