Closed huyvvbka closed 5 months ago
Hello there.
It sounds like you're trying to get push notifications to show up on your iOS device, correct? The error message, "The operation couldn't be completed. No APNS token specified before fetching FCM Token" is an error that comes from the rnfirebase
SDK, not the Customer.io SDK.
The error message happens because rnfirebase
is not able to provide you with a FCM device token until it has been able to successfully receive a APN device token.
In order to have your app get a APN device token, you need to:
Could you verify for me that you have followed all of these steps?
If you have, could you please provide to me these files:
MyAppPushNotificationsHandler
AppDelegate.mm
ios/Podfile
ios/Podfile.lock
I understand these files might have sensitive information in them. You can send them to win@customer.io
instead of in this public github issue. If you do send the email, be sure to reference this github issue so the ticket can be routed to our team.
Thanks for contacting us today. Have a great day!
Thank you for your response.
The issue mentioned only occurs when I want to add the following code snippet to the file MyAppPushNotificationsHandler.swift:
MessagingPushAPN.initialize { config in
config.showPushAppInForeground = true // true will display the push when the app is in the foreground
}
In reality, I only receive notifications from Customer.io when the app is in the background. It doesn't work as expected when the app is in the foreground.
import Foundation
import CioMessagingPushAPN
import CioTracking
@objc
public class MyAppPushNotificationsHandler : NSObject {
public override init() {}
@objc(setupCustomerIOClickHandling)
public func setupCustomerIOClickHandling() {
// This line of code is required in order for the Customer.io SDK to handle push notification click events.
// We are working on removing this requirement in a future release.
// Remember to modify the siteId, apiKey and region with your own values.
CustomerIO.initialize(siteId: "my-siteId", apiKey: "my-apiKey", region: .US) { config in
}
MessagingPushAPN.initialize { config in
config.showPushAppInForeground = true // true will display the push when the app is in the foreground
}
}
@objc(application:deviceToken:)
public func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
MessagingPush.shared.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
}
@objc(application:error:)
public func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
MessagingPush.shared.application(application, didFailToRegisterForRemoteNotificationsWithError: error)
}
}
#import "AppDelegate.h"
#import "SampleApp-Swift.h"
#import <Firebase.h>
#import "RNBootSplash.h"
#import <RNGoogleSignin/RNGoogleSignin.h>
#import <React/RCTLinkingManager.h>
#import <AppCenterReactNative.h>
#import <AppCenterReactNativeAnalytics.h>
#import <AppCenterReactNativeCrashes.h>
#import "RNFBMessagingModule.h"
#import <React/RCTBundleURLProvider.h>
#import <AuthenticationServices/AuthenticationServices.h>
#import <SafariServices/SafariServices.h>
#import <FBAEMKit/FBAEMKit-Swift.h>
#import <FBSDKCoreKit/FBSDKCoreKit-Swift.h>
#import <CodePush/CodePush.h>
@implementation AppDelegate MyAppPushNotificationsHandler* pnHandlerObj = [[MyAppPushNotificationsHandler alloc] init];
(BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary )launchOptions { [FIRApp configure]; [FBSDKApplicationDelegate.sharedInstance initializeSDK]; [[FBSDKApplicationDelegate sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions]; self.moduleName = @"SampleApp"; // You can add your custom initial props in the dictionary below. // They will be passed down to the ViewController used by React Native. self.initialProps = [RNFBMessagingModule addCustomPropsToUserProps:nil withLaunchOptions:launchOptions];
[super application:application didFinishLaunchingWithOptions:launchOptions];
[application registerForRemoteNotifications]; [pnHandlerObj setupCustomerIOClickHandling];
[RNBootSplash initWithStoryboard:@"BootSplash" rootView:self.window.rootViewController.view]; // <- initialization using the storyboard file name
return YES; }
(NSURL )sourceURLForBridge:(RCTBridge )bridge {
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
return [CodePush bundleURL];
}
(BOOL)application:(UIApplication )app openURL:(NSURL )url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> )options { NSDictionary infoDict = [[NSBundle mainBundle] infoDictionary]; NSString* fbappid = [infoDict objectForKey:@"FacebookAppID"]; [FBAEMReporter configureWithNetworker:nil appID:fbappid reporter:nil]; [FBAEMReporter enable]; [FBAEMReporter handle:url];
if ([[FBSDKApplicationDelegate sharedInstance] application:app openURL:url options:options]) { return YES; }
if ([RNGoogleSignin application:app openURL:url options:options]) { return YES; }
if ([RCTLinkingManager application:app openURL:url options:options]) { return YES; }
return NO; }
(BOOL)application:(UIApplication )application continueUserActivity:(nonnull NSUserActivity )userActivity
restorationHandler:(nonnull void (^)(NSArray<id
// Required to register device token.
// Required for the registrationError event.
@end
- Podfile
def node_require(script)
require Pod::Executable.execute_command('node', ['-p', "require.resolve( '#{script}', {paths: [process.argv[1]]}, )", dir]).strip end
node_require('react-native/scripts/react_native_pods.rb') node_require('react-native-permissions/scripts/setup.rb')
platform :ios, '13.0' prepare_react_native_project!
setup_permissions([
'LocationAccuracy',
'LocationWhenInUse'
])
react-native-flipper
your iOS build will fail when NO_FLIPPER=1
is set.react-native-flipper
depends on (FlipperKit,...) that will be excluded#
react-native-flipper
using a react-native.config.js
flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled
linkage = ENV['USE_FRAMEWORKS'] if linkage != nil Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green use_frameworks! :linkage => :static end
target 'SampleApp' do config = use_native_modules!
flags = get_default_flags()
pod 'customerio-reactnative/apn', :path => '../node_modules/customerio-reactnative'
use_react_native!( :path => config[:reactNativePath],
# Upcoming versions of React Native may rely on get_default_flags(), but
# we make it explicit here to aid in the React Native upgrade process.
:hermes_enabled => true,
:fabric_enabled => false,
# Enables Flipper.
#
# Note that if you have use_frameworks! enabled, Flipper will not work and
# you should disable the next line.
:flipper_configuration => flipper_config,
# An absolute path to your application root.
:app_path => "#{Pod::Config.instance.installation_root}/.."
)
pod 'Firebase', :modular_headers => true pod 'FirebaseCoreInternal', :modular_headers => true pod 'GoogleUtilities', :modular_headers => true pod 'FirebaseCore', :modular_headers => true pod 'FirebaseCoreExtension', :modular_headers => true pod 'FirebaseABTesting', :modular_headers => true pod 'FirebaseInstallations', :modular_headers => true pod 'GoogleDataTransport', :modular_headers => true pod 'FirebaseSessions', :modular_headers => true pod 'nanopb', :modular_headers => true pod 'AppAuth', :modular_headers => true pod 'GTMSessionFetcher', :modular_headers => true
pod 'react-native-fbsdk-next', :path => '../node_modules/react-native-fbsdk-next' pod 'react-native-date-picker', :path => '../node_modules/react-native-date-picker' pod 'react-native-blob-util', :path => '../node_modules/react-native-blob-util'
target 'SampleAppTests' do inherit! :complete
end ENVFILES = { 'Prod' => '$(PODS_ROOT)/../../.env.production', }
post_install do |installer| react_native_post_install( installer, config[:reactNativePath], :mac_catalyst_enabled => false ) __apply_Xcode_12_5_M1_post_install_workaround(installer) installer.pods_project.targets.each do |target| target.build_configurations.each do |config| if target.name == 'react-native-config' config.build_settings['ENVFILE'] = ENVFILES[config.name] end end end end end
target 'ImageNotification' do pod 'Firebase', :modular_headers => true pod 'FirebaseCoreInternal', :modular_headers => true pod 'GoogleUtilities', :modular_headers => true pod 'FirebaseCore', :modular_headers => true pod 'FirebaseCoreExtension', :modular_headers => true pod 'Firebase/Messaging', :modular_headers => true # eg 6.31.0 end
target 'NotificationServiceExtension' do
pod 'customerio-reactnative-richpush/apn', :path => '../node_modules/customerio-reactnative' end
Thanks for giving additional information.
Could you please describe the issue that you're encountering? Sorry, I am not completely sure what it is.
I did notice something. It looks like you're using Firebase messaging for push notifications in your app, but you have the APN version of the Customer.io SDK installed in your app. Perhaps this is causing the issues for you? We give instructions in our documentation for FCM. If you are using FCM in your app for push notifications, I suggest following those instructions instead of the APN instructions.
I hope you have a great rest of your day!
Thank you, @levibostian , for your response.
I have re-implemented to receive notifications via FCM as instructed on customer.io. It works well when the application is in the background, but when it is in the foreground, it does not work at all as expected. I have checked extensively, but no notifications are received when in the foreground.
const unsubscribe = messaging().onMessage(async remoteMessage => {
console.log("remoteMessage:", remoteMessage)
});
messaging().onMessage does not trigger.
Please help me!
import Foundation
import CioMessagingPushFCM
import FirebaseMessaging
import CioTracking
@objc public class MyAppPushNotificationsHandler : NSObject {
public override init() {}
@objc(setupCustomerIOClickHandling) public func setupCustomerIOClickHandling() { // This line of code is required in order for the Customer.io SDK to handle push notification click events. // We are working on removing this requirement in a future release. // Remember to modify the siteId and apiKey with your own values. CustomerIO.initialize(siteId: "my-siteid", apiKey: "my-apikey", region: Region.US) { config in
// Automatically register push device tokens to the Customer.io SDK
config.autoTrackDeviceAttributes = true
// This is convenient for internal testing.
// It is optional.
config.logLevel = .debug
}
MessagingPushFCM.initialize {config in
config.showPushAppInForeground = true
}
}
// Register device on receiving a device token (FCM) @objc(didReceiveRegistrationToken:fcmToken:) public func didReceiveRegistrationToken(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { MessagingPush.shared.messaging(messaging, didReceiveRegistrationToken: fcmToken) } }
- AppDelegate
@implementation AppDelegate MyAppPushNotificationsHandler *pnHandlerObj = [[MyAppPushNotificationsHandler alloc] init];
(BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary )launchOptions {
self.moduleName = @"SampleApp"; // You can add your custom initial props in the dictionary below. // They will be passed down to the ViewController used by React Native. self.initialProps = [RNFBMessagingModule addCustomPropsToUserProps:nil withLaunchOptions:launchOptions];
[FIRApp configure]; [FIRMessaging messaging].delegate = self; [FBSDKApplicationDelegate.sharedInstance initializeSDK]; [[FBSDKApplicationDelegate sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];
[super application:application didFinishLaunchingWithOptions:launchOptions];
[pnHandlerObj setupCustomerIOClickHandling];
[RNBootSplash initWithStoryboard:@"BootSplash" rootView:self.window.rootViewController.view]; // <- initialization using the storyboard file name
return YES; }
(NSURL )sourceURLForBridge:(RCTBridge )bridge {
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
return [CodePush bundleURL];
}
(BOOL)application:(UIApplication )app openURL:(NSURL )url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> )options { NSDictionary infoDict = [[NSBundle mainBundle] infoDictionary]; NSString* fbappid = [infoDict objectForKey:@"FacebookAppID"]; [FBAEMReporter configureWithNetworker:nil appID:fbappid reporter:nil]; [FBAEMReporter enable]; [FBAEMReporter handle:url];
if ([[FBSDKApplicationDelegate sharedInstance] application:app openURL:url options:options]) { return YES; }
if ([RNGoogleSignin application:app openURL:url options:options]) { return YES; }
if ([RCTLinkingManager application:app openURL:url options:options]) { return YES; }
return NO; }
(BOOL)application:(UIApplication )application continueUserActivity:(nonnull NSUserActivity )userActivity
restorationHandler:(nonnull void (^)(NSArray<id
@end
- Podfile
def node_require(script)
require Pod::Executable.execute_command('node', ['-p', "require.resolve( '#{script}', {paths: [process.argv[1]]}, )", dir]).strip end
node_require('react-native/scripts/react_native_pods.rb') node_require('react-native-permissions/scripts/setup.rb')
platform :ios, '13.0' prepare_react_native_project! use_modular_headers!
setup_permissions([
'LocationAccuracy',
'LocationWhenInUse'
])
react-native-flipper
your iOS build will fail when NO_FLIPPER=1
is set.react-native-flipper
depends on (FlipperKit,...) that will be excluded#
react-native-flipper
using a react-native.config.js
flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled
linkage = ENV['USE_FRAMEWORKS'] if linkage != nil Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green use_frameworks! :linkage => :static end
target 'SampleApp' do config = use_native_modules!
flags = get_default_flags()
pod 'customerio-reactnative/fcm', :path => '../node_modules/customerio-reactnative'
use_react_native!( :path => config[:reactNativePath],
# Upcoming versions of React Native may rely on get_default_flags(), but
# we make it explicit here to aid in the React Native upgrade process.
:hermes_enabled => true,
:fabric_enabled => false,
# Enables Flipper.
#
# Note that if you have use_frameworks! enabled, Flipper will not work and
# you should disable the next line.
#:flipper_configuration => flipper_config,
# An absolute path to your application root.
:app_path => "#{Pod::Config.instance.installation_root}/.."
)
pod 'Firebase' pod 'FirebaseCoreInternal' pod 'GoogleUtilities' pod 'FirebaseCore' pod 'FirebaseCoreExtension' pod 'FirebaseABTesting' pod 'FirebaseInstallations' pod 'GoogleDataTransport' pod 'FirebaseSessions' pod 'nanopb' pod 'AppAuth' pod 'GTMSessionFetcher'
pod 'react-native-fbsdk-next', :path => '../node_modules/react-native-fbsdk-next' pod 'react-native-date-picker', :path => '../node_modules/react-native-date-picker' pod 'react-native-blob-util', :path => '../node_modules/react-native-blob-util'
target 'SampleAppTests' do inherit! :complete
end ENVFILES = { 'Prod' => '$(PODS_ROOT)/../../.env.production', }
post_install do |installer| react_native_post_install( installer, config[:reactNativePath], :mac_catalyst_enabled => false ) __apply_Xcode_12_5_M1_post_install_workaround(installer) installer.pods_project.targets.each do |target| target.build_configurations.each do |config| if target.name == 'react-native-config' config.build_settings['ENVFILE'] = ENVFILES[config.name] end end end end end
target 'ImageNotification' do pod 'Firebase', :modular_headers => true pod 'FirebaseCoreInternal', :modular_headers => true pod 'GoogleUtilities', :modular_headers => true pod 'FirebaseCore', :modular_headers => true pod 'FirebaseCoreExtension', :modular_headers => true pod 'Firebase/Messaging', :modular_headers => true # eg 6.31.0 end
target 'NotificationServiceExtension' do pod 'customerio-reactnative-richpush/fcm', :path => '../node_modules/customerio-reactnative' end
Thanks again for providing more information.
I am glad to hear that you are able to see push notifications while your app is in the background. In regards to push notifications not displaying while your app is in the foreground, this could be caused by this rnfirebase
behavior that does not display push notifications while app is in the foreground.
We do have a FCM sample app that does display push notifications sent from Customer.io when the app is in the foreground. The app also does use rnfirebase
including onMessage()
callback function.
I suggest reviewing the code in our sample app and comparing the app to your app's code. Make modifications to your app to more closely match the rnfirebase
setup that the sample app has.
I hope that this app is able to give you the details that you need to get this working. Have a great day!
Closing issue due to inactivity.
Feel free to add new comments and we would be happy to re-open and help.
SDK version: 3.7.0
Environment: Production
Describe the bug It appears that you're experiencing an issue with the rnfirebase library when using customer.io for push marketing notifications with APNS on iOS. Specifically, when you set config.showPushAppInForeground = true, you encounter the error message "The operation couldn't be completed. No APNS token specified before fetching FCM Token" when calling messaging().getToken() from Firebase. And foreground notification not working
Screenshots