Closed alperenkarip closed 8 months ago
Use the REST apis for FCM to post specific JSON to FCM with your device token so that you have control over the message
Make sure content-available is set to true in that JSON
Plug in the device and watch Console.app logs of the device when you send the message, it should show you the FCM JSON landing on the device via APNS
It will likely tell you why it is deciding not to deliver it to the app - usually something about power management and deciding that it doesn't want to waste the battery power of the device by letting your app run, since "content-available" messages are the only way to deliver things silently in the background and they are designed to be just to pre-cache content
The only reliable way to get FCM delivered is to have a notification block. data-only messages will always see hit or miss behavior like this. It likely works in your development setup because you use the app so often the device thinks it is worthy of spending battery power on a well-used app, but the TestFlight version doesn't have that history (and neither will your normal users) so it doesn't deliver to app
@mikehardy Thank you for your time, I tried again with fcm rest api as you said, but the result did not change. When I send the "notification" feature to the data I send, I get a notification, but when I remove it, unfortunately, the notification does not appear. Also, thinking that Testflight does not give priority to it, I tried again by building in release mode and publishing the application, the result is the same :(.
In kill state, you get a notification, but I don't think Notifee is working, firebase is sending notifications.
{
"priority":"HIGH",
"content_available": true,
"mutable_content":true,
"notification":{
"message":"s",
"title":"s",
"body":"s"
},
"data":{
"title":"xcTitlex",
"body":"Body",
"Message":"w",
"NotificationType":2,
"GivenName":"ALPEREN",
"FamilyName":"KARİP",
"ID":"2"
},
"to":"f6qTr9dl305vjPH2GT8LUx:APA91bGL_V-zKx2OBvSrkwZwVBHNzpqnBr9A2AgYxe5g4JfrmNKry9LcKm0lFzmte4iIeakesSPUV0MB_d7FlnGUIP7ripGc_Uz4dyZ7PI0QgFS-_KQRVRFpcc30ah5yo-rdyiGvaLlG"
}
Notifications only come if the application is in the background or in the foreground, but not in kill state.
{
"priority":"HIGH",
"content_available": true,
"mutable_content":true,
"data":{
"title":"xcTitlex",
"body":"Body",
"Message":"w",
"NotificationType":2,
"GivenName":"ALPEREN",
"FamilyName":"KARİP",
"ID":"2"
},
"to":"f6qTr9dl305vjPH2GT8LUx:APA91bGL_V-zKx2OBvSrkwZwVBHNzpqnBr9A2AgYxe5g4JfrmNKry9LcKm0lFzmte4iIeakesSPUV0MB_d7FlnGUIP7ripGc_Uz4dyZ7PI0QgFS-_KQRVRFpcc30ah5yo-rdyiGvaLlG"
}
RESULT
{ "multicast_id": 5178755344861181995, "success": 1, "failure": 0, "canonical_ids": 0, "results": [ { "message_id": "1702333746779856" } ] }
These two statements are the most important:
Plug in the device and watch Console.app logs of the device when you send the message, it should show you the FCM JSON landing on the device via APNS
and
The only reliable way to get FCM delivered is to have a notification block.
This is by Apple design. It is not in our control or your control
It appears based on commentary that the issue is more of a "wish", as in "I have this business requirement that is hard to meet based on operating system constraints and I wish it were possible..."
Unfortunately that doesn't make it actionable for the reasons I've laid out, and like all the other issues (about one a week on average...) that come in looking for reliable iOS deliver of data-only notifications, this is not actionable
Hello, everything works correctly in the development environment, but I cannot receive kill state notifications in the test flight. setBackgroundMessageHandler is not triggered. When I open the application, notifications start coming. I tried many solutions but none of them worked. I even wrote a module in setBackgroundMessageHandler that will leave a log in firestore every time it runs, but no recording occurs, when I try it in the development environment, a notification comes and it records in firestore. I decided to ask you as a last resort. What can I do about this issue?
Firebase Admin C#
```javascript var message = new MulticastMessage() { Tokens = registrationTokens, Android = new AndroidConfig() { Priority = Priority.High }, Apns = new ApnsConfig() { Headers = new Dictionary
{
["apns-priority"] = "10",
["apns-push-type"] = "background",
["apns-topic"] = "com.sabisv1"
},
Aps = new Aps()
{
ContentAvailable = true,
MutableContent = true,
Badge = 1,
Sound = "default"
},
},
Data = new Dictionary()
{
["title"] = request.Title,
["body"] = request.Body,
["ID"] = request.ID,
["notificationType"] = request.NotificationType.ToString(),
},
};
```
package.json
```javascript { "name": "sabisv1", "version": "0.0.1", "private": true, "scripts": { "android": "react-native run-android", "ios": "react-native run-ios", "lint": "eslint .", "start": "react-native start", "test": "jest", "check-dependencies": "rnx-align-deps", "fix-dependencies": "rnx-align-deps --write", "postinstall": "npx patch-package" }, "dependencies": { "react": "18.2.0", "react-native": "0.73.0", "@freakycoder/react-native-bounceable": "^1.0.3", "@notifee/react-native": "^7.8.0", "@react-native-async-storage/async-storage": "^1.17.11", "@react-native-community/datetimepicker": "^6.4.2", "@react-native-firebase/app": "^18.7.1", "@react-native-firebase/auth": "^18.7.1", "@react-native-firebase/firestore": "^18.7.1", "@react-native-firebase/messaging": "^18.7.1", "@react-native-firebase/remote-config": "^18.7.1", "@react-native-masked-view/masked-view": "^0.2.7", "@react-navigation/bottom-tabs": "^6.0.9", "@react-navigation/material-top-tabs": "^6.0.6", "@react-navigation/native": "^6.0.8", "@react-navigation/native-stack": "^6.0.2", "@react-navigation/stack": "^6.2.0", "@types/lodash": "^4.14.194", "apisauce": "2.1.6", "babel-plugin-transform-remove-console": "^6.9.4", "clsx": "^1.2.1", "dayjs": "^1.11.7", "geolib": "^3.3.3", "i18n-js": "3.8.0", "jwt-decode": "^3.1.2", "lodash": "^4.17.21", "mobx": "6.6.2", "mobx-react-lite": "3.4.0", "mobx-state-tree": "5.1.6", "nativewind": "^2.0.11", "react-native-accordion-list-view": "^2.0.1", "react-native-alert-notification": "^0.3.4", "react-native-animatable": "^1.3.3", "react-native-app-auth": "^7.1.0", "react-native-calendar-strip": "^2.2.5", "react-native-collapsible": "^1.6.0", "react-native-config": "^1.5.1", "react-native-device-info": "^10.3.0", "react-native-dropdown-picker": "^5.3.0", "react-native-dynamic-search-bar": "^2.0.2", "react-native-encrypted-storage": "^4.0.3", "react-native-fast-image": "^8.6.3", "react-native-geolocation-service": "^5.3.1", "react-native-gesture-handler": "^2.12.1", "react-native-inappbrowser-reborn": "^3.7.0", "react-native-indicators": "^0.17.0", "react-native-keychain": "8.1.1", "react-native-linear-gradient": "^2.6.2", "react-native-localization": "^2.3.1", "react-native-maps": "^1.7.1", "react-native-maps-directions": "^1.9.0", "react-native-pager-view": "^6.1.4", "react-native-paper": "^4.10.1", "react-native-reanimated": "^3.5.2", "react-native-safe-area-context": "^4.4.1", "react-native-safe-area-view": "^1.1.1", "react-native-screens": "^3.19.0", "react-native-shared-element": "0.8.4", "react-native-spinkit": "^1.5.1", "react-native-tab-view": "^3.1.1", "react-native-table-component": "^1.2.2", "react-native-vector-icons": "^9.2.0", "react-native-webview": "^11.23.0", "react-native-youtube-iframe": "^2.2.2", "react-navigation-shared-element": "^3.1.3", "rn-sliding-up-panel": "^2.4.6" }, "devDependencies": { "@babel/core": "^7.20.0", "@babel/preset-env": "^7.20.0", "@babel/runtime": "^7.20.0", "@react-native/babel-preset": "^0.73.18", "@react-native/eslint-config": "^0.73.1", "@react-native/metro-config": "^0.73.2", "@react-native/typescript-config": "^0.73.1", "@types/react": "^18.2.6", "@types/react-test-renderer": "^18.0.0", "babel-jest": "^29.6.3", "eslint": "^8.19.0", "jest": "^29.6.3", "prettier": "2.8.8", "react-test-renderer": "18.2.0", "typescript": "5.0.4", "@rnx-kit/align-deps": "^2.2.2", "@types/i18n-js": "3.8.3", "@types/metro-config": "^0.76.3", "@types/react-native": "~0.70.6", "@types/react-native-indicators": "^0.16.2", "@types/react-native-vector-icons": "^6.4.13", "@typescript-eslint/eslint-plugin": "^5.17.0", "@typescript-eslint/parser": "^5.17.0", "tailwindcss": "3.3.2" }, "engines": { "node": ">=18" }, "rnx-kit": { "kitType": "app", "alignDeps": { "requirements": [ "react-native@0.71" ], "capabilities": [ "animation", "babel-preset-react-native", "core", "core-android", "core-ios", "datetime-picker", "gestures", "jest", "navigation/native", "navigation/stack", "react", "react-dom", "react-test-renderer", "safe-area", "screens", "storage" ] } } } ```
podfile
```javascript # Resolve react_native_pods.rb with node to allow for hoisting require Pod::Executable.execute_command('node', ['-p', 'require.resolve( "react-native/scripts/react_native_pods.rb", {paths: [process.argv[1]]}, )', __dir__]).strip platform :ios, min_ios_version_supported prepare_react_native_project! linkage = ENV['USE_FRAMEWORKS'] if linkage != nil Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green use_frameworks! :linkage => linkage.to_sym end target 'sabisv1' do config = use_native_modules! use_frameworks! :linkage => :static $RNFirebaseAsStaticFramework = true pod 'Firebase' pod 'FirebaseCore' pod 'FirebaseCoreInternal' pod 'GoogleUtilities' pod 'FirebaseCoreExtension' pod 'FirebaseFirestoreInternal' pod 'FirebaseABTesting' pod 'FirebaseInstallations' pod 'FirebaseFirestore' pod 'FirebaseMessaging' pod 'FirebaseRemoteConfig' pod 'FirebaseAuth' pod 'react-native-config', :path => '../node_modules/react-native-config' pod 'react-native-config/Extension', :path => '../node_modules/react-native-config' # react-native-maps dependencies pod 'react-native-maps', path: '../node_modules/react-native-maps' pod 'react-native-google-maps', path: '../node_modules/react-native-maps' pod 'GoogleMaps' pod 'Google-Maps-iOS-Utils' use_react_native!( :path => config[:reactNativePath], # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/.." ) $FirebaseSDKVersion = '10.17.0' # for Firebase target 'sabisv1Tests' do inherit! :complete # Pods for testing end post_install do |installer| # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 react_native_post_install( installer, config[:reactNativePath], :mac_catalyst_enabled => false ) end end ```
info.plist
```javascript
BGTaskSchedulerPermittedIdentifiers
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleDevelopmentRegion
en
CFBundleDisplayName
SABİS
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
APPL
CFBundleShortVersionString
$(MARKETING_VERSION)
CFBundleSignature
????
CFBundleURLTypes
CFBundleURLName
com.sabisv1
CFBundleURLSchemes
com.sabisv1
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
FirebaseAppDelegateProxyEnabled
NSLocationAlwaysAndWhenInUseUsageDescription
We use our university API services in order to provide accurate information to our university students.
LSRequiresIPhoneOS
NSAppTransportSecurity
NSAllowsArbitraryLoads
NSAllowsLocalNetworking
NSLocationWhenInUseUsageDescription
You will get zero benefit allowing this app accessing your location. You should never see this alert. If you do alert technical support at destek@sabis.sakarya.edu.tr
UIAppFonts
Muli-ExtraBold.ttf
Muli-Regular.ttf
Muli-Black.ttf
Muli-BlackItalic.ttf
Muli-Bold.ttf
Muli-BoldItalic.ttf
Muli-ExtraBoldItalic.ttf
Muli-ExtraLight.ttf
Muli-ExtraLightItalic.ttf
Muli-Italic.ttf
Muli-Light.ttf
Muli-LightItalic.ttf
Muli-SemiBold.ttf
Muli-SemiBoldItalic.ttf
AntDesign.ttf
Entypo.ttf
EvilIcons.ttf
Feather.ttf
FontAwesome.ttf
FontAwesome5_Brands.ttf
FontAwesome5_Regular.ttf
FontAwesome5_Solid.ttf
Fontisto.ttf
Foundation.ttf
Ionicons.ttf
MaterialCommunityIcons.ttf
MaterialIcons.ttf
Octicons.ttf
SimpleLineIcons.ttf
Zocial.ttf
UIBackgroundModes
fetch
processing
remote-notification
UILaunchStoryboardName
LaunchScreen
UIRequiredDeviceCapabilities
armv7
UIRequiresFullScreen
UIStatusBarStyle
UIStatusBarStyleDefault
UIUserInterfaceStyle
Light
UIViewControllerBasedStatusBarAppearance
```
appdelegate.m
```javascript //
#import "AppDelegate.h"
#import // for Firebase
#import
#import //v
#import "RNCConfig.h"
#import "RNFBMessagingModule.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[FIRApp configure]; //for Firebase
[GMSServices provideAPIKey:@"AIzaSyDooFj9tsiEjseKeo544X7Xs7z5ca89P_Q"];
self.moduleName = @"sabisv1";
self.initialProps = [RNFBMessagingModule addCustomPropsToUserProps:nil withLaunchOptions:launchOptions];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken: (NSData *)deviceToken
{
[FIRMessaging messaging].APNSToken = deviceToken;
NSString *fcmToken = [FIRMessaging messaging].FCMToken;
NSLog(@"++APNST deviceToken : %@", deviceToken);
NSLog(@"++FCM device token : %@", fcmToken);
}
- (BOOL) application: (UIApplication *)application
openURL: (NSURL *)url
options: (NSDictionary *) options
{
if ([self.authorizationFlowManagerDelegate resumeExternalUserAgentFlowWithURL:url]) {
return YES;
}
return [RCTLinkingManager application:application openURL:url options:options];
}
- (BOOL) application: (UIApplication *) application
continueUserActivity: (nonnull NSUserActivity *)userActivity
restorationHandler: (nonnull void (^)(NSArray> * _Nullable))restorationHandler
{
if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
if (self.authorizationFlowManagerDelegate) {
BOOL resumableAuth = [self.authorizationFlowManagerDelegate resumeExternalUserAgentFlowWithURL:userActivity.webpageURL];
if (resumableAuth) {
return YES;
}
}
}
return [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
return [self getBundleURL];
}
- (NSURL *)getBundleURL
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
@end
```
index.js
```javascript import {AppRegistry} from 'react-native'; import App from './app/app.tsx'; import {name as appName} from './app.json'; import messaging from '@react-native-firebase/messaging'; import NotifeeManager from './app/components/notification-manager/notifee-manager'; import notifee from '@notifee/react-native'; import firestoreManager from './app/components/notification-manager/firestore-manager'; function HeadlessCheck({isHeadless}) { if (isHeadless) { return null; } return ;
}
notifee.onBackgroundEvent(async ({type, detail}) => {
const {notification, pressAction} = detail;
console.log('NOTIFEE BACKGROUNDEVENT', type);
});
messaging().setBackgroundMessageHandler(async remoteMessage => {
console.log('FIREBASE BACKGROUND MESSAGE');
firestoreManager.saveNotificationLogToFirestore(
'FIREBASE BACKGROUND MESSAGE',
JSON.stringify(remoteMessage),
);
await NotifeeManager.onMessageReceived(remoteMessage);
});
AppRegistry.registerComponent(appName, () => HeadlessCheck);
```