Skip to content

[🐛] [ANDROID] react-native-notifications has some Bundle.clone problem that crashes apps. Go to that repo. #6637

Closed
@viktor-CCM

Description

@viktor-CCM

Issue

I created a new project from template RN(npx react-native init AwesomeProject).
I used the guide from the documentation for the integration with Android part.

I sent the following HTTP POST request to https://fcm.googleapis.com/fcm/send (via Postman).
I got the push notification.

Step to reproduce:
Dead state
Click on the notification message
App will open
messaging().getInitialNotification() return notification
Dead state
Click on the notification message
App will crash

Screenshot 2022-10-26 at 21 19 50


Project Files

Javascript

Click To Expand React.useEffect(() => { messaging().onNotificationOpenedApp(remoteMessage => { console.log( 'remoteMessage caused app to open from background state:', remoteMessage, ); });
messaging()
  .getInitialNotification()
  .then(remoteMessage => {
    if (remoteMessage) {
      console.log(
        'Notification caused app to open from quit state:',
        remoteMessage,
      );
    }
  })
  .catch(er => {
    console.log('getInitialNotification ', er);
  });

}, []);

package.json:

{
"name": ".........",
"version": "0.0.1",
"private": true,
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"start": "react-native start",
"test": "jest",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx"
},
"dependencies": {
"@react-native-firebase/app": "^16.2.0",
"@react-native-firebase/messaging": "^16.2.0",
"react": "18.1.0",
"react-native": "0.70.3",
"react-native-notifications": "^4.3.1"
},
"devDependencies": {
"@babel/core": "^7.12.9",
"@babel/runtime": "^7.12.5",
"@react-native-community/eslint-config": "^2.0.0",
"@tsconfig/react-native": "^2.0.2",
"@types/jest": "^26.0.23",
"@types/react": "^18.0.21",
"@types/react-native": "^0.70.4",
"@types/react-test-renderer": "^18.0.0",
"@typescript-eslint/eslint-plugin": "^5.37.0",
"@typescript-eslint/parser": "^5.37.0",
"babel-jest": "^26.6.3",
"eslint": "^7.32.0",
"jest": "^26.6.3",
"metro-react-native-babel-preset": "0.72.3",
"react-test-renderer": "18.1.0",
"typescript": "^4.8.3"
},
"jest": {
"preset": "react-native",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
]
}
}

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:
# N/A

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:

// 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

    if (System.properties['os.arch'] == "aarch64") {
        // For M1 Users we need to use the NDK 24 which added support for aarch64
        ndkVersion = "24.0.8215888"
    } else {
        // Otherwise we default to the side-by-side NDK version from AGP.
        ndkVersion = "21.4.7075529"
    }
}
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.10'

    // NOTE: Do not place your application dependencies here; they belong
    // in the individual module build.gradle files
}

}

allprojects {
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()
maven { url 'https://www.jitpack.io' }
}
}

android/app/build.gradle:

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

import com.android.build.OutputFile
import org.apache.tools.ant.taskdefs.condition.Os

/**

  • 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: true, // clean and rebuild if changing
]

apply from: "../../node_modules/react-native/react.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 that value will be read 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);

/**

  • 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"]
    }

android {
ndkVersion rootProject.ext.ndkVersion

compileSdkVersion rootProject.ext.compileSdkVersion

defaultConfig {
    applicationId "com.mobile"
    minSdkVersion rootProject.ext.minSdkVersion
    targetSdkVersion rootProject.ext.targetSdkVersion
    versionCode 1
    versionName "1.0"
    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())
    }
}
signingConfigs {
    debug {
        storeFile file('debug.keystore')
        storePassword 'android'
        keyAlias 'androiddebugkey'
        keyPassword 'android'
    }
}
buildTypes {
    debug {
        signingConfig signingConfigs.debug
    }
    release {
        // Caution! In production, you need to generate your own keystore file.
        // see https://reactnative.dev/docs/signed-apk-android.
        signingConfig signingConfigs.debug
        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
        // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc.
        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 * 1000 + versionCodes.get(abi)
        }

    }
}

}

dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])

//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+"  // From node_modules

implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.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) {
    //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'
}

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

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 = 'ccm'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':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.mobile.ccm;

import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;

public class MainActivity extends ReactActivity {

/**

  • Returns the name of the main component registered from JavaScript. This is used to schedule
  • rendering of the component.
    */
    @OverRide
    protected String getMainComponentName() {
    return "ccm";
    }

/**

  • Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
  • you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer
  • (Paper).
    */
    @OverRide
    protected ReactActivityDelegate createReactActivityDelegate() {
    return new MainActivityDelegate(this, getMainComponentName());
    }

public static class MainActivityDelegate extends ReactActivityDelegate {
public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
super(activity, mainComponentName);
}

@Override
protected ReactRootView createRootView() {
  ReactRootView reactRootView = new ReactRootView(getContext());
  // If you opted-in for the New Architecture, we enable the Fabric Renderer.
  reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
  return reactRootView;
}

@Override
protected boolean isConcurrentRootEnabled() {
  // If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18).
  // More on this on https://reactjs.org/blog/2022/03/29/react-v18.html
  return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
}

}
}

AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />

<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">
  <activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
    android:launchMode="singleTask"
    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>
</application>


Environment

Click To Expand

react-native info output:

System:
    OS: macOS 12.5.1
    CPU: (16) x64 Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
    Memory: 151.75 MB / 32.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.14.2 - ~/.nvm/versions/node/v16.14.2/bin/node
    Yarn: 1.22.18 - /usr/local/bin/yarn
    npm: 8.5.0 - ~/.nvm/versions/node/v16.14.2/bin/npm
    Watchman: 2021.06.07.00 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.11.3 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: DriverKit 21.4, iOS 16.0, macOS 12.3, tvOS 16.0, watchOS 9.0
    Android SDK:
      Android NDK: 22.1.7171670
  IDEs:
    Android Studio: 2021.2 AI-212.5712.43.2112.8815526
    Xcode: 14.0.1/14A400 - /usr/bin/xcodebuild
  Languages:
    Java: 11.0.11 - /usr/bin/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: 18.1.0 => 18.1.0 
    react-native: 0.70.3 => 0.70.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
    • Both
  • react-native-firebase version you're using that has this issue:
    • 16.2.0
  • Firebase module(s) you're using that has the issue:
    • @react-native-firebase/messaging
  • Are you using TypeScript?
    • Y/N & VERSION


Metadata

Metadata

Assignees

No one assigned

    Labels

    help: needs-triageIssue needs additional investigation/triaging.type: bugNew bug report

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions