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.69k stars 2.21k forks source link

[πŸ›] AppCheck usage sky rockets after update #7766

Closed RomanKidoodle closed 4 months ago

RomanKidoodle commented 6 months ago

Issue

We have noticed that our PlayIntegrity usage has skyrocketed after update of the react-native-firebase/* packages. We have updated from 17.4.2 to 19.0.0

  "@react-native-firebase/analytics": "17.4.2",
  "@react-native-firebase/app": "17.4.2",
  "@react-native-firebase/app-check": "17.4.2",
  "@react-native-firebase/auth": "17.4.2",
  "@react-native-firebase/crashlytics": "17.4.2",
  "@react-native-firebase/dynamic-links": "17.4.2",
  "@react-native-firebase/in-app-messaging": "17.4.2",
  "@react-native-firebase/messaging": "17.4.2",
  "@react-native-firebase/remote-config": "^17.4.2",

  "@react-native-firebase/analytics": "19.0.0",
  "@react-native-firebase/app": "19.0.0",
  "@react-native-firebase/app-check": "19.0.0",
  "@react-native-firebase/auth": "19.0.0",
  "@react-native-firebase/crashlytics": "19.0.0",
  "@react-native-firebase/dynamic-links": "19.0.0",
  "@react-native-firebase/in-app-messaging": "19.0.0",
  "@react-native-firebase/messaging": "19.0.0",
  "@react-native-firebase/remote-config": "19.0.0",

We haven't done any other change apart from the version upgrade. As for the usage, we run

await firebase.appCheck().initializeAppCheck({
      provider: provider,
      isTokenAutoRefreshEnabled: false,
    });

in the code outside the react


setupApp() // here the appCheck is called

export const RootApp = () => { ... }

And then apart from default usage for phone number auth, we use it for a custom provider like this

export const getAppCheckHeaders = async () => {
  const appCheck = await firebase.appCheck().getToken();

  return {
    ...getDefaultHeaders(),
    'X-token': appCheck.token,
  };
};

After the update, we see that the number of PlayIntegrity calls doubled and is raising. This is not caused by the raise in users numbers. image

I'm not sure if for iOS there is also problem - we don't have(or don't know about) view into the details of Apple service behind the AppCheck.

Project Files

Javascript

Click To Expand

#### `package.json`: ```json # N/A ``` #### `firebase.json` for react-native-firebase v6: ```json # N/A ```

iOS

Click To Expand

#### `ios/Podfile`: - [ ] I'm not using Pods - [x] I'm using Pods and my Podfile looks like: ```ruby # N/A ``` #### `AppDelegate.m`: ```objc // 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`: ```groovy // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { ext { buildToolsVersion = "33.0.0" minSdkVersion = 24 compileSdkVersion = 33 targetSdkVersion = 33 googlePlayServicesAuthVersion = "19.2.0" kotlinVersion = '1.7.10' castFrameworkVersion = "21.0.0" // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. ndkVersion = "23.1.7779620" } repositories { google() mavenCentral() } dependencies { classpath("com.android.tools.build:gradle:7.3.1") classpath("com.facebook.react:react-native-gradle-plugin") classpath 'com.google.gms:google-services:4.3.10' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.9' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } ``` #### `android/app/build.gradle`: ```groovy apply plugin: "com.android.application" apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' apply plugin: "com.facebook.react" import com.android.build.OutputFile if (!System.getenv()["CI"] ) { project.ext.envConfigFiles = [ dev: ".env.development", ] } apply from: "../../node_modules/@sentry/react-native/sentry.gradle" apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle" /** * This is the configuration block to customize your React Native Android app. * By default you don't need to apply any configuration, just uncomment the lines you need. */ react { } /** * Set this to true to create four separate APKs instead of one, * one for each native architecture. This is useful if you don't * use App Bundles (https://developer.android.com/guide/app-bundle/) * and want to have separate APKs to upload to the Play Store. */ def enableSeparateBuildPerCPUArchitecture = false /** * Set this to true to Run Proguard on Release builds to minify the Java bytecode. */ def enableProguardInReleaseBuilds = false /** * The preferred build flavor of JavaScriptCore (JSC) * * 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:+' /** * Private function to get the list of Native Architectures you want to build. * This reads the value from reactNativeArchitectures in your gradle.properties * file and works together with the --active-arch-only flag of react-native run-android. */ def reactNativeArchitectures() { def value = project.getProperties().get("reactNativeArchitectures") return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] } // ! SegiTV is excluded from this versioning def getProductionVersionName = { -> return "1.1.1" } def getProductionVersionCode = { -> return 1 } // https://react-native-google-cast.github.io/docs/getting-started/installation def safeExtGet(prop, fallback) { rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback } android { compileSdkVersion rootProject.ext.compileSdkVersion configurations.all { resolutionStrategy { force 'org.xerial:sqlite-jdbc:3.34.0' force 'androidx.browser:browser:1.3.0' } } lintOptions { checkReleaseBuilds false // Add this abortOnError false } def keystoreProperties = new Properties() def keystorePropertiesFile = rootProject.file('key.properties') if (keystorePropertiesFile.exists()) { keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } defaultConfig { applicationId "xxx.xxx.xxx" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" multiDexEnabled true missingDimensionStrategy 'store', 'play' } splits { abi { reset() enable enableSeparateBuildPerCPUArchitecture universalApk false // If true, also generate a universal APK include (*reactNativeArchitectures()) } } signingConfigs { 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 } if (System.getenv()["CI"] && keystorePropertiesFile.exists()) { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile file(keystoreProperties['storeFile']) storePassword keystoreProperties['storePassword'] } } // Uncomment to build aab bundle. Pass path pointing to dev key file on your computer in storeFile // dev { // storeFile file('') // storePassword 'devTest' // keyAlias 'devAlias' // keyPassword 'devTest' // } debug { storeFile file('debug.keystore') storePassword 'android' keyAlias 'androiddebugkey' keyPassword 'android' } } buildTypes { debug { signingConfig null } release { // Caution! In production, you need to generate your own keystore file. // see https://reactnative.dev/docs/signed-apk-android. minifyEnabled enableProguardInReleaseBuilds proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" firebaseCrashlytics { nativeSymbolUploadEnabled true unstrippedNativeLibsDir 'build/intermediates/merged_native_libs/release/out/lib' } } } // 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 } } } flavorDimensions "default" productFlavors { dev { signingConfig signingConfigs.debug minSdkVersion rootProject.ext.minSdkVersion applicationId 'video.laminar.dev.android' targetSdkVersion rootProject.ext.targetSdkVersion resValue "string", "build_config_package", "xxx.xxx.xxx" manifestPlaceholders = [firebaseDeepLink: "laminar.page.link", appDeepLink:"client.dev.laminar.video"] versionCode Integer.valueOf(System.getenv().getOrDefault('BUILD_NUMBER', '1')) versionName "1.0.0" } } } dependencies { // The version of react-native is set by the React Native Gradle Plugin implementation("com.facebook.react:react-android") implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0") implementation "com.google.android.gms:play-services-cast-framework:${safeExtGet('castFrameworkVersion', '+')}" implementation project(':react-native-google-cast') debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { exclude group:'com.squareup.okhttp3', module:'okhttp' } debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") if (hermesEnabled.toBoolean()) { implementation("com.facebook.react:hermes-android") } else { implementation jscFlavor } } 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`: ```groovy // N/A ``` #### `MainApplication.java`: ```java package video.laminar.mobile; import android.app.Application; import android.content.Context; import com.facebook.react.PackageList; import com.facebook.react.ReactApplication; import com.facebook.react.ReactInstanceManager; import com.facebook.FacebookSdk; import com.facebook.LoggingBehavior; import com.reactnative.googlecast.GoogleCastPackage; import com.horcrux.svg.SvgPackage; import com.lugg.ReactNativeConfig.ReactNativeConfigPackage; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; import com.facebook.react.defaults.DefaultReactNativeHost; import com.facebook.soloader.SoLoader; import java.util.List; import org.wonday.orientation.OrientationActivityLifecycle; import android.webkit.WebView; import java.lang.reflect.InvocationTargetException; public class MainApplication extends Application implements ReactApplication { private final ReactNativeHost mReactNativeHost = new DefaultReactNativeHost(this) { @Override public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } @Override protected List getPackages() { @SuppressWarnings("UnnecessaryLocalVariable") List packages = new PackageList(this).getPackages(); // packages.add(new ReactVideoPackage()); // 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 boolean isNewArchEnabled() { return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; } @Override protected Boolean isHermesEnabled() { return BuildConfig.IS_HERMES_ENABLED; } }; @Override public ReactNativeHost getReactNativeHost() { return mReactNativeHost; } @Override public void onCreate() { super.onCreate(); SoLoader.init(this, /* native exopackage */ false); registerActivityLifecycleCallbacks(OrientationActivityLifecycle.getInstance()); if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { // If you opted-in for the New Architecture, we load the native entry point for this app. DefaultNewArchitectureEntryPoint.load(); } initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); FacebookSdk.addLoggingBehavior(LoggingBehavior.REQUESTS); } /** * 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.mobile.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:** ``` info Fetching system and libraries information... System: OS: macOS 14.1.1 CPU: (8) arm64 Apple M1 Pro Memory: 168.02 MB / 32.00 GB Shell: 5.9 - /bin/zsh Binaries: Node: 18.19.1 - ~/.nvm/versions/node/v18.19.1/bin/node Yarn: 1.22.19 - /opt/homebrew/bin/yarn npm: 10.2.4 - ~/.nvm/versions/node/v18.19.1/bin/npm Watchman: 2024.01.22.00 - /opt/homebrew/bin/watchman Managers: CocoaPods: 1.15.2 - /opt/homebrew/bin/pod SDKs: iOS SDK: Platforms: DriverKit 23.2, iOS 17.2, macOS 14.2, tvOS 17.2, watchOS 10.2 Android SDK: Not Found IDEs: Android Studio: 2022.3 AI-223.8836.35.2231.11005911 Xcode: 15.1/15C65 - /usr/bin/xcodebuild Languages: Java: 17.0.10 - /usr/bin/javac npmPackages: @react-native-community/cli: Not Found react: 18.2.0 => 18.2.0 react-native: 0.71.6 => 0.71.6 react-native-macos: Not Found npmGlobalPackages: *react-native*: Not Found info React Native v0.74.0 is now available (your project is running on v0.71.6). info Changelog: https://github.com/facebook/react-native/releases/tag/v0.74.0 info Diff: https://react-native-community.github.io/upgrade-helper/?from=0.71.6 info For more info, check out "https://reactnative.dev/docs/upgrading". ``` - **Platform that you're experiencing the issue on**: - [ ] iOS - [ ] Android - [ ] **iOS** but have not tested behavior on Android - [x] **Android** but have not tested behavior on iOS - [ ] Both - **`react-native-firebase` version you're using that has this issue:** - `19.0.0` - **`Firebase` module(s) you're using that has the issue:** - `@react-native-firebase/app-check` - **Are you using `TypeScript`?** - `Y` & `4.8.4`


mikehardy commented 6 months ago

Not sure what could cause it - investigation process would be:

If there is no obvious explanation from their CHANGELOG or release notes, you might open an issue on firebase-android-sdk to see what they think

RomanKidoodle commented 5 months ago

I will create an issue in the native sdk as well. I'll add some more information to this ticket:

For clarity, this is how we initialize the app check:

import { firebase } from '@react-native-firebase/app-check';

try {
    const provider = firebase
      .appCheck()
      .newReactNativeFirebaseAppCheckProvider();

    await provider.configure({
      android: {
        ...(isEnvValueSet(Config.ANDROID_APP_CHECK_DEBUG_TOKEN)
          ? {
              provider: 'debug',
              debugToken: Config.ANDROID_APP_CHECK_DEBUG_TOKEN,
            }
          : {
              provider: 'playIntegrity',
            }),
      },
      apple: {
        provider: 'appAttest',
      },
    });

    await firebase.appCheck().initializeAppCheck({
      provider: provider,
      isTokenAutoRefreshEnabled: false,
    });
  } catch (err: any) {
    captureError(err);
  }

EDIT: I've just noticed that the change in usage is actually for both Android and iOS: image

So this might be an issue with the library here πŸ€”

github-actions[bot] commented 4 months ago

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.