feat(messaging): ios & android messaging updates & fixes (#3339)

See PR #3339 for changes.

Co-authored-by: Salakar <mike.diarmid@gmail.com>
This commit is contained in:
Elliot Hesp
2020-03-27 00:06:30 +00:00
committed by GitHub
parent d65e6341a4
commit d66a6118f8
51 changed files with 1285 additions and 861 deletions

4
.gitignore vendored
View File

@@ -550,3 +550,7 @@ GoogleService-Info.plist
# generated file
RNFBVersion.m
app.playground.js
app.admob.js
app.smartreply.js

View File

@@ -45,6 +45,7 @@
"cross-env": "^5.2.0",
"eslint": "^6.1.0",
"flow-bin": "^0.100.0",
"firebase-admin": "^8.10.0",
"genversion": "^2.1.1",
"husky": "^1.3.1",
"lerna": "3.17.0",

View File

@@ -29,7 +29,7 @@
"peerDependencies": {
"@react-native-firebase/app": "*"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -24,7 +24,7 @@
"peerDependencies": {
"@react-native-firebase/app": "*"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -13,7 +13,7 @@
"url": "https://github.com/invertase/react-native-firebase/tree/master/packages/app-types"
},
"license": "Apache-2.0",
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -61,7 +61,7 @@
"type": "opencollective",
"url": "https://opencollective.com/react-native-firebase"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -24,7 +24,7 @@
"peerDependencies": {
"@react-native-firebase/app": "*"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -32,7 +32,7 @@
"dependencies": {
"stacktrace-js": "^2.0.0"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -27,7 +27,7 @@
"peerDependencies": {
"@react-native-firebase/app": "*"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -25,7 +25,7 @@
"peerDependencies": {
"@react-native-firebase/app": "*"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -29,7 +29,7 @@
"peerDependencies": {
"@react-native-firebase/app": "*"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -29,7 +29,7 @@
"devDependencies": {
"@react-native-firebase/private-tests-firebase-functions": "^0.0.1"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -26,7 +26,7 @@
"peerDependencies": {
"@react-native-firebase/app": "*"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -29,7 +29,7 @@
"peerDependencies": {
"@react-native-firebase/app": "*"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -40,16 +40,17 @@ project.ext {
apply from: file("./../../app/android/firebase-json.gradle")
def autoInitEnabled = "true"
def defaultNotificationChannelId = ""
def defaultNotificationColor = ""
def notificationChannelId = ""
def defaultNotificationColor = "@color/white";
def notificationColor = defaultNotificationColor
if (rootProject.ext && rootProject.ext.firebaseJson) {
if (rootProject.ext.firebaseJson.isFlagEnabled("messaging_auto_init_enabled") == false) {
autoInitEnabled = "false"
}
defaultNotificationChannelId = rootProject.ext.firebaseJson.getStringValue("messaging_android_notification_channel_id", "")
defaultNotificationColor = rootProject.ext.firebaseJson.getStringValue("messaging_android_notification_color", "")
notificationChannelId = rootProject.ext.firebaseJson.getStringValue("messaging_android_notification_channel_id", "")
notificationColor = rootProject.ext.firebaseJson.getStringValue("messaging_android_notification_color", defaultNotificationColor)
}
android {
@@ -57,8 +58,8 @@ android {
multiDexEnabled true
manifestPlaceholders = [
firebaseJsonAutoInitEnabled: autoInitEnabled,
firebaseJsonNotificationChannelId: defaultNotificationChannelId,
firebaseJsonNotificationColor: defaultNotificationColor
firebaseJsonNotificationChannelId: notificationChannelId,
firebaseJsonNotificationColor: notificationColor
]
}
lintOptions {

View File

@@ -129,7 +129,7 @@ public class ReactNativeFirebaseMessagingModule extends ReactNativeFirebaseModul
.call(getExecutor(), () -> NotificationManagerCompat.from(getReactApplicationContext()).areNotificationsEnabled())
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
promise.resolve(task.getResult());
promise.resolve(task.getResult() ? 1 : 0);
} else {
rejectPromiseWithExceptionMap(promise, task.getException());
}

View File

@@ -34,6 +34,86 @@ describe('messaging()', () => {
return Promise.resolve();
}
});
it('sets the value', async () => {
should.equal(firebase.messaging().isAutoInitEnabled, true);
await firebase.messaging().setAutoInitEnabled(false);
should.equal(firebase.messaging().isAutoInitEnabled, false);
});
});
describe('isDeviceRegisteredForRemoteMessages', () => {
android.it('returns true on android', () => {
should.equal(firebase.messaging().isDeviceRegisteredForRemoteMessages, true);
// check deprecated method also
should.equal(firebase.messaging().isRegisteredForRemoteNotifications, true);
});
it('defaults to false on ios before registering', () => {
if (device.getPlatform() === 'ios') {
should.equal(firebase.messaging().isDeviceRegisteredForRemoteMessages, false);
// check deprecated method also
should.equal(firebase.messaging().isRegisteredForRemoteNotifications, false);
}
});
});
describe('unregisterDeviceForRemoteMessages', () => {
android.it('resolves on android', async () => {
await firebase.messaging().unregisterDeviceForRemoteMessages();
// check deprecated method also
await firebase.messaging().unregisterForRemoteNotifications();
});
});
describe('hasPermission', () => {
android.it('returns true android (default)', async () => {
should.equal(await firebase.messaging().hasPermission(), true);
});
it('returns -1 on ios (default)', async () => {
if (device.getPlatform() === 'ios') {
should.equal(await firebase.messaging().hasPermission(), -1);
}
});
});
describe('unregisterDeviceForRemoteMessages', () => {
android.it('resolves on android', async () => {
await firebase.messaging().unregisterDeviceForRemoteMessages();
// check deprecated method also
await firebase.messaging().unregisterForRemoteNotifications();
});
});
describe('requestPermission', () => {
android.it('resolves 1 on android', async () => {
should.equal(await firebase.messaging().requestPermission(), 1);
});
});
describe('getAPNSToken', () => {
android.it('resolves null on android', async () => {
should.equal(await firebase.messaging().getAPNSToken(), null);
});
it('resolves null on ios if using simulator', async () => {
if (device.getPlatform() === 'ios') {
should.equal(await firebase.messaging().getAPNSToken(), null);
}
});
});
describe('unsupported web sdk methods', () => {
it('useServiceWorker should not error when called', () => {
firebase.messaging().useServiceWorker();
});
it('usePublicVapidKey should not error when called', () => {
firebase.messaging().usePublicVapidKey();
});
});
describe('getInitialNotification', () => {
it('returns null when no initial notification', async () => {
should.equal(await firebase.messaging().getInitialNotification(), null);
});
});
describe('getToken()', () => {
@@ -91,9 +171,14 @@ describe('messaging()', () => {
}
});
android.it('receives messages when the app is in the foreground', async () => {
it('receives messages when the app is in the foreground', async () => {
const spy = sinon.spy();
const unsubscribe = firebase.messaging().onMessage(spy);
if (device.getPlatform() === 'ios') {
await firebase.messaging().registerDeviceForRemoteMessages();
// call deprecated method also
await firebase.messaging().registerForRemoteNotifications();
}
const token = await firebase.messaging().getToken();
await TestsAPI.messaging().sendToDevice(token, {
data: {

View File

@@ -8,9 +8,11 @@
/* Begin PBXBuildFile section */
2744B98621F45429004F8E3F /* RNFBMessagingModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBMessagingModule.m */; };
DA26951322C6AFFC00241B22 /* RNFBMessagingDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DA26951222C6AFFC00241B22 /* RNFBMessagingDelegate.m */; };
27F24640242AA29F0098906C /* RNFBMessaging+UNUserNotificationCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F2463F242AA29E0098906C /* RNFBMessaging+UNUserNotificationCenter.m */; };
27F24643242AA2EE0098906C /* RNFBMessaging+AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F24642242AA2EE0098906C /* RNFBMessaging+AppDelegate.m */; };
27F24646242AA30E0098906C /* RNFBMessaging+FIRMessagingDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F24645242AA30E0098906C /* RNFBMessaging+FIRMessagingDelegate.m */; };
27F2464D242AA7330098906C /* RNFBMessaging+NSNotificationCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F2464C242AA7330098906C /* RNFBMessaging+NSNotificationCenter.m */; };
DA446E5222CA48690066A0A3 /* RNFBMessagingSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA446E5122CA48690066A0A3 /* RNFBMessagingSerializer.m */; };
DA446E5522CA4FB30066A0A3 /* RNFBMessagingAppDelegateInterceptor.m in Sources */ = {isa = PBXBuildFile; fileRef = DA446E5422CA4FB30066A0A3 /* RNFBMessagingAppDelegateInterceptor.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -29,12 +31,16 @@
2744B98221F45429004F8E3F /* libRNFBMessaging.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFBMessaging.a; sourceTree = BUILT_PRODUCTS_DIR; };
2744B98421F45429004F8E3F /* RNFBMessagingModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBMessagingModule.h; path = RNFBMessaging/RNFBMessagingModule.h; sourceTree = SOURCE_ROOT; };
2744B98521F45429004F8E3F /* RNFBMessagingModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBMessagingModule.m; path = RNFBMessaging/RNFBMessagingModule.m; sourceTree = SOURCE_ROOT; };
DA26951222C6AFFC00241B22 /* RNFBMessagingDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBMessagingDelegate.m; sourceTree = "<group>"; };
DA26951422C6B00A00241B22 /* RNFBMessagingDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBMessagingDelegate.h; sourceTree = "<group>"; };
27F2463E242AA29E0098906C /* RNFBMessaging+UNUserNotificationCenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RNFBMessaging+UNUserNotificationCenter.h"; sourceTree = "<group>"; };
27F2463F242AA29E0098906C /* RNFBMessaging+UNUserNotificationCenter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "RNFBMessaging+UNUserNotificationCenter.m"; sourceTree = "<group>"; };
27F24641242AA2EE0098906C /* RNFBMessaging+AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RNFBMessaging+AppDelegate.h"; sourceTree = "<group>"; };
27F24642242AA2EE0098906C /* RNFBMessaging+AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "RNFBMessaging+AppDelegate.m"; sourceTree = "<group>"; };
27F24644242AA30E0098906C /* RNFBMessaging+FIRMessagingDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RNFBMessaging+FIRMessagingDelegate.h"; sourceTree = "<group>"; };
27F24645242AA30E0098906C /* RNFBMessaging+FIRMessagingDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "RNFBMessaging+FIRMessagingDelegate.m"; sourceTree = "<group>"; };
27F2464B242AA7330098906C /* RNFBMessaging+NSNotificationCenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RNFBMessaging+NSNotificationCenter.h"; sourceTree = "<group>"; };
27F2464C242AA7330098906C /* RNFBMessaging+NSNotificationCenter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "RNFBMessaging+NSNotificationCenter.m"; sourceTree = "<group>"; };
DA446E5022CA485C0066A0A3 /* RNFBMessagingSerializer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBMessagingSerializer.h; sourceTree = "<group>"; };
DA446E5122CA48690066A0A3 /* RNFBMessagingSerializer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBMessagingSerializer.m; sourceTree = "<group>"; };
DA446E5322CA4F2E0066A0A3 /* RNFBMessagingAppDelegateInterceptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBMessagingAppDelegateInterceptor.h; sourceTree = "<group>"; };
DA446E5422CA4FB30066A0A3 /* RNFBMessagingAppDelegateInterceptor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBMessagingAppDelegateInterceptor.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -61,12 +67,16 @@
children = (
2744B98421F45429004F8E3F /* RNFBMessagingModule.h */,
2744B98521F45429004F8E3F /* RNFBMessagingModule.m */,
DA26951222C6AFFC00241B22 /* RNFBMessagingDelegate.m */,
DA26951422C6B00A00241B22 /* RNFBMessagingDelegate.h */,
DA446E5022CA485C0066A0A3 /* RNFBMessagingSerializer.h */,
DA446E5122CA48690066A0A3 /* RNFBMessagingSerializer.m */,
DA446E5322CA4F2E0066A0A3 /* RNFBMessagingAppDelegateInterceptor.h */,
DA446E5422CA4FB30066A0A3 /* RNFBMessagingAppDelegateInterceptor.m */,
27F2463E242AA29E0098906C /* RNFBMessaging+UNUserNotificationCenter.h */,
27F2463F242AA29E0098906C /* RNFBMessaging+UNUserNotificationCenter.m */,
27F24641242AA2EE0098906C /* RNFBMessaging+AppDelegate.h */,
27F24642242AA2EE0098906C /* RNFBMessaging+AppDelegate.m */,
27F24644242AA30E0098906C /* RNFBMessaging+FIRMessagingDelegate.h */,
27F24645242AA30E0098906C /* RNFBMessaging+FIRMessagingDelegate.m */,
27F2464B242AA7330098906C /* RNFBMessaging+NSNotificationCenter.h */,
27F2464C242AA7330098906C /* RNFBMessaging+NSNotificationCenter.m */,
);
path = RNFBMessaging;
sourceTree = "<group>";
@@ -139,9 +149,11 @@
buildActionMask = 2147483647;
files = (
2744B98621F45429004F8E3F /* RNFBMessagingModule.m in Sources */,
DA446E5522CA4FB30066A0A3 /* RNFBMessagingAppDelegateInterceptor.m in Sources */,
27F24643242AA2EE0098906C /* RNFBMessaging+AppDelegate.m in Sources */,
27F24640242AA29F0098906C /* RNFBMessaging+UNUserNotificationCenter.m in Sources */,
DA446E5222CA48690066A0A3 /* RNFBMessagingSerializer.m in Sources */,
DA26951322C6AFFC00241B22 /* RNFBMessagingDelegate.m in Sources */,
27F2464D242AA7330098906C /* RNFBMessaging+NSNotificationCenter.m in Sources */,
27F24646242AA30E0098906C /* RNFBMessaging+FIRMessagingDelegate.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -15,21 +15,20 @@
*
*/
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <Firebase/Firebase.h>
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
NS_ASSUME_NONNULL_BEGIN
@interface RNFBMessagingAppDelegateInterceptor : NSObject <UIApplicationDelegate>
@interface RNFBMessagingAppDelegate : NSObject <UIApplicationDelegate>
@property _Nullable RCTPromiseRejectBlock registerPromiseRejecter;
@property _Nullable RCTPromiseResolveBlock registerPromiseResolver;
+ (instancetype)sharedInstance;
+ (_Nonnull instancetype)sharedInstance;
- (void)observe;
- (void)setPromiseResolve:(RCTPromiseResolveBlock)resolve andPromiseReject:(RCTPromiseRejectBlock)reject;
@@ -37,8 +36,6 @@ NS_ASSUME_NONNULL_BEGIN
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error;
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo;
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler;
@end

View File

@@ -0,0 +1,123 @@
/**
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <objc/runtime.h>
#import <Firebase/Firebase.h>
#import <GoogleUtilities/GULAppDelegateSwizzler.h>
#import <React/RCTConvert.h>
#import <RNFBApp/RNFBSharedUtils.h>
#import <RNFBApp/RNFBRCTEventEmitter.h>
#import "RNFBMessagingSerializer.h"
#import "RNFBMessaging+AppDelegate.h"
@implementation RNFBMessagingAppDelegate
+ (instancetype)sharedInstance {
static dispatch_once_t once;
__strong static RNFBMessagingAppDelegate *sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[RNFBMessagingAppDelegate alloc] init];
});
return sharedInstance;
}
- (void)observe {
static dispatch_once_t once;
__weak RNFBMessagingAppDelegate *weakSelf = self;
dispatch_once(&once, ^{
RNFBMessagingAppDelegate *strongSelf = weakSelf;
[GULAppDelegateSwizzler registerAppDelegateInterceptor:strongSelf];
[GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods];
SEL didReceiveRemoteNotificationWithCompletionSEL =
NSSelectorFromString(@"application:didReceiveRemoteNotification:fetchCompletionHandler:");
if ([[GULAppDelegateSwizzler sharedApplication].delegate respondsToSelector:didReceiveRemoteNotificationWithCompletionSEL]) {
// noop - user has own implementation of this method in their AppDelegate, this
// means GULAppDelegateSwizzler will have already replaced it with a donor method
} else {
// add our own donor implementation of application:didReceiveRemoteNotification:fetchCompletionHandler:
Method donorMethod = class_getInstanceMethod(
object_getClass(strongSelf), didReceiveRemoteNotificationWithCompletionSEL
);
class_addMethod(
object_getClass([GULAppDelegateSwizzler sharedApplication].delegate),
didReceiveRemoteNotificationWithCompletionSEL,
method_getImplementation(donorMethod),
method_getTypeEncoding(donorMethod)
);
}
});
}
// used to temporarily store a promise instance to resolve calls to `registerForRemoteNotifications`
- (void)setPromiseResolve:(RCTPromiseResolveBlock)resolve andPromiseReject:(RCTPromiseRejectBlock)reject {
_registerPromiseResolver = resolve;
_registerPromiseRejecter = reject;
}
#pragma mark -
#pragma mark AppDelegate Methods
// called when `registerForRemoteNotifications` completes successfully
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
#ifdef DEBUG
[[FIRMessaging messaging] setAPNSToken:deviceToken type:FIRMessagingAPNSTokenTypeSandbox];
#else
[[FIRMessaging messaging] setAPNSToken:deviceToken type:FIRMessagingAPNSTokenTypeProd];
#endif
if (_registerPromiseResolver != nil) {
_registerPromiseResolver(@([RCTConvert BOOL:@([UIApplication sharedApplication].isRegisteredForRemoteNotifications)]));
_registerPromiseResolver = nil;
_registerPromiseRejecter = nil;
}
}
// called when `registerForRemoteNotifications` fails to complete
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
if (_registerPromiseRejecter != nil) {
[RNFBSharedUtils rejectPromiseWithNSError:_registerPromiseRejecter error:error];
_registerPromiseResolver = nil;
_registerPromiseRejecter = nil;
}
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
if (userInfo[@"gcm.message_id"]) {
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
// TODO add support in a later version for calling completion handler directly from JS when user JS code complete
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (25 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
completionHandler(UIBackgroundFetchResultNewData);
});
// TODO investigate later - RN bridge gets invalidated at start when in background and a new bridge created - losing all events
// TODO so we just delay sending the event for a few seconds as a workaround
// TODO most likely Remote Debugging causing bridge to be invalidated
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_message_received_background" body:[RNFBMessagingSerializer remoteMessageUserInfoToDict:userInfo]];
});
} else {
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_message_received" body:[RNFBMessagingSerializer remoteMessageUserInfoToDict:userInfo]];
completionHandler(UIBackgroundFetchResultNoData);
}
}
}
@end

View File

@@ -16,12 +16,16 @@
*/
#import <Foundation/Foundation.h>
#import <Firebase/Firebase.h>
#import <React/RCTBridgeModule.h>
@interface RNFBMessagingDelegate : NSObject <FIRMessagingDelegate, UNUserNotificationCenterDelegate>
NS_ASSUME_NONNULL_BEGIN
+ (_Nonnull instancetype) sharedInstance;
@interface RNFBMessagingFIRMessagingDelegate : NSObject <FIRMessagingDelegate>
@end
+ (_Nonnull instancetype)sharedInstance;
- (void)observe;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,80 @@
/**
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <objc/runtime.h>
#import <objc/message.h>
#import <RNFBApp/RNFBRCTEventEmitter.h>
#import <GoogleUtilities/GULAppDelegateSwizzler.h>
#import "RNFBMessaging+FIRMessagingDelegate.h"
#import "RNFBMessagingSerializer.h"
@implementation RNFBMessagingFIRMessagingDelegate
+ (instancetype)sharedInstance {
static dispatch_once_t once;
__strong static RNFBMessagingFIRMessagingDelegate *sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[RNFBMessagingFIRMessagingDelegate alloc] init];
});
return sharedInstance;
}
- (void)observe {
static dispatch_once_t once;
__weak RNFBMessagingFIRMessagingDelegate *weakSelf = self;
dispatch_once(&once, ^{
RNFBMessagingFIRMessagingDelegate *strongSelf = weakSelf;
[FIRMessaging messaging].delegate = strongSelf;
[FIRMessaging messaging].shouldEstablishDirectChannel = YES;
});
}
#pragma mark -
#pragma mark FIRMessagingDelegate Methods
// JS -> `onTokenRefresh`
- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_token_refresh" body:@{
@"token": fcmToken
}];
// If the users AppDelegate implements messaging:didReceiveRegistrationToken: then call it
SEL messaging_didReceiveRegistrationTokenSelector =
NSSelectorFromString(@"messaging:didReceiveRegistrationToken:");
if ([[GULAppDelegateSwizzler sharedApplication].delegate respondsToSelector:messaging_didReceiveRegistrationTokenSelector]) {
void (*usersDidReceiveRegistrationTokenIMP)(id, SEL, FIRMessaging *, NSString *) = (typeof(usersDidReceiveRegistrationTokenIMP)) &objc_msgSend;
usersDidReceiveRegistrationTokenIMP([GULAppDelegateSwizzler sharedApplication].delegate, messaging_didReceiveRegistrationTokenSelector, messaging, fcmToken);
}
}
// JS -> `onMessage`
// Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground.
// To enable direct data messages, you can set [Messaging messaging].shouldEstablishDirectChannel to YES.
- (void)messaging:(nonnull FIRMessaging *)messaging didReceiveMessage:(nonnull FIRMessagingRemoteMessage *)remoteMessage {
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_message_received" body:[RNFBMessagingSerializer remoteMessageToDict:remoteMessage]];
// If the users AppDelegate implements messaging:didReceiveMessage: then call it
SEL messaging_didReceiveMessageSelector =
NSSelectorFromString(@"messaging:didReceiveMessage:");
if ([[GULAppDelegateSwizzler sharedApplication].delegate respondsToSelector:messaging_didReceiveMessageSelector]) {
void (*usersDidReceiveMessageIMP)(id, SEL, FIRMessaging *, FIRMessagingRemoteMessage *) = (typeof(usersDidReceiveMessageIMP)) &objc_msgSend;
usersDidReceiveMessageIMP([GULAppDelegateSwizzler sharedApplication].delegate, messaging_didReceiveMessageSelector, messaging, remoteMessage);
}
}
@end

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface RNFBMessagingNSNotificationCenter : NSObject
+ (_Nonnull instancetype)sharedInstance;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,176 @@
/**
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <Firebase/Firebase.h>
#import <React/RCTRootView.h>
#import <React/RCTConvert.h>
#import <RNFBApp/RNFBRCTEventEmitter.h>
#import "RNFBMessaging+AppDelegate.h"
#import "RNFBMessaging+NSNotificationCenter.h"
#import "RNFBMessaging+UNUserNotificationCenter.h"
#import "RNFBMessaging+FIRMessagingDelegate.h"
@implementation RNFBMessagingNSNotificationCenter
+ (instancetype)sharedInstance {
static dispatch_once_t once;
__strong static RNFBMessagingNSNotificationCenter *sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[RNFBMessagingNSNotificationCenter alloc] init];
});
return sharedInstance;
}
- (void)observe {
static dispatch_once_t once;
__weak RNFBMessagingNSNotificationCenter *weakSelf = self;
dispatch_once(&once, ^{
RNFBMessagingNSNotificationCenter *strongSelf = weakSelf;
// Application
// JS -> `getInitialNotification`
// ObjC -> Initialize other delegates & observers
[[NSNotificationCenter defaultCenter] addObserver:strongSelf selector:@selector(application_onDidFinishLaunchingNotification:) name:UIApplicationDidFinishLaunchingNotification object:nil];
// Application
// ObjC - > Mutates the root React components initialProps to toggle `isHeadless` state
[[NSNotificationCenter defaultCenter] addObserver:strongSelf selector:@selector(application_onDidEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
// Firebase Messaging
// JS -> `onSendError` events
[[NSNotificationCenter defaultCenter] addObserver:strongSelf selector:@selector(messaging_onSendErrorNotification:) name:FIRMessagingSendErrorNotification object:nil];
// Firebase Messaging
// JS -> `onMessageSent` events
[[NSNotificationCenter defaultCenter] addObserver:strongSelf selector:@selector(messaging_onSendSuccessNotification:) name:FIRMessagingSendSuccessNotification object:nil];
// Firebase Messaging
// JS -> `onDeletedMessages` events
[[NSNotificationCenter defaultCenter] addObserver:strongSelf selector:@selector(messaging_onDeletedMessagesNotification) name:FIRMessagingMessagesDeletedNotification object:nil];
});
}
// start observing immediately on class load - specifically for UIApplicationDidFinishLaunchingNotification
+ (void)load {
[[self sharedInstance] observe];
}
#pragma mark -
#pragma mark Firebase Messaging Notifications
// Firebase Messaging
// JS -> `onSendError`
- (void)messaging_onSendErrorNotification:(NSNotification *)notification {
NSDictionary *userInfo = notification.userInfo;
NSError *error = (NSError *) userInfo[@"error"];
NSString *messageID = (NSString *) userInfo[@"messageID"];
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_message_send_error" body:@{
@"messageId": messageID,
@"error": @{
@"code": @"unknown",
@"message": error.localizedDescription
}
}];
}
// Firebase Messaging
// JS -> `onMessageSent`
- (void)messaging_onSendSuccessNotification:(NSNotification *)notification {
NSDictionary *userInfo = notification.userInfo;
NSString *messageID = (NSString *) userInfo[@"messageID"];
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_message_sent" body:@{
@"messageId": messageID
}];
}
// Firebase Messaging
// JS -> `onDeletedMessages`
- (void)messaging_onDeletedMessagesNotification {
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_message_deleted" body:@{}];
}
#pragma mark -
#pragma mark Application Notifications
- (void)application_onDidFinishLaunchingNotification:(nonnull NSNotification *)notification {
// setup our delegates & swizzling after app finishes launching
// these methods are idempotent so can safely be called multiple times
[[RNFBMessagingAppDelegate sharedInstance] observe];
[[RNFBMessagingUNUserNotificationCenter sharedInstance] observe];
[[RNFBMessagingFIRMessagingDelegate sharedInstance] observe];
RCTRootView *rctRootView;
if (
[UIApplication sharedApplication].delegate != nil &&
[UIApplication sharedApplication].delegate.window != nil &&
[UIApplication sharedApplication].delegate.window.rootViewController != nil &&
[UIApplication sharedApplication].delegate.window.rootViewController.view != nil &&
[[UIApplication sharedApplication].delegate.window.rootViewController.view isKindOfClass:[RCTRootView class]]
) {
rctRootView = (RCTRootView *) [UIApplication sharedApplication].delegate.window.rootViewController.view;
}
if (notification.userInfo[UIApplicationLaunchOptionsRemoteNotificationKey]) {
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
if (rctRootView != nil) {
NSMutableDictionary *appPropertiesDict = rctRootView.appProperties != nil ? [rctRootView.appProperties mutableCopy] : [NSMutableDictionary dictionary];
appPropertiesDict[@"isHeadless"] = @([RCTConvert BOOL:@(YES)]);
rctRootView.appProperties = appPropertiesDict;
}
#if !(TARGET_IPHONE_SIMULATOR)
// When an app launches in the background (BG mode) and is launched with the notification launch option the app delegate method
// application:didReceiveRemoteNotification:fetchCompletionHandler: will not get called unless registerForRemoteNotifications
// was called early during app initialization - we call it here in this scenario as the user can only call this via JS, at which point
// it'd be too late resulting in the app being terminated.
[[UIApplication sharedApplication] registerForRemoteNotifications];
#endif
} else {
if (rctRootView != nil) {
NSMutableDictionary *appPropertiesDict = rctRootView.appProperties != nil ? [rctRootView.appProperties mutableCopy] : [NSMutableDictionary dictionary];
appPropertiesDict[@"isHeadless"] = @([RCTConvert BOOL:@(NO)]);
rctRootView.appProperties = appPropertiesDict;
}
}
} else {
if (rctRootView != nil) {
NSMutableDictionary *appPropertiesDict = rctRootView.appProperties != nil ? [rctRootView.appProperties mutableCopy] : [NSMutableDictionary dictionary];
appPropertiesDict[@"isHeadless"] = @([RCTConvert BOOL:@(NO)]);
rctRootView.appProperties = appPropertiesDict;
}
}
}
- (void)application_onDidEnterForeground {
if (
[UIApplication sharedApplication].delegate != nil &&
[UIApplication sharedApplication].delegate.window != nil &&
[UIApplication sharedApplication].delegate.window.rootViewController != nil &&
[UIApplication sharedApplication].delegate.window.rootViewController.view != nil &&
[[UIApplication sharedApplication].delegate.window.rootViewController.view isKindOfClass:[RCTRootView class]]
) {
RCTRootView *rctRootView = (RCTRootView *) [UIApplication sharedApplication].delegate.window.rootViewController.view;
if (rctRootView.appProperties != nil && rctRootView.appProperties[@"isHeadless"] == @(YES)) {
NSMutableDictionary *appPropertiesDict = [rctRootView.appProperties mutableCopy];
appPropertiesDict[@"isHeadless"] = @([RCTConvert BOOL:@(NO)]);
rctRootView.appProperties = appPropertiesDict;
}
}
}
@end

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <UserNotifications/UserNotifications.h>
NS_ASSUME_NONNULL_BEGIN
@interface RNFBMessagingUNUserNotificationCenter : NSObject <UNUserNotificationCenterDelegate>
@property NSDictionary* initialNotification;
+ (_Nonnull instancetype)sharedInstance;
- (void)observe;
- (nullable NSDictionary *)getInitialNotification;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,80 @@
/**
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <RNFBApp/RNFBRCTEventEmitter.h>
#import "RNFBMessagingSerializer.h"
#import "RNFBMessaging+UNUserNotificationCenter.h"
@implementation RNFBMessagingUNUserNotificationCenter
+ (instancetype)sharedInstance {
static dispatch_once_t once;
__strong static RNFBMessagingUNUserNotificationCenter *sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[RNFBMessagingUNUserNotificationCenter alloc] init];
sharedInstance.initialNotification = nil;
});
return sharedInstance;
}
- (void)observe {
static dispatch_once_t once;
__weak RNFBMessagingUNUserNotificationCenter *weakSelf = self;
dispatch_once(&once, ^{
RNFBMessagingUNUserNotificationCenter *strongSelf = weakSelf;
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = strongSelf;
});
}
- (nullable NSDictionary *)getInitialNotification {
if (_initialNotification != nil) {
NSDictionary *initialNotificationCopy = [_initialNotification copy];
_initialNotification = nil;
return initialNotificationCopy;
}
return nil;
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
if (notification.request.content.userInfo[@"gcm.message_id"]) {
NSDictionary *notificationDict = [RNFBMessagingSerializer notificationToDict:notification];
// Don't send an event if contentAvailable is true - application:didReceiveRemoteNotification will send the event
// for us, we don't want to duplicate them
if (!notificationDict[@"contentAvailable"]) {
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_message_received" body:notificationDict];
}
// TODO in a later version allow customising completion options in JS code
completionHandler(UNNotificationPresentationOptionNone);
}
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
NSDictionary *remoteNotification = response.notification.request.content.userInfo;
if (remoteNotification[@"gcm.message_id"]) {
NSDictionary *notificationDict = [RNFBMessagingSerializer remoteMessageUserInfoToDict:remoteNotification];
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_notification_opened" body:notificationDict];
_initialNotification = notificationDict;
completionHandler();
}
}
@end

View File

@@ -1,82 +0,0 @@
/**
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <React/RCTConvert.h>
#import <RNFBApp/RNFBSharedUtils.h>
#import <RNFBApp/RNFBRCTEventEmitter.h>
#import <GoogleUtilities/GULAppDelegateSwizzler.h>
#import "RNFBMessagingAppDelegateInterceptor.h"
#import "RNFBMessagingSerializer.h"
@implementation RNFBMessagingAppDelegateInterceptor
+ (instancetype)sharedInstance {
static dispatch_once_t once;
static RNFBMessagingAppDelegateInterceptor *sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[RNFBMessagingAppDelegateInterceptor alloc] init];
[GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods];
[GULAppDelegateSwizzler registerAppDelegateInterceptor:sharedInstance];
});
return sharedInstance;
}
// used to temporarily store a promise instance to resolve calls to `registerForRemoteNotifications`
- (void)setPromiseResolve:(RCTPromiseResolveBlock)resolve andPromiseReject:(RCTPromiseRejectBlock)reject {
_registerPromiseResolver = resolve;
_registerPromiseRejecter = reject;
}
// called when `registerForRemoteNotifications` completes successfully
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[FIRMessaging messaging].APNSToken = deviceToken;
if (_registerPromiseResolver != nil) {
_registerPromiseResolver(@([RCTConvert BOOL:@([UIApplication sharedApplication].isRegisteredForRemoteNotifications)]));
_registerPromiseResolver = nil;
_registerPromiseRejecter = nil;
}
}
// called when `registerForRemoteNotifications` fails to complete
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
if (_registerPromiseRejecter != nil) {
[RNFBSharedUtils rejectPromiseWithNSError:_registerPromiseRejecter error:error];
_registerPromiseResolver = nil;
_registerPromiseRejecter = nil;
}
}
// APNS - only called on iOS versions less than v10 (which isn't officially supported, added here for ease later on)
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
// send message event for remote notifications that have also have data
if (userInfo[@"aps"] && ((NSDictionary *) userInfo[@"aps"]).count >= 1 && userInfo[@"aps"][@"content-available"]) {
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_message_received" body:[RNFBMessagingSerializer remoteMessageAppDataToDict:userInfo withMessageId:nil]];
}
}
// APNS - only called on iOS versions greater than or equal to v10 (this one is officially supported)
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
// send message event for remote notifications that have also have data
if (userInfo[@"aps"] && ((NSDictionary *) userInfo[@"aps"]).count >= 1 && userInfo[@"aps"][@"content-available"]) {
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_message_received" body:[RNFBMessagingSerializer remoteMessageAppDataToDict:userInfo withMessageId:nil]];
// complete immediately
completionHandler(UIBackgroundFetchResultNoData);
}
}
@end

View File

@@ -1,106 +0,0 @@
/**
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <RNFBApp/RNFBRCTEventEmitter.h>
#import <UserNotifications/UserNotifications.h>
#import "RNFBMessagingDelegate.h"
#import "RNFBMessagingSerializer.h"
@implementation RNFBMessagingDelegate
+ (instancetype)sharedInstance {
static dispatch_once_t once;
static RNFBMessagingDelegate *sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[RNFBMessagingDelegate alloc] init];
[FIRMessaging messaging].delegate = sharedInstance;
[FIRMessaging messaging].shouldEstablishDirectChannel = YES;
// JS -> `onSendError`
[[NSNotificationCenter defaultCenter] addObserver:sharedInstance selector:@selector(sendDataMessageFailure:) name:FIRMessagingSendErrorNotification object:nil];
// JS -> `onMessageSent`
[[NSNotificationCenter defaultCenter] addObserver:sharedInstance selector:@selector(sendDataMessageSuccess:) name:FIRMessagingSendSuccessNotification object:nil];
// JS -> `onDeletedMessages`
[[NSNotificationCenter defaultCenter] addObserver:sharedInstance selector:@selector(didDeleteMessagesOnServer) name:FIRMessagingMessagesDeletedNotification object:nil];
});
return sharedInstance;
}
#pragma mark -
#pragma mark UNUserNotificationCenter Methods
// JS -> `onSendError`
- (void)sendDataMessageFailure:(NSNotification *)notification {
NSDictionary *userInfo = notification.userInfo;
NSError *error = (NSError *) userInfo[@"error"];
NSString *messageID = (NSString *) userInfo[@"messageID"];
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_message_send_error" body:@{
@"messageId": messageID,
@"error": @{
@"code": @"unknown",
@"message": error.localizedDescription
}
}];
}
// JS -> `onMessageSent`
- (void)sendDataMessageSuccess:(NSNotification *)notification {
NSDictionary *userInfo = notification.userInfo;
NSString *messageID = (NSString *) userInfo[@"messageID"];
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_message_sent" body:@{
@"messageId": messageID
}];
}
// JS -> `onDeletedMessages`
- (void)didDeleteMessagesOnServer {
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_message_deleted" body:@{}];
}
#pragma mark -
#pragma mark FIRMessagingDelegate Methods
// ----------------------
// TOKEN Message
// --------------------\/
// JS -> `onTokenRefresh`
- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_token_refresh" body:@{
@"token": fcmToken
}];
}
// ----------------------
// DATA Message
// --------------------\/
// JS -> `onMessage`
// Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground.
// To enable direct data messages, you can set [Messaging messaging].shouldEstablishDirectChannel to YES.
- (void)messaging:(nonnull FIRMessaging *)messaging didReceiveMessage:(nonnull FIRMessagingRemoteMessage *)remoteMessage {
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_message_received" body:[RNFBMessagingSerializer remoteMessageToDict:remoteMessage]];
}
@end

View File

@@ -16,10 +16,9 @@
*/
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <Firebase/Firebase.h>
@interface RNFBMessagingModule : NSObject <RCTBridgeModule, FIRMessagingDelegate>
@interface RNFBMessagingModule : NSObject <RCTBridgeModule>
@end

View File

@@ -15,17 +15,15 @@
*
*/
#import <Firebase/Firebase.h>
#import <React/RCTUtils.h>
#import <React/RCTConvert.h>
#import <Firebase/Firebase.h>
#import <RNFBApp/RNFBSharedUtils.h>
#import <UserNotifications/UserNotifications.h>
#import "RNFBMessagingModule.h"
#import "RNFBMessagingDelegate.h"
#import "RNFBMessagingSerializer.h"
#import "RNFBMessagingAppDelegateInterceptor.h"
#import "RNFBMessaging+AppDelegate.h"
#import "RNFBMessaging+UNUserNotificationCenter.h"
@implementation RNFBMessagingModule
#pragma mark -
@@ -35,12 +33,6 @@ RCT_EXPORT_MODULE();
- (id)init {
self = [super init];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// ensure shared instances are initialized early
[RNFBMessagingDelegate sharedInstance];
[RNFBMessagingAppDelegateInterceptor sharedInstance];
});
return self;
}
@@ -62,6 +54,12 @@ RCT_EXPORT_MODULE();
#pragma mark -
#pragma mark Firebase Messaging Methods
RCT_EXPORT_METHOD(getInitialNotification:
(RCTPromiseResolveBlock) resolve
:(RCTPromiseRejectBlock) reject
) {
resolve([[RNFBMessagingUNUserNotificationCenter sharedInstance] getInitialNotification]);
}
RCT_EXPORT_METHOD(setAutoInitEnabled:
(BOOL) enabled
@@ -83,26 +81,38 @@ RCT_EXPORT_METHOD(getToken:
:(RCTPromiseResolveBlock) resolve
:(RCTPromiseRejectBlock) reject
) {
#if !(TARGET_IPHONE_SIMULATOR)
if ([UIApplication sharedApplication].isRegisteredForRemoteNotifications == NO) {
[RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:(NSMutableDictionary *) @{
@"code": @"unregistered",
@"message": @"You must be registered for remote notifications before calling get token, see messaging().registerForRemoteNotifications() or requestPermission().",
@"message": @"You must be registered for remote messages before calling getToken, see messaging().registerDeviceForRemoteMessages().",
}];
return;
}
#endif
NSDictionary *options = nil;
if ([FIRMessaging messaging].APNSToken) {
options = @{@"apns_token": [FIRMessaging messaging].APNSToken};
}
[[FIRInstanceID instanceID] tokenWithAuthorizedEntity:authorizedEntity scope:scope options:options handler:^(NSString *_Nullable identity, NSError *_Nullable error) {
if (error) {
[RNFBSharedUtils rejectPromiseWithNSError:reject error:error];
} else {
resolve(identity);
if ([scope isEqualToString:@"FCM"] && [authorizedEntity isEqualToString:[FIRApp defaultApp].options.GCMSenderID]) {
[[FIRInstanceID instanceID] instanceIDWithHandler:^(FIRInstanceIDResult *_Nullable result, NSError *_Nullable error) {
if (error) {
[RNFBSharedUtils rejectPromiseWithNSError:reject error:error];
} else {
resolve(result.token);
}
}];
} else {
NSDictionary *options = nil;
if ([FIRMessaging messaging].APNSToken) {
options = @{@"apns_token": [FIRMessaging messaging].APNSToken};
}
}];
[[FIRInstanceID instanceID] tokenWithAuthorizedEntity:authorizedEntity scope:scope options:options handler:^(NSString *_Nullable identity, NSError *_Nullable error) {
if (error) {
[RNFBSharedUtils rejectPromiseWithNSError:reject error:error];
} else {
resolve(identity);
}
}];
}
}
RCT_EXPORT_METHOD(deleteToken:
@@ -128,12 +138,22 @@ RCT_EXPORT_METHOD(getAPNSToken:
if (apnsToken) {
resolve([RNFBMessagingSerializer APNSTokenFromNSData:apnsToken]);
} else {
#if !(TARGET_IPHONE_SIMULATOR)
if ([UIApplication sharedApplication].isRegisteredForRemoteNotifications == NO) {
[RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:(NSMutableDictionary *) @{
@"code": @"unregistered",
@"message": @"You must be registered for remote messages before calling getAPNSToken, see messaging().registerDeviceForRemoteMessages().",
}];
return;
}
#endif
resolve([NSNull null]);
}
}
RCT_EXPORT_METHOD(requestPermission:
(RCTPromiseResolveBlock) resolve
(NSDictionary *) permissions
:(RCTPromiseResolveBlock) resolve
:(RCTPromiseRejectBlock) reject
) {
if (RCTRunningInAppExtension()) {
@@ -143,60 +163,52 @@ RCT_EXPORT_METHOD(requestPermission:
return;
}
RCTPromiseResolveBlock customResolver = ^(id result) {
if (@available(iOS 10.0, *)) {
UNAuthorizationOptions authOptions;
if (@available(iOS 12.0, *)) {
authOptions = UNAuthorizationOptionProvisional | UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
} else {
authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
}
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError *_Nullable error) {
if (error) {
[RNFBSharedUtils rejectPromiseWithNSError:reject error:error];
} else {
resolve(@([RCTConvert BOOL:@(granted)]));
}
}];
} else {
// TODO community iOS 9 support could be added here with `registerUserNotificationSettings:settings` & `didRegisterUserNotificationSettings`
[RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:[@{
@"code": @"unsupported-platform-version",
@"message": @"requestPermission call failed; minimum supported version requirement not met (iOS 10)."} mutableCopy]];
if (@available(iOS 10.0, *)) {
UNAuthorizationOptions options = UNAuthorizationOptionNone;
if ([permissions[@"alert"] isEqual:@(YES)]) {
options |= UNAuthorizationOptionAlert;
}
};
if ([UIApplication sharedApplication].isRegisteredForRemoteNotifications == YES) {
customResolver(nil);
if ([permissions[@"badge"] isEqual:@(YES)]) {
options |= UNAuthorizationOptionBadge;
}
if ([permissions[@"sound"] isEqual:@(YES)]) {
options |= UNAuthorizationOptionSound;
}
if ([permissions[@"provisional"] isEqual:@(YES)]) {
if (@available(iOS 12.0, *)) {
options |= UNAuthorizationOptionProvisional;
}
}
if ([permissions[@"announcement"] isEqual:@(YES)]) {
if (@available(iOS 13.0, *)) {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
options |= UNAuthorizationOptionAnnouncement;
#endif
}
}
if ([permissions[@"carPlay"] isEqual:@(YES)]) {
options |= UNAuthorizationOptionCarPlay;
}
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError *_Nullable error) {
if (error) {
[RNFBSharedUtils rejectPromiseWithNSError:reject error:error];
} else {
[self hasPermission:resolve :reject];
}
}];
} else {
if (@available(iOS 10.0, *)) {
UNAuthorizationOptions authOptions;
if (@available(iOS 12.0, *)) {
authOptions = UNAuthorizationOptionProvisional | UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
} else {
authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
}
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError *_Nullable error) {
if (error) {
[RNFBSharedUtils rejectPromiseWithNSError:reject error:error];
} else {
[[RNFBMessagingAppDelegateInterceptor sharedInstance] setPromiseResolve:customResolver andPromiseReject:reject];
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] registerForRemoteNotifications];
});
}
}];
} else {
// TODO community iOS 9 support could be added here
[RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:[@{
@"code": @"unsupported-platform-version",
@"message": @"requestPermission call failed; minimum supported version requirement not met (iOS 10)."} mutableCopy]];
}
[RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:[@{
@"code": @"unsupported-platform-version",
@"message": @"requestPermission call failed; minimum supported version requirement not met (iOS 10)."} mutableCopy]];
}
}
@@ -204,35 +216,25 @@ RCT_EXPORT_METHOD(registerForRemoteNotifications:
(RCTPromiseResolveBlock) resolve
: (RCTPromiseRejectBlock) reject
) {
[[RNFBMessagingAppDelegateInterceptor sharedInstance] setPromiseResolve:resolve andPromiseReject:reject];
[[UIApplication sharedApplication] registerForRemoteNotifications];
if ([UIApplication sharedApplication].isRegisteredForRemoteNotifications == YES) {
return resolve(@([RCTConvert BOOL:@(YES)]));
}
#if TARGET_IPHONE_SIMULATOR
resolve(@([RCTConvert BOOL:@(YES)]));
return;
#endif
if (@available(iOS 10.0, *)) {
UNAuthorizationOptions authOptions;
if (@available(iOS 12.0, *)) {
authOptions = UNAuthorizationOptionProvisional | UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
if ([UIApplication sharedApplication].isRegisteredForRemoteNotifications == YES) {
resolve(@([RCTConvert BOOL:@(YES)]));
} else {
authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
[[RNFBMessagingAppDelegate sharedInstance] setPromiseResolve:resolve andPromiseReject:reject];
}
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError *_Nullable error) {
if (error) {
[RNFBSharedUtils rejectPromiseWithNSError:reject error:error];
} else {
[[RNFBMessagingAppDelegateInterceptor sharedInstance] setPromiseResolve:resolve andPromiseReject:reject];
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] registerForRemoteNotifications];
});
}
}];
// Apple docs recommend that registerForRemoteNotifications is always called on app start regardless of current status
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] registerForRemoteNotifications];
});
} else {
// TODO community iOS 9 support could be added here
[RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:[@{
@"code": @"unsupported-platform-version",
@"message": @"requestPermission call failed; minimum supported version requirement not met (iOS 10)."} mutableCopy]];
@"message": @"registerDeviceForRemoteMessages call failed; minimum supported version requirement not met (iOS 10)."} mutableCopy]];
}
}
@@ -250,11 +252,25 @@ RCT_EXPORT_METHOD(hasPermission:
) {
if (@available(iOS 10.0, *)) {
[[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings *_Nonnull settings) {
BOOL hasPermission = [RCTConvert BOOL:@(settings.authorizationStatus >= UNAuthorizationStatusAuthorized)];
resolve(@(hasPermission));
NSNumber *authorizedStatus = @-1;
if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) {
authorizedStatus = @-1;
} else if (settings.authorizationStatus == UNAuthorizationStatusDenied) {
authorizedStatus = @0;
} else if (settings.authorizationStatus == UNAuthorizationStatusAuthorized) {
authorizedStatus = @1;
}
if (@available(iOS 12.0, *)) {
if (settings.authorizationStatus == UNAuthorizationStatusProvisional) {
authorizedStatus = @2;
}
}
resolve(authorizedStatus);
}];
} else {
// TODO community iOS 9 support could be added here via application `currentUserNotificationSettings`.types != UIUserNotificationTypeNone
[RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:[@{
@"code": @"unsupported-platform-version",
@"message": @"hasPermission call failed; minimum supported version requirement not met (iOS 10)."} mutableCopy]];

View File

@@ -16,16 +16,17 @@
*/
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <Firebase/Firebase.h>
@interface RNFBMessagingSerializer : NSObject
+ (NSString *) APNSTokenFromNSData:(NSData *)tokenData;
+ (NSString *)APNSTokenFromNSData:(NSData *)tokenData;
+ (NSDictionary *)remoteMessageToDict:(FIRMessagingRemoteMessage *)remoteMessage;
+ (NSDictionary *)remoteMessageAppDataToDict:(NSDictionary *)appData withMessageId:(nullable NSString *)messageId;
+ (NSDictionary *)notificationToDict:(UNNotification *)notification;
+ (NSDictionary *)remoteMessageUserInfoToDict:(NSDictionary *)userInfo;
@end

View File

@@ -1,4 +1,3 @@
//
/**
* Copyright (c) 2016-present Invertase Limited & Contributors
*
@@ -16,7 +15,7 @@
*
*/
#import <React/RCTConvert.h>
#import "RNFBMessagingSerializer.h"
@implementation RNFBMessagingSerializer
@@ -33,63 +32,162 @@
}
+ (NSDictionary *)remoteMessageToDict:(FIRMessagingRemoteMessage *)remoteMessage {
return [self remoteMessageAppDataToDict:remoteMessage.appData withMessageId:remoteMessage.messageID];
return [self remoteMessageUserInfoToDict:remoteMessage.appData];
}
+ (NSDictionary *)notificationToDict:(UNNotification *)notification {
return [self remoteMessageUserInfoToDict:notification.request.content.userInfo];
}
+ (NSDictionary *)remoteMessageAppDataToDict:(NSDictionary *)appData withMessageId:(nullable NSString *)messageId {
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
+ (NSDictionary *)remoteMessageUserInfoToDict:(NSDictionary *)userInfo {
NSMutableDictionary *message = [[NSMutableDictionary alloc] init];
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
NSMutableDictionary *notification = [[NSMutableDictionary alloc] init];
NSMutableDictionary *notificationIOS = [[NSMutableDictionary alloc] init];
if (messageId != nil) {
message[@"messageId"] = messageId;
}
for (id key in appData) {
// messageId
// message.data
for (id key in userInfo) {
// message.messageId
if ([key isEqualToString:@"gcm.message_id"] || [key isEqualToString:@"google.message_id"] || [key isEqualToString:@"message_id"]) {
message[@"messageId"] = appData[key];
message[@"messageId"] = userInfo[key];
continue;
}
// messageType
// message.messageType
if ([key isEqualToString:@"message_type"]) {
message[@"messageType"] = appData[key];
message[@"messageType"] = userInfo[key];
continue;
}
// collapseKey
// message.collapseKey
if ([key isEqualToString:@"collapse_key"]) {
message[@"collapseKey"] = appData[key];
message[@"collapseKey"] = userInfo[key];
continue;
}
// from
// message.from
if ([key isEqualToString:@"from"]) {
message[@"from"] = appData[key];
message[@"from"] = userInfo[key];
continue;
}
// sentTime
// message.sentTime
if ([key isEqualToString:@"google.c.a.ts"]) {
message[@"sentTime"] = appData[key];
}
// to
if ([key isEqualToString:@"to"] || [key isEqualToString:@"google.to"]) {
message[@"to"] = appData[key];
}
// skip keys that shouldn't be included
if ([key isEqualToString:@"notification"] || [key hasPrefix:@"gcm."] || [key hasPrefix:@"google."]) {
message[@"sentTime"] = userInfo[key];
continue;
}
data[key] = appData[key];
// message.to
if ([key isEqualToString:@"to"] || [key isEqualToString:@"google.to"]) {
message[@"to"] = userInfo[key];
continue;
}
// build data dict from remaining keys but skip keys that shouldn't be included in data
if (
[key isEqualToString:@"aps"] ||
[key hasPrefix:@"gcm."] ||
[key hasPrefix:@"google."]
) {
continue;
}
data[key] = userInfo[key];
}
message[@"data"] = data;
if (userInfo[@"aps"] != nil) {
NSDictionary *apsDict = userInfo[@"aps"];
// message.category
if (apsDict[@"category"] != nil) {
message[@"category"] = apsDict[@"category"];
}
// message.threadId
if (apsDict[@"thread-id"] != nil) {
message[@"threadId"] = apsDict[@"thread-id"];
}
// message.contentAvailable
if (apsDict[@"content-available"] != nil) {
message[@"contentAvailable"] = @([RCTConvert BOOL:apsDict[@"content-available"]]);
}
// message.mutableContent
if (apsDict[@"mutable-content"] != nil && [apsDict[@"mutable-content"] isEqualToString:@"1"]) {
message[@"mutableContent"] = @([RCTConvert BOOL:apsDict[@"mutable-content"]]);
}
// message.notification.*
if (apsDict[@"alert"] != nil) {
// can be a string or dictionary
if ([apsDict[@"alert"] isKindOfClass:[NSString class]]) {
// message.notification.title
notification[@"title"] = apsDict[@"alert"];
} else if ([apsDict[@"alert"] isKindOfClass:[NSDictionary class]]) {
NSDictionary *apsAlertDict = apsDict[@"alert"];
// message.notification.title
if (apsAlertDict[@"title"] != nil) {
notification[@"title"] = apsAlertDict[@"title"];
}
// message.notification.body
if (apsAlertDict[@"body"] != nil) {
notification[@"body"] = apsAlertDict[@"body"];
}
// iOS only
// message.notification.ios.subtitle
if (apsAlertDict[@"subtitle"] != nil) {
notificationIOS[@"subtitle"] = apsAlertDict[@"subtitle"];
}
// iOS only
// message.notification.ios.badge
if (apsAlertDict[@"badge"] != nil) {
notificationIOS[@"badge"] = apsAlertDict[@"badge"];
}
}
notification[@"ios"] = notificationIOS;
message[@"notification"] = notification;
}
// message.notification.ios.sound
if (apsDict[@"sound"] != nil) {
if ([apsDict[@"sound"] isKindOfClass:[NSString class]]) {
// message.notification.ios.sound
notification[@"sound"] = apsDict[@"sound"];
} else if ([apsDict[@"sound"] isKindOfClass:[NSDictionary class]]) {
NSDictionary *apsSoundDict = apsDict[@"sound"];
NSMutableDictionary *notificationIOSSound = [[NSMutableDictionary alloc] init];
// message.notification.ios.sound.name String
if (apsSoundDict[@"name"] != nil) {
notificationIOSSound[@"name"] = apsSoundDict[@"name"];
}
// message.notification.ios.sound.critical Boolean
if (apsSoundDict[@"critical"] != nil) {
notificationIOSSound[@"critical"] = @([RCTConvert BOOL:apsSoundDict[@"critical"]]);
}
// message.notification.ios.sound.volume Number
if (apsSoundDict[@"volume"] != nil) {
notificationIOSSound[@"volume"] = apsSoundDict[@"volume"];
}
// message.notification.ios.sound
notificationIOS[@"sound"] = notificationIOSSound;
}
notification[@"ios"] = notificationIOS;
message[@"notification"] = notification;
}
}
message[@"data"] = data;
return message;
}
@end
@end

View File

@@ -58,7 +58,9 @@ export namespace FirebaseMessagingTypes {
import NativeFirebaseError = ReactNativeFirebase.NativeFirebaseError;
export interface Statics {
// firebase.messaging.* static props go here
AuthorizationStatus: typeof AuthorizationStatus;
NotificationAndroidPriority: typeof NotificationAndroidPriority;
NotificationAndroidVisibility: typeof NotificationAndroidVisibility;
}
/**
@@ -104,6 +106,33 @@ export namespace FirebaseMessagingTypes {
* Additional Notification data sent with the message
*/
notification?: Notification;
/**
* Whether the iOS APNS message was configured as a background update notification.
*
* @platform ios iOS
*/
contentAvailable?: boolean;
/**
* Whether the iOS APNS `mutable-content` property on the message was set
* allowing the app to modify the notification via app extensions.
*
* @platform ios iOS
*/
mutableContent?: boolean;
/**
* The iOS category this notification is assigned to.
*
* @platform ios iOS
*/
category?: string;
/**
* An iOS app specific identifier used for notification grouping.
*/
threadId?: string;
}
export interface Notification {
@@ -117,21 +146,42 @@ export namespace FirebaseMessagingTypes {
*/
body?: string;
ios?: {
/**
* The notification's subtitle.
*/
subtitle?: string;
/**
* The value of the badge on the home screen app icon.
* If not specified, the badge is not changed.
* If set to 0, the badge has been removed.
*/
badge?: string;
/**
* The sound played when the notification was delivered on the device (if permissions permit).
*/
sound?: string | NotificationIOSCriticalSound;
};
/**
* Additional Android specific properties set on the notification.
*/
android?: {
/**
* The sound played when the notification was delivered on the device (channel settings permitted).
*
* Set as "default" if the default device notification sound was used.
*/
sound?: string;
/**
* The channel ID set on the notification. If not set, the notification uses the default
* "Miscellaneous" channel set by FCM.
*/
channelId?: string;
/**
* Name of the click action set on the notification.
*/
clickAction?: string;
/**
* The custom color used to tint the notification content.
*/
@@ -158,6 +208,11 @@ export namespace FirebaseMessagingTypes {
*/
count?: number;
/**
* Name of the click action set on the notification.
*/
clickAction?: string;
/**
* The notification priority.
*
@@ -171,13 +226,6 @@ export namespace FirebaseMessagingTypes {
| NotificationAndroidPriority.PRIORITY_HIGH
| NotificationAndroidPriority.PRIORITY_MAX;
/**
* The sound played when the notification was delivered on the device (channel settings permitted).
*
* Set as "default" if the default device notification sound was used.
*/
sound?: string;
/**
* Ticker text set on the notification.
*
@@ -196,11 +244,41 @@ export namespace FirebaseMessagingTypes {
};
}
/**
* Represents a critical sound configuration that can be included in the
* `aps` dictionary of an APNs payload.
*/
export interface NotificationIOSCriticalSound {
/**
* The critical alert flag. Set to `true` to enable the critical alert.
*/
critical?: boolean;
/**
* The name of a sound file in the app's main bundle or in the `Library/Sounds`
* folder of the app's container directory. Specify the string "default" to play
* the system sound.
*/
name: string;
/**
* The volume for the critical alert's sound. Must be a value between 0.0
* (silent) and 1.0 (full volume).
*/
volume?: number;
}
/**
* The enum representing a notification priority.
*
* Note; on devices which have channel support (Android 8.0 (API level 26) +),
* this value will be ignored. Instead, the channel "importance" level is used.
*
* Example:
*
* ```js
* firebase.messaging.NotificationAndroidPriority.PRIORITY_MIN;
* ```
*/
export enum NotificationAndroidPriority {
/**
@@ -238,6 +316,12 @@ export namespace FirebaseMessagingTypes {
/**
* The enum representing the visibility of a notification.
*
* Example:
*
* ```js
* firebase.messaging.NotificationAndroidVisibility.VISIBILITY_SECRET;
* ```
*/
export enum NotificationAndroidVisibility {
/**
@@ -256,6 +340,96 @@ export namespace FirebaseMessagingTypes {
VISIBILITY_PUBLIC = 1,
}
/**
* An interface representing all the available permissions that can be requested by your app via
* the `requestPermission` API.
*/
export interface IOSPermissions {
/**
* Request permission to display alerts.
*
* Defaults to true.
*/
alert?: boolean;
/**
* Request permission for Siri to automatically read out notification messages over AirPods.
*
* Defaults to false.
*
* @platform ios iOS >= 13
*/
announcement?: boolean;
/**
* Request permission to update the application badge.
*
* Defaults to true.
*/
badge?: boolean;
/**
* Request permission to display notifications in a CarPlay environment.
*
* Defaults to true.
*/
carPlay?: boolean;
/**
* Request permission to provisionally create non-interrupting notifications.
*
* Defaults to false.
*
* @platform ios iOS >= 12
*/
provisional?: boolean;
/**
* Request permission to play sounds.
*
* Defaults to true.
*/
sound?: boolean;
}
/**
* An enum representing the notification authorization status for this app on the device.
*
* Value is truthy if authorized, compare against an exact status (e.g. iOS PROVISIONAL) for a more
* granular status.
*
* Example:
*
* ```js
* firebase.messaging.AuthorizationStatus.NOT_DETERMINED;
* ```
*/
export enum AuthorizationStatus {
/**
* The app user has not yet chosen whether to allow the application to create notifications. Usually
* this status is returned prior to the first call of `requestPermission`.
*
* @platform ios iOS
*/
NOT_DETERMINED = -1,
/**
* The app is not authorized to create notifications.
*/
DENIED = 0,
/**
* The app is authorized to create notifications.
*/
AUTHORIZED = 1,
/**
* The app is currently authorized to post non-interrupting user notifications
* @platform ios iOS >= 12
*/
PROVISIONAL = 2,
}
/**
* An event that is received when a message fails to send.
*
@@ -492,7 +666,7 @@ export namespace FirebaseMessagingTypes {
*
* @ios
*/
requestPermission(): Promise<boolean>;
requestPermission(permissions?: IOSPermissions): Promise<AuthorizationStatus>;
/**
* Deprecated. See `registerDeviceForRemoteMessages` instead.
@@ -591,15 +765,19 @@ export namespace FirebaseMessagingTypes {
getAPNSToken(): Promise<string | null>;
/**
* Returns a boolean value as to whether the user has messaging permission for this app.
* Returns a `AuthorizationStatus` as to whether the user has messaging permission for this app.
*
* #### Example
*
* ```js
* const hasPermission = await firebase.messaging().hasPermission();
* const authStatus = await firebase.messaging().hasPermission();
* if (authStatus === firebase.messaging.AuthorizationStatus.AUTHORIZED) {
* // yay
* }
*
* ```
*/
hasPermission(): Promise<boolean>;
hasPermission(): Promise<AuthorizationStatus>;
/**
* Called when the FCM server deletes pending messages. This may be due to:

View File

@@ -16,10 +16,12 @@
*/
import {
hasOwnProperty,
isAndroid,
isBoolean,
isFunction,
isIOS,
isObject,
isString,
isUndefined,
} from '@react-native-firebase/app/lib/common';
@@ -32,7 +34,25 @@ import { AppRegistry } from 'react-native';
import remoteMessageOptions from './remoteMessageOptions';
import version from './version';
const statics = {};
const statics = {
AuthorizationStatus: {
NOT_DETERMINED: -1,
DENIED: 0,
AUTHORIZED: 1,
PROVISIONAL: 2,
},
NotificationAndroidPriority: {
PRIORITY_LOW: -1,
PRIORITY_DEFAULT: 0,
PRIORITY_HIGH: 1,
PRIORITY_MAX: 2,
},
NotificationAndroidVisibility: {
VISIBILITY_SECRET: -1,
VISIBILITY_PRIVATE: 0,
VISIBILITY_PUBLIC: 1,
},
};
const namespace = 'messaging';
@@ -59,6 +79,19 @@ class FirebaseMessagingModule extends FirebaseModule {
}
return remoteMessage => backgroundMessageHandler(remoteMessage);
});
if (isIOS) {
this.emitter.addListener('messaging_message_received_background', remoteMessage => {
if (!backgroundMessageHandler) {
console.warn(
'No background message handler has been set. Set a handler via the "setBackgroundMessageHandler" method.',
);
return Promise.resolve();
}
return backgroundMessageHandler(remoteMessage);
});
}
}
get isAutoInitEnabled() {
@@ -142,9 +175,6 @@ class FirebaseMessagingModule extends FirebaseModule {
throw new Error("firebase.messaging().onMessage(*) 'listener' expected a function.");
}
// TODO(salakar) rework internals as without this native module will never be ready (therefore never subscribes)
this.native;
const subscription = this.emitter.addListener('messaging_message_received', listener);
return () => subscription.remove();
}
@@ -156,9 +186,6 @@ class FirebaseMessagingModule extends FirebaseModule {
);
}
// TODO(salakar) rework internals as without this native module will never be ready (therefore never subscribes)
this.native;
const subscription = this.emitter.addListener('messaging_notification_opened', listener);
return () => subscription.remove();
}
@@ -168,9 +195,6 @@ class FirebaseMessagingModule extends FirebaseModule {
throw new Error("firebase.messaging().onTokenRefresh(*) 'listener' expected a function.");
}
// TODO(salakar) rework internals as without this native module will never be ready (therefore never subscribes)
this.native;
const subscription = this.emitter.addListener('messaging_token_refresh', event => {
// TODO remove after v7.0.0, see: https://github.com/invertase/react-native-firebase/issues/2889
const { token } = event;
@@ -192,11 +216,45 @@ class FirebaseMessagingModule extends FirebaseModule {
/**
* @platform ios
*/
requestPermission() {
requestPermission(permissions) {
if (isAndroid) {
return Promise.resolve(true);
return Promise.resolve(1);
}
return this.native.requestPermission();
const defaultPermissions = {
alert: true,
announcement: false,
badge: true,
carPlay: true,
provisional: false,
sound: true,
};
if (!permissions) {
return this.native.requestPermission(defaultPermissions);
}
if (!isObject(permissions)) {
throw new Error('firebase.messaging().requestPermission(*) expected an object value.');
}
Object.entries(permissions).forEach(([key, value]) => {
if (!hasOwnProperty(defaultPermissions, key)) {
throw new Error(
`firebase.messaging().requestPermission(*) unexpected key "${key}" provided to permissions object.`,
);
}
if (!isBoolean(value)) {
throw new Error(
`firebase.messaging().requestPermission(*) the permission "${key}" expected a boolean value.`,
);
}
defaultPermissions[key] = value;
});
return this.native.requestPermission(defaultPermissions);
}
registerDeviceForRemoteMessages() {
@@ -264,9 +322,6 @@ class FirebaseMessagingModule extends FirebaseModule {
throw new Error("firebase.messaging().onDeletedMessages(*) 'listener' expected a function.");
}
// TODO(salakar) rework internals as without this native module will never be ready (therefore never subscribes)
this.native;
const subscription = this.emitter.addListener('messaging_message_deleted', listener);
return () => subscription.remove();
}
@@ -277,9 +332,6 @@ class FirebaseMessagingModule extends FirebaseModule {
throw new Error("firebase.messaging().onMessageSent(*) 'listener' expected a function.");
}
// TODO(salakar) rework internals as without this native module will never be ready (therefore never subscribes)
this.native;
const subscription = this.emitter.addListener('messaging_message_sent', listener);
return () => {
subscription.remove();
@@ -292,9 +344,6 @@ class FirebaseMessagingModule extends FirebaseModule {
throw new Error("firebase.messaging().onSendError(*) 'listener' expected a function.");
}
// TODO(salakar) rework internals as without this native module will never be ready (therefore never subscribes)
this.native;
const subscription = this.emitter.addListener('messaging_message_send_error', listener);
return () => subscription.remove();
}
@@ -309,10 +358,6 @@ class FirebaseMessagingModule extends FirebaseModule {
);
}
if (isIOS) {
return;
}
backgroundMessageHandler = handler;
}
@@ -391,6 +436,7 @@ export default createModuleNamespace({
'messaging_message_received',
'messaging_message_send_error',
'messaging_notification_opened',
...(isIOS ? ['messaging_message_received_background'] : []),
],
hasMultiAppSupport: false,
hasCustomUrlOrRegionSupport: false,

View File

@@ -24,7 +24,7 @@
"peerDependencies": {
"@react-native-firebase/app": "*"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -11,6 +11,9 @@ console.log(firebase.app().messaging().app.name);
// checks statics exist
console.log(firebase.messaging.SDK_VERSION);
console.log(firebase.messaging.AuthorizationStatus.AUTHORIZED);
console.log(firebase.messaging.NotificationAndroidPriority.PRIORITY_LOW);
console.log(firebase.messaging.NotificationAndroidVisibility.VISIBILITY_PRIVATE);
// checks statics exist on defaultExport
console.log(firebase.SDK_VERSION);

View File

@@ -32,7 +32,7 @@
"peerDependencies": {
"@react-native-firebase/app": "*"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -34,7 +34,7 @@
"peerDependencies": {
"@react-native-firebase/app": "*"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -29,7 +29,7 @@
"peerDependencies": {
"@react-native-firebase/app": "*"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -26,7 +26,7 @@
"peerDependencies": {
"@react-native-firebase/app": "*"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -31,7 +31,7 @@
"peerDependencies": {
"@react-native-firebase/app": "*"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
"publishConfig": {
"access": "public"
}

View File

@@ -21,5 +21,5 @@
"publishConfig": {
"access": "public"
},
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd"
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da"
}

View File

@@ -1,138 +0,0 @@
/* eslint-disable */
/*
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import React, { useEffect, Component } from 'react';
import { AppRegistry, Image, StyleSheet, View, Text } from 'react-native';
import {
AdsConsent,
InterstitialAd,
RewardedAd,
BannerAd,
TestIds,
BannerSize,
} from '@react-native-firebase/admob';
import firebase from '@react-native-firebase/app';
function Root() {
async function init() {
// await AdsConsent.setDebugGeography(1);
//
// const foo = await AdsConsent.requestInfoUpdate(['pub-4406399463942824']);
// console.warn(foo);
// const r = await AdsConsent.showForm({
// privacyPolicy: 'https://invertase.io/privacy-policy',
// // withPersonalizedAds: true,
// // withNonPersonalizedAds: false,
// // withAdFree: false,
// });
// // console.log(r);
//
// const p = await AdsConsent.getAdProviders();
// console.warn('p', p);
// console.log(Interstitial)
// await Interstitial.request('ca-app-pub-3940256099942544/1033173712', {
// listener(event, error) {
// console.warn(event, error);
// },
// });
// const options = {
// requestNonPersonalizedAdsOnly: true,
// networkExtras: {
// user: '123',
// foo: 'bar',
// npa: '1',
// },
// keywords: ['foo'],
// testDevices: ['EMULATOR'],
// location: [53.481073, -2.237074],
// requestAgent: 'CoolAds',
// };
//
//
// const rewardedAd = RewardedAd.createForAdRequest(TestIds.REWARDED, options);
// //
// // rewardedAd.onAdEvent(console.log);
// //
// // rewardedAd.load();
//
// rewardedAd.onAdEvent(async (type, error, data) => {
// console.log('>>>', type, error, data);
//
// if (type === 'rewarded_loaded') {
// await rewardedAd.show();
// }
// });
// //
// rewardedAd.load();
}
// testing ssh - not sure the name
// const interstitialAd = InterstitialAd.createForAdRequest(TestIds.INTERSTITIAL, {
// //
// });
// await interstitialAd.show();
//
// interstitialAd.onAdEvent(async (type, error) => {
// console.log('>>>', type, error);
// if (type === 'loaded') {
// console.log('!!!!! show')
// }
// });
//
// interstitialAd.load();
// }
useEffect(() => {
init().catch(console.error);
}, []);
return (
<View
style={{ flex: 1, justifyContent: 'center', flexDirection: 'column', alignItems: 'center' }}
>
<BannerAd
size={firebase.admob.BannerAdSize.LARGE_BANNER}
request={{}}
unitId={TestIds.BANNER + '123'}
onAdLoaded={() => console.log('loaded')}
onAdFailedToLoad={e => console.log('failed to load', e)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
horizontal: {
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
padding: 10,
},
logo: {
height: 120,
marginBottom: 16,
width: 135,
},
});
AppRegistry.registerComponent('testing', () => Root);

View File

@@ -1,87 +0,0 @@
/* eslint-disable no-console */
/*
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import React, { useEffect, useState } from 'react';
import { AppRegistry, Text, Image, StyleSheet, View } from 'react-native';
import messaging from '@react-native-firebase/messaging';
messaging().setBackgroundMessageHandler(async r => {
console.log('setBackgroundMessageHandler', r);
});
function Root() {
const [token, setToken] = useState('');
useEffect(() => {
console.warn('use effect');
messaging()
.getInitialNotification()
.then(n => {
console.warn('initial notification', n);
});
messaging().onNotificationOpenedApp(event => {
console.log('onNotificationOpenedApp', event);
});
messaging().onMessage(msg => {
console.log('onMessage', msg);
});
messaging()
.getToken()
.then(t => {
console.log(t);
setToken(t);
});
}, []);
return (
<View style={[styles.container, styles.horizontal]}>
<Text>{token}</Text>
<Image
source={{
uri:
'https://github.com/invertase/react-native-firebase-starter/raw/master/assets/ReactNativeFirebase.png',
}}
style={[styles.logo]}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
horizontal: {
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
padding: 10,
},
logo: {
height: 120,
marginBottom: 16,
width: 135,
},
});
AppRegistry.registerComponent('testing', () => Root);

View File

@@ -1,140 +0,0 @@
/* eslint-disable */
/*
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import React, { Component } from 'react';
import { AppRegistry, StyleSheet } from 'react-native';
import { GiftedChat } from 'react-native-gifted-chat';
import firebase from '@react-native-firebase/app';
import '@react-native-firebase/ml-natural-language';
let id = 0;
class Root extends Component {
smartReplyConversation = firebase.naturalLanguage().newSmartReplyConversation();
state = {
messages: [
{
_id: id++,
text: 'React Native Firebase -> ML Kit Smart Replies',
system: false,
user: {
_id: 987,
name: 'R',
avatar:
'https://camo.githubusercontent.com/e7a14b9a151d9b1d23a0d05dac1af86b0e972714/68747470733a2f2f692e696d6775722e636f6d2f4a497942744b572e706e67',
},
},
],
suggestions: [],
};
onQuickReply = replies => {
const createdAt = new Date();
if (replies.length === 1) {
this.onSend([
{
createdAt,
_id: id++,
text: replies[0].title,
user: {
_id: 234,
},
},
]);
} else if (replies.length > 1) {
this.onSend([
{
createdAt,
_id: id++,
text: replies.map(reply => reply.title).join(', '),
user: {
_id: 234,
},
},
]);
} else {
console.warn('replies param is not set correctly');
}
};
onSend = async messages => {
for (let i = 0; i < messages.length; i++) {
const { text, user, createdAt } = messages[i];
this.smartReplyConversation.addRemoteUserMessage(
text,
createdAt.getTime(),
user._id + '' || 'testRemoteUser',
);
}
const suggestions = await this.smartReplyConversation.getSuggestedReplies();
this.setState(prevState => {
let quickRepliesMessage = null;
if (suggestions.length) {
quickRepliesMessage = {
_id: id++,
text: '',
// createdAt: new Date(),
user: {
_id: 234,
},
quickReplies: {
type: 'radio',
values: suggestions.map($ => ({ title: $.text, value: $.text })),
},
};
}
return {
messages: quickRepliesMessage
? [quickRepliesMessage, ...messages, ...prevState.messages]
: [...messages, ...prevState.messages],
};
});
};
render() {
return (
<GiftedChat
inverted
messages={this.state.messages}
onQuickReply={this.onQuickReply}
onSend={this.onSend}
/>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
horizontal: {
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
padding: 10,
},
logo: {
height: 120,
marginBottom: 16,
width: 135,
},
});
AppRegistry.registerComponent('testing', () => Root);

View File

@@ -16,5 +16,6 @@
*/
require('./app');
// require('./app.playground');
//require('./app.admob');
// require('./app.smartreply');

View File

@@ -194,9 +194,9 @@ PODS:
- Firebase/Functions (6.13.0):
- Firebase/CoreOnly
- FirebaseFunctions (~> 2.5.1)
- Firebase/InAppMessagingDisplay (6.13.0):
- Firebase/InAppMessaging (6.13.0):
- Firebase/CoreOnly
- FirebaseInAppMessagingDisplay (~> 0.15.5)
- FirebaseInAppMessaging (~> 0.15.5)
- Firebase/Messaging (6.13.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 4.1.9)
@@ -298,9 +298,6 @@ PODS:
- FirebaseCore (~> 6.2)
- FirebaseInstanceID (~> 4.0)
- GoogleDataTransportCCTSupport (~> 1.0)
- FirebaseInAppMessagingDisplay (0.15.5):
- FirebaseCore (~> 6.2)
- FirebaseInAppMessaging (>= 0.15.0)
- FirebaseInstanceID (4.2.7):
- FirebaseCore (~> 6.0)
- GoogleUtilities/Environment (~> 6.0)
@@ -536,64 +533,64 @@ PODS:
- React-Core (= 0.60.5)
- React-RCTWebSocket (0.60.5):
- React-Core (= 0.60.5)
- RNFBAdMob (6.2.0):
- RNFBAdMob (6.3.4):
- Firebase/AdMob (~> 6.13.0)
- Firebase/Analytics (~> 6.13.0)
- Firebase/Core (~> 6.13.0)
- PersonalizedAdConsent
- React
- RNFBApp
- RNFBAnalytics (6.2.0):
- RNFBAnalytics (6.3.4):
- Firebase/Core (~> 6.13.0)
- React
- RNFBApp
- RNFBApp (6.2.0):
- RNFBApp (6.3.4):
- Firebase/Core (~> 6.13.0)
- React
- RNFBAuth (6.2.0):
- RNFBAuth (6.3.4):
- Firebase/Auth (~> 6.13.0)
- Firebase/Core (~> 6.13.0)
- React
- RNFBApp
- RNFBCrashlytics (6.2.0):
- RNFBCrashlytics (6.3.4):
- Crashlytics (~> 3.14.0)
- Fabric (~> 1.10.2)
- Firebase/Core (~> 6.13.0)
- React
- RNFBApp
- RNFBDatabase (6.2.0):
- RNFBDatabase (6.3.4):
- Firebase/Core (~> 6.13.0)
- Firebase/Database (~> 6.13.0)
- React
- RNFBApp
- RNFBDynamicLinks (6.2.0):
- RNFBDynamicLinks (6.3.4):
- Firebase/Core (~> 6.13.0)
- Firebase/DynamicLinks (~> 6.13.0)
- React
- RNFBApp
- RNFBFirestore (6.2.0):
- RNFBFirestore (6.3.4):
- Firebase/Core (~> 6.13.0)
- Firebase/Firestore (~> 6.13.0)
- React
- RNFBApp
- RNFBFunctions (6.2.0):
- RNFBFunctions (6.3.4):
- Firebase/Functions (~> 6.13.0)
- React
- RNFBApp
- RNFBIid (6.2.0):
- RNFBIid (6.3.4):
- Firebase/Core (~> 6.13.0)
- React
- RNFBApp
- RNFBInAppMessaging (6.2.0):
- RNFBInAppMessaging (6.3.4):
- Firebase/Core (~> 6.13.0)
- Firebase/InAppMessagingDisplay (~> 6.13.0)
- Firebase/InAppMessaging (~> 6.13.0)
- React
- RNFBApp
- RNFBMessaging (6.2.0):
- RNFBMessaging (6.3.4):
- Firebase/Messaging (~> 6.13.0)
- React
- RNFBApp
- RNFBMLNaturalLanguage (6.2.0):
- RNFBMLNaturalLanguage (6.3.4):
- Firebase/Core (~> 6.13.0)
- Firebase/MLCommon (~> 6.13.0)
- Firebase/MLNaturalLanguage (~> 6.13.0)
@@ -601,7 +598,7 @@ PODS:
- Firebase/MLNLSmartReply (~> 6.13.0)
- React
- RNFBApp
- RNFBMLVision (6.2.0):
- RNFBMLVision (6.3.4):
- Firebase/Core (~> 6.13.0)
- Firebase/MLVision (~> 6.13.0)
- Firebase/MLVisionBarcodeModel (~> 6.13.0)
@@ -610,17 +607,17 @@ PODS:
- Firebase/MLVisionTextModel (~> 6.13.0)
- React
- RNFBApp
- RNFBPerf (6.2.0):
- RNFBPerf (6.3.4):
- Firebase/Core (~> 6.13.0)
- Firebase/Performance (~> 6.13.0)
- React
- RNFBApp
- RNFBRemoteConfig (6.2.0):
- RNFBRemoteConfig (6.3.4):
- Firebase/Core (~> 6.13.0)
- Firebase/RemoteConfig (~> 6.13.0)
- React
- RNFBApp
- RNFBStorage (6.2.0):
- RNFBStorage (6.3.4):
- Firebase/Core (~> 6.13.0)
- Firebase/Storage (~> 6.13.0)
- React
@@ -689,7 +686,6 @@ SPEC REPOS:
- FirebaseFirestore
- FirebaseFunctions
- FirebaseInAppMessaging
- FirebaseInAppMessagingDisplay
- FirebaseInstanceID
- FirebaseMessaging
- FirebaseMLCommon
@@ -820,7 +816,6 @@ SPEC CHECKSUMS:
FirebaseFirestore: 2e92e977280d63ecbf3fd58bdbfaf9145abb880f
FirebaseFunctions: 5af7c35d1c5e41608fecbb667eb6c4e672e318d0
FirebaseInAppMessaging: acbfa8c5582b11ccc0366511d29ef1d288f302fc
FirebaseInAppMessagingDisplay: 60a65c8277f17675a8a5b92e9a97cd914b45d4ff
FirebaseInstanceID: ebd2ea79ee38db0cb5f5167b17a0d387e1cc7b6e
FirebaseMessaging: e8d71368a5c579083da02203146c953f3386d503
FirebaseMLCommon: 074a67e05122b1c9f6401a4e33b2cea3b4efd224
@@ -869,23 +864,23 @@ SPEC CHECKSUMS:
React-RCTText: b074d89033583d4f2eb5faf7ea2db3a13c7553a2
React-RCTVibration: 2105b2e0e2b66a6408fc69a46c8a7fb5b2fdade0
React-RCTWebSocket: cd932a16b7214898b6b7f788c8bddb3637246ac4
RNFBAdMob: 6bd7b601928d23a0b454252172fedbe746b0f7cc
RNFBAnalytics: 57dc0bfad4e40f68779757653676699072651218
RNFBApp: 5b215aacc09105a1761de31b9a0eb2abcce06253
RNFBAuth: 61673c0d38ce225c315e7be13a1b494904baedd2
RNFBCrashlytics: 63bb6e8c450075e2b01b98865911ece999da8ac9
RNFBDatabase: 267f476097111054553ecb99208201945961efa5
RNFBDynamicLinks: fc6a123aaa86dc8745dcb3050ecc9c8e199f64df
RNFBFirestore: 5de4ae898df51a3ecc16a45db15019836c5cec87
RNFBFunctions: 04ab4f777106d8a20ed1c9c2116f24014c23d61a
RNFBIid: b42fc6a9bba8be4efb69e2809f8b3d1615e5e8cd
RNFBInAppMessaging: 0bc9efa4f705b1f8feef9045fdcfc09b3bb4f085
RNFBMessaging: be0b936394416ec5503add603f2c0a641c353063
RNFBMLNaturalLanguage: a79d764d55e5bd55d8e1c022183a7adb46f0d0ed
RNFBMLVision: 0acf59ad65d8d3e5e9079d44bd090cf1c65718f4
RNFBPerf: d2d2facff8a3afb13670e2ee7ad0c078ecb51eb8
RNFBRemoteConfig: 05d416f414ca721b5ea215eeea8bb47360b4ab00
RNFBStorage: 336c47daa7ba460fcac8b61054f68130c618cfaa
RNFBAdMob: 220fc6f8db48fc824ebbb6704f3887a2c779254e
RNFBAnalytics: b8bad44e6653af73219b1a7af24bf3452cb02c1b
RNFBApp: 7d4006751de8bb5cafa2e8d2e7d94ee250df81db
RNFBAuth: ed8b865db45f7ded9dbf535e390cba2ba672aede
RNFBCrashlytics: 93e1cc09a93aa4bb1e9b5a07af0efb2702db5a39
RNFBDatabase: 1201eb94eff3ab457d3e898fb5c347ddc67e00db
RNFBDynamicLinks: e0d320b2bd02dee6ed1f0a7d8deecdf3469db461
RNFBFirestore: 04c1eb90463c208ee072988d463c74bec09d08c1
RNFBFunctions: 6975565f0abcc68d9731d05b78778f003db0eca5
RNFBIid: 4aa2f4fb218fd4effff8c6f947a6cfa44557d16f
RNFBInAppMessaging: 956fa7fe24e213218bb67ef2fb5db0e0aee4d091
RNFBMessaging: 51cc7f6beaf4c4feac6f18ea941bba5854e3d9c6
RNFBMLNaturalLanguage: 4aacf1c4f339a5733054e69fc8d680272d38f50c
RNFBMLVision: 352b94db5c5521c222217bfdb4d3f43ab0b2f9ea
RNFBPerf: d5c9efa43b61bdcff5ac949932055b5e5a5c132f
RNFBRemoteConfig: acfef78587e8d544b53338c07ecbc172fae1b781
RNFBStorage: 3628afb1f3dd0b3395fc15c95967b9f080897aec
yoga: 312528f5bbbba37b4dcea5ef00e8b4033fdd9411
PODFILE CHECKSUM: 4ceb34e93fa1dd96bcca7e61934b407531c8e96e

File diff suppressed because one or more lines are too long

View File

@@ -55,6 +55,15 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "testing.app"
BlueprintName = "testing"
ReferencedContainer = "container:testing.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
@@ -67,22 +76,11 @@
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "testing.app"
BlueprintName = "testing"
ReferencedContainer = "container:testing.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Release"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
@@ -99,8 +97,6 @@
ReferencedContainer = "container:testing.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
version = "1.3">
version = "1.7">
<BuildAction
parallelizeBuildables = "NO"
buildImplicitDependencies = "YES">
@@ -55,6 +55,15 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "testing.app"
BlueprintName = "testing"
ReferencedContainer = "container:testing.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
@@ -67,17 +76,6 @@
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "testing.app"
BlueprintName = "testing"
ReferencedContainer = "container:testing.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -99,8 +97,13 @@
ReferencedContainer = "container:testing.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
<EnvironmentVariables>
<EnvironmentVariable
key = "OS_ACTIVITY_MODE"
value = "disable"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
<LocationScenarioReference
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
referenceType = "1">

View File

@@ -37,6 +37,7 @@
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];
@@ -60,4 +61,20 @@
return NO;
}
- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
NSLog(@"TESTING1");
[self aTest];
NSLog(@"TESTING2");
}
- (void)aTest {
NSLog(@"TESTING3");
}
- (void)messaging:(nonnull FIRMessaging *)messaging didReceiveMessage:(nonnull FIRMessagingRemoteMessage *)remoteMessage {
NSLog(@"TESTING1");
[self aTest];
NSLog(@"TESTING2");
}
@end