mirror of
https://github.com/zhigang1992/react-native-firebase.git
synced 2026-01-12 22:50:20 +08:00
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:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -550,3 +550,7 @@ GoogleService-Info.plist
|
||||
|
||||
# generated file
|
||||
RNFBVersion.m
|
||||
|
||||
app.playground.js
|
||||
app.admob.js
|
||||
app.smartreply.js
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"peerDependencies": {
|
||||
"@react-native-firebase/app": "*"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"peerDependencies": {
|
||||
"@react-native-firebase/app": "*"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/react-native-firebase"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"peerDependencies": {
|
||||
"@react-native-firebase/app": "*"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"dependencies": {
|
||||
"stacktrace-js": "^2.0.0"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"peerDependencies": {
|
||||
"@react-native-firebase/app": "*"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"peerDependencies": {
|
||||
"@react-native-firebase/app": "*"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"peerDependencies": {
|
||||
"@react-native-firebase/app": "*"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"devDependencies": {
|
||||
"@react-native-firebase/private-tests-firebase-functions": "^0.0.1"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"peerDependencies": {
|
||||
"@react-native-firebase/app": "*"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"peerDependencies": {
|
||||
"@react-native-firebase/app": "*"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
123
packages/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m
Normal file
123
packages/messaging/ios/RNFBMessaging/RNFBMessaging+AppDelegate.m
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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]];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
212
packages/messaging/lib/index.d.ts
vendored
212
packages/messaging/lib/index.d.ts
vendored
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"peerDependencies": {
|
||||
"@react-native-firebase/app": "*"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"peerDependencies": {
|
||||
"@react-native-firebase/app": "*"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"peerDependencies": {
|
||||
"@react-native-firebase/app": "*"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"peerDependencies": {
|
||||
"@react-native-firebase/app": "*"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"peerDependencies": {
|
||||
"@react-native-firebase/app": "*"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"peerDependencies": {
|
||||
"@react-native-firebase/app": "*"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd",
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
||||
@@ -21,5 +21,5 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"gitHead": "93c6b38f6d5e8f015aab585d7d4c18674f4a63cd"
|
||||
"gitHead": "c077731efbf8edf7b393e17d3e3878e9e7f621da"
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -16,5 +16,6 @@
|
||||
*/
|
||||
|
||||
require('./app');
|
||||
// require('./app.playground');
|
||||
//require('./app.admob');
|
||||
// require('./app.smartreply');
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user