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.54k stars 2.19k forks source link

🔥 Automatically collected events are not collected all the time #1758

Closed LorandP closed 5 years ago

LorandP commented 5 years ago

Issue

Automatically collected events like Opens and Conversions which show how many times a push notification was opened do not register on firebase console all the time. You can see the events here https://www.photobox.co.uk/my/photo/full?photo_id=501468107131 https://support.google.com/firebase/answer/6317485?hl=en

The onNotificationOpened method is triggered but these two events are not collected all the time. ` import firebase from 'react-native-firebase' class FCM { constructor() { this.notificationListener = null; this.notificationOpenedListener = null; this.notificationChannel = null; }

async addListeners() { try { if (isIOS) { return NotificationsIOS.configure(); }

  // Build a channel object
  this.channel = new firebase.notifications.Android.Channel(
    'app-channel',
    'app Channel',
    firebase.notifications.Android.Importance.Max
  );
  // Create the channel
  firebase.notifications().android.createChannel(this.channel);

  this.messageListener = firebase.messaging().onMessage((message) => {
    Insider.handleNotification(message.data);
  });

  this.notificationListener = firebase.notifications().onNotification((notification) => {
    notification.setSound('default');
    notification
      .android.setChannelId('app-channel')
      .android.setPriority(firebase.notifications.Android.Priority.High)
      .android.setSmallIcon('ic_notification');

    firebase.notifications().displayNotification(notification);
  });

  // Open notification - App in Foreground and background
  this.notificationOpenedListener = firebase.notifications().onNotificationOpened((notificationOpen) => {
    // Get information about the notification that was opened
    const notification = notificationOpen.notification;
    NotificationService.handleNotificationData(notification.data);
    Insider.handleNotification(notification.data);
  });
} catch (err) {
  CrashlyticsService.logException('FCM.addListeners', {}, err);
}

}

removeListeners() { try { this.notificationListener(); this.messageListener(); this.notificationOpenedListener(); this.notificationChannel = null; } catch (err) { CrashlyticsService.logException('FCM.removeListeners', {}, err); } }`


Project Files

iOS

ios/Podfile:

` platform :ios, '9.0'

target 'app' do Uncomment the next line if you're using Swift or would like to use dynamic frameworks use_frameworks!

pod 'Fabric', '1.8.0' pod 'Crashlytics', '3.11.0'

pod Firebase/Core, ~> 5.3.0 pod Firebase/Messaging, ~> 5.3.0 pod Firebase/Auth, ~> 5.3.0 pod Firebase/Firestore, ~> 5.3.0

pod NewRelicAgent, 5.14.2

end `

# N/A

AppDelegate.m:

/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#import "AppDelegate.h"

@import Firebase;
#import <UserNotifications/UserNotifications.h>
#import "RNFirebaseNotifications.h"
#import "RNFirebaseMessaging.h"
#import "RNFirebaseEvents.h"

#import <React/RCTPushNotificationManager.h>

#import <Fabric/Fabric.h>
#import <Crashlytics/Crashlytics.h>

#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import "RNSplashScreen.h"
#import <React/RCTLinkingManager.h>
#import "ReactNativeConfig.h"

#import <react-native-branch/RNBranch.h>

#import <NewRelicAgent/NewRelic.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
//  if ([[url scheme] isEqualToString:@"insiderappstreettest"] || [[url scheme] isEqualToString:@"insiderappstreet"]) {
//    [Insider handleUrl:url];
//  } else {
    return [RCTLinkingManager application:application openURL:url
                        sourceApplication:sourceApplication annotation:annotation];
//  }
//  return YES;
}

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
 restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
{
 return [RCTLinkingManager application:application
                  continueUserActivity:userActivity
                    restorationHandler:restorationHandler];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  NSString *newRelicToken = [ReactNativeConfig envFor:@"NEW_RELIC_TOKEN"];
  [NewRelicAgent startWithApplicationToken:newRelicToken];

  NSString *isProduction = [ReactNativeConfig envFor:@"IS_PRODUCTION"];

  [RNBranch initSessionWithLaunchOptions:launchOptions isReferrable:YES];

  NSURL *jsCodeLocation;

  jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];

  NSString *firebaseConfig = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info-staging" ofType:@"plist"];
  if ([isProduction isEqualToString:@"true"]) {
    firebaseConfig = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist"];
  }

  FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:firebaseConfig];
  [FIRApp configureWithOptions:options];
  [RNFirebaseNotifications configure];

  RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@"app"
                                               initialProperties:nil
                                                   launchOptions:launchOptions];

  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];
  [RNSplashScreen show];
  [Fabric with:@[[Crashlytics class]]];
  [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];

  return YES;
}

- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)token
{
  NSLog(@"Registration successful, bundle identifier: %@, mode: %@, device token: %@",
  [NSBundle.mainBundle bundleIdentifier], [self modeString], token);
  [RCTPushNotificationManager didRegisterForRemoteNotificationsWithDeviceToken:token];
}

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
//  [[RNFirebaseNotifications instance] didReceiveLocalNotification:notification];
  [RCTPushNotificationManager didReceiveLocalNotification:notification];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo
fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler {
//  [[RNFirebaseNotifications instance] didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
  [RCTPushNotificationManager didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}

- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
//  [[RNFirebaseMessaging instance] didRegisterUserNotificationSettings:notificationSettings];
  [RCTPushNotificationManager didRegisterUserNotificationSettings:notificationSettings];
}

- (void)userNotificationCenter:(UNUserNotificationCenter* )center willPresentNotification:(UNNotification* )notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
    //For notification Banner - when app in foreground
    completionHandler(UNNotificationPresentationOptionAlert);
    // Print Notification info
//     NSLog(@"Userinfo %@",notification.request.content.userInfo);
}

// Required for the registrationError event.
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
  [RCTPushNotificationManager didFailToRegisterForRemoteNotificationsWithError:error];
}

- (NSString *)modeString
{
#if DEBUG
  return @"Development (sandbox)";
#else
  return @"Production";
#endif
}

@end

Android

android/build.gradle:

buildscript {
    repositories {
        jcenter()
        maven {
            url 'https://maven.google.com/'
            name 'Google'
        }
        google()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.3'
        classpath 'com.google.gms:google-services:3.2.1'
        classpath "com.newrelic.agent.android:agent-gradle-plugin:5.17.2"

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

allprojects {
    repositories {
        google()
        // Add jitpack repository (added by react-native-spinkit)
        maven { url "https://jitpack.io" }
        mavenLocal()
        jcenter()
        maven {
            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
            url "$rootDir/../node_modules/react-native/android"
        }
        maven {
            url 'https://maven.google.com/'
            name 'Google'
        }
        maven { url 'https://mobile.useinsider.com'}
        mavenCentral()
    }
}

android/app/build.gradle:

// Firebase dependencies
    implementation 'com.google.firebase:firebase-core:16.0.6'
    implementation "com.google.android.gms:play-services-base:16.0.1"
    implementation "com.google.firebase:firebase-messaging:17.3.4"
    implementation "com.google.firebase:firebase-auth:16.0.5"
    implementation "com.google.firebase:firebase-firestore:17.1.3"
    implementation 'com.android.support:multidex:1.0.3'
    implementation 'com.google.android.gms:play-services-tagmanager:16.0.6'
    implementation 'com.google.android.gms:play-services-location:16.0.0'

android/settings.gradle:

rootProject.name = 'app'
include ':react-native-sentry'
project(':react-native-sentry').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sentry/android')
include ':react-native-branch'
project(':react-native-branch').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-branch/android')
native-firebase/android')
include ':react-native-firebase'
project(':react-native-firebase').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-firebase/android')
include ':react-native-splash-screen'
project(':react-native-splash-screen').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-splash-screen/android')
include ':react-native-photo-view'
project(':react-native-photo-view').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-photo-view/android')
include ':react-native-wheel-picker'
project(':react-native-wheel-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-wheel-picker/android')
include ':react-native-spinkit'
project(':react-native-spinkit').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-spinkit/android')
include ':react-native-blur'
project(':react-native-blur').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-blur/android')
include ':react-native-restart'
project(':react-native-restart').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-restart/android')
include ':react-native-vector-icons'
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
include ':react-native-i18n'
project(':react-native-i18n').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-i18n/android')
include ':react-native-config'
project(':react-native-config').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-config/android')
include ':react-native-fabric'
project(':react-native-fabric').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fabric/android')
include ':react-native-insider'
project(':react-native-insider').projectDir = new File(rootProject.projectDir,  '../node_modules/react-native-insider/android')
include ':app'

MainApplication.java:

package com.apparel.app;

import android.app.Application;

import com.facebook.react.ReactApplication;
import com.zyu.ReactNativeWheelPickerPackage;
import com.react.rnspinkit.RNSpinkitPackage;
import com.cmcewen.blurview.BlurViewPackage;
import org.devio.rn.splashscreen.SplashScreenReactPackage;
import com.avishayil.rnrestart.ReactNativeRestartPackage;
import com.oblador.vectoricons.VectorIconsPackage;
import com.AlexanderZaytsev.RNI18n.RNI18nPackage;
import com.lugg.ReactNativeConfig.ReactNativeConfigPackage;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import com.smixx.fabric.FabricPackage;
import com.reactnative.photoview.PhotoViewPackage;
import com.reactlibrary.RNInsiderPackage;
import io.sentry.RNSentryPackage;

import io.invertase.firebase.RNFirebasePackage;
import io.invertase.firebase.messaging.RNFirebaseMessagingPackage;
import io.invertase.firebase.notifications.RNFirebaseNotificationsPackage;
import io.invertase.firebase.auth.RNFirebaseAuthPackage;
import io.invertase.firebase.firestore.RNFirebaseFirestorePackage;
import io.invertase.firebase.analytics.RNFirebaseAnalyticsPackage;

import io.branch.rnbranch.RNBranchPackage;
import io.branch.referral.Branch;

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() {
      return Arrays.<ReactPackage>asList(
        new FabricPackage(),
        new MainReactPackage(),
        new SplashScreenReactPackage(),
        new ReactNativeWheelPickerPackage(),
        new RNSpinkitPackage(),
        new BlurViewPackage(),
        new ReactNativeRestartPackage(),
        new VectorIconsPackage(),
        new RNI18nPackage(),
        new ReactNativeConfigPackage(),
        new RNFirebasePackage(),
        new RNFirebaseMessagingPackage(),
        new RNFirebaseNotificationsPackage(),
        new RNFirebaseAuthPackage(),
        new RNFirebaseFirestorePackage(),
        new RNFirebaseAnalyticsPackage(),
        new PhotoViewPackage(),
        new RNInsiderPackage(),
        new RNBranchPackage(),
        new RNSentryPackage()
      );
    }

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

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

  @Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
    Branch.getAutoInstance(this);
  }
}

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.apparel.app"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.VIBRATE" />

    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="22" />

    <application
      android:name=".MainApplication"
      xmlns:tools="http://schemas.android.com/tools"
      android:supportsRtl="true"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:theme="@style/AppTheme">

        <service android:name="io.invertase.firebase.messaging.RNFirebaseMessagingService">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
        <service android:name="io.invertase.firebase.messaging.RNFirebaseInstanceIdService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
            </intent-filter>
        </service>

        <service android:name="io.invertase.firebase.messaging.RNFirebaseBackgroundMessagingService" />

        <receiver android:name="io.invertase.firebase.notifications.RNFirebaseNotificationReceiver"/>
        <receiver android:enabled="true" android:exported="true"  android:name="io.invertase.firebase.notifications.RNFirebaseNotificationsRebootReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <action android:name="android.intent.action.QUICKBOOT_POWERON"/>
                <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>

        <activity
        android:name=".MainActivity"
        android:screenOrientation="portrait"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
        android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="http" android:host="app" />
                <data android:scheme="http" android:host="en-ae.app.com" />
                <data android:scheme="http" android:host="ar-ae.app.com" />
                <data android:scheme="http" android:host="en-sa.app.com" />
                <data android:scheme="http" android:host="ar-sa.app.com" />
                <data android:scheme="https" />
            </intent-filter>

            <intent-filter android:label="filter_react_native">
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="app" />
            </intent-filter>

            <!-- Branch URI Scheme -->
            <intent-filter>
                <data android:scheme="app" />
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
            </intent-filter>

      </activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
        <meta-data
            android:name="io.fabric.ApiKey"
            android:value="key" />

        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="app-channel"/>

        <meta-data
            android:name="com.google.firebase.messaging.default_notification_icon"
            android:resource="@mipmap/ic_notification" />
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_color"
            android:resource="@color/gray_400" />

        <!-- Branch init -->
        <meta-data android:name="io.branch.sdk.BranchKey" android:value="@string/BRANCH_KEY" />
        <meta-data android:name="io.branch.sdk.BranchKey.test" android:value="@string/BRANCH_KEY_TEST" />
        <meta-data android:name="io.branch.sdk.TestMode" android:value="false" /> <!-- Set to true to use Branch_Test_Key -->

        <!-- Branch install referrer tracking (optional) -->
        <receiver android:name="io.branch.referral.InstallListener" android:exported="true">
            <intent-filter>
                <action android:name="com.android.vending.INSTALL_REFERRER" />
            </intent-filter>
        </receiver>
    </application>
</manifest>

Environment


Think react-native-firebase is great? Please consider supporting the project with any of the below:

smathson commented 5 years ago

I'm trying to track down the same issue. For us we are only missing the events on iOS, Android gets them just fine. Also, looking back through the data in the Firebase Console it looks like we've never gotten these automatic events for notifications on iOS and we've been using this lib since v3. Can anyone confirm that they do get the events on iOS?

LorandP commented 5 years ago

@smathson I can confirm that we receive these events in iOS. Our only problem is that we do not receive them all the time.

smathson commented 5 years ago

@LorandP Thank you, upgrading the Firebase SDK to 5.11.0 and re-enabling method swizzling solved our issue but events still don't seem completely reliable. As far as I can tell from tailing the logs, the Firebase SDK is getting all of the events as it should, they just aren't making their way to the console properly. I don't think this is an issue with this project, but rather an underlying issue with the Firebase SDK itself.

stale[bot] commented 5 years ago

Hello 👋, this issue has been automatically marked as stale because it has not had activity for quite some time. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 5 years ago

Closing this issue after a prolonged period of inactivity. If this is still present in the latest release, please feel free to create a new issue with up-to-date information.