Skip to content
This repository was archived by the owner on Apr 4, 2023. It is now read-only.

Commit 36e2ae0

Browse files
iOS 10 Notification Object Structure #193
1 parent f03d82e commit 36e2ae0

File tree

3 files changed

+193
-87
lines changed

3 files changed

+193
-87
lines changed

docs/MESSAGING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ Similarly to the message callback you can either wire this through `init` or as
8181
Using the Firebase Console gives you most flexibility, but you can quickly and easily test from the command line as well:
8282

8383
```
84-
curl -X POST --header "Authorization: key=SERVER_KEY" --Header "Content-Type: application/json" https://fcm.googleapis.com/fcm/send -d "{\"notification\":{\"title\": \"My title\", \"text\": \"My text\", \"sound\": \"default\"}, \"priority\": \"High\", \"to\": \"DEVICE_TOKEN\"}"
84+
curl -X POST --header "Authorization: key=SERVER_KEY" --Header "Content-Type: application/json" https://fcm.googleapis.com/fcm/send -d "{\"notification\":{\"title\": \"My title\", \"text\": \"My text\", \"sound\": \"default\"}, \"data\":{\"foo\":\"bar\"}, \"priority\": \"High\", \"to\": \"DEVICE_TOKEN\"}"
8585
```
8686

8787
* SERVER_KEY: see below

firebase.ios.js

Lines changed: 191 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var applicationSettings = require("application-settings");
44
var utils = require("utils/utils");
55
var types = require("utils/types");
66
var frame = require("ui/frame");
7+
var platform = require("platform");
78

89
firebase._messagingConnected = null;
910
firebase._pendingNotifications = [];
@@ -58,32 +59,39 @@ firebase.addAppDelegateMethods = function(appDelegate) {
5859
}
5960

6061
if (typeof(FIRMessaging) !== "undefined") {
62+
// not required when swizzling is enabled (which is the default)
6163
appDelegate.prototype.applicationDidRegisterForRemoteNotificationsWithDeviceToken = function (application, devToken) {
62-
// TODO guard with _messagingConnected ?
6364
applicationSettings.setBoolean("registered", true);
64-
FIRInstanceID.instanceID().setAPNSTokenType(devToken, FIRInstanceIDAPNSTokenTypeUnknown);
65-
FIRMessaging.messaging().connectWithCompletion(function(error) {
66-
if (!error) {
67-
firebase._messagingConnected = true;
68-
}
69-
});
65+
/*
66+
FIRInstanceID.instanceID().setAPNSTokenType(devToken, FIRInstanceIDAPNSTokenTypeUnknown); // FIRInstanceIDAPNSTokenTypeSandbox, ..
67+
FIRMessaging.messaging().connectWithCompletion(function(error) {
68+
if (!error) {
69+
firebase._messagingConnected = true;
70+
}
71+
});
72+
*/
7073
};
7174

72-
appDelegate.prototype.applicationDidReceiveRemoteNotificationFetchCompletionHandler = function (application, userInfo, completionHandler) {
75+
appDelegate.prototype.applicationDidReceiveRemoteNotificationFetchCompletionHandler = function (app, userInfo, completionHandler) {
7376
completionHandler(UIBackgroundFetchResultNewData);
7477
var userInfoJSON = firebase.toJsObject(userInfo);
78+
var aps = userInfo.objectForKey("aps");
79+
if (aps !== null) {
80+
var alert = aps.objectForKey("alert");
81+
if (alert !== null) {
82+
userInfoJSON.title = alert.objectForKey("title");
83+
userInfoJSON.body = alert.objectForKey("body");
84+
}
85+
}
7586

76-
if (application.applicationState === UIApplicationState.UIApplicationStateActive) {
87+
firebase._pendingNotifications.push(userInfoJSON);
88+
if (app.applicationState === UIApplicationState.UIApplicationStateActive) {
89+
userInfoJSON.foreground = true;
7790
if (firebase._receivedNotificationCallback !== null) {
78-
userInfoJSON.foreground = true;
79-
firebase._receivedNotificationCallback(userInfoJSON);
80-
} else {
81-
userInfoJSON.foreground = false;
82-
firebase._pendingNotifications.push(userInfoJSON);
91+
firebase._processPendingNotifications();
8392
}
8493
} else {
8594
userInfoJSON.foreground = false;
86-
firebase._pendingNotifications.push(userInfoJSON);
8795
}
8896
};
8997
}
@@ -118,10 +126,10 @@ firebase.addOnPushTokenReceivedCallback = function (callback) {
118126
return;
119127
}
120128
firebase._receivedPushTokenCallback = callback;
121-
129+
122130
// may already be present
123131
if (firebase._pushToken) {
124-
callback(firebase._pushToken);
132+
callback(firebase._pushToken);
125133
}
126134

127135
var app = utils.ios.getter(UIApplication, UIApplication.sharedApplication);
@@ -156,11 +164,13 @@ firebase._processPendingNotifications = function() {
156164
if (firebase._receivedNotificationCallback !== null) {
157165
for (var p in firebase._pendingNotifications) {
158166
var userInfoJSON = firebase._pendingNotifications[p];
159-
console.log("Received a push notification with title: " + userInfoJSON.aps.alert.title);
160-
// move the most relevant properties so it's according to the TS definition and aligned with Android
161-
userInfoJSON.title = userInfoJSON.aps.alert.title;
162-
userInfoJSON.body = userInfoJSON.aps.alert.body;
163-
userInfoJSON.badge = userInfoJSON.aps.badge;
167+
// move the most relevant properties (if set) so it's according to the TS definition and aligned with Android
168+
if (userInfoJSON.aps && userInfoJSON.aps.alert) {
169+
userInfoJSON.title = userInfoJSON.aps.alert.title;
170+
userInfoJSON.body = userInfoJSON.aps.alert.body;
171+
}
172+
// cleanup
173+
userInfoJSON.aps = undefined;
164174
firebase._receivedNotificationCallback(userInfoJSON);
165175
}
166176
firebase._pendingNotifications = [];
@@ -198,10 +208,60 @@ firebase._registerForRemoteNotifications = function (app) {
198208
return;
199209
}
200210
firebase._registerForRemoteNotificationsRanThisSession = true;
201-
var notificationTypes = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationActivationModeBackground;
202-
var notificationSettings = UIUserNotificationSettings.settingsForTypesCategories(notificationTypes, null);
203-
app.registerForRemoteNotifications(); // prompts the user to accept notifications
204-
app.registerUserNotificationSettings(notificationSettings);
211+
212+
if (parseInt(platform.device.osVersion) >= 10) {
213+
var authorizationOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
214+
var curNotCenter = utils.ios.getter(UNUserNotificationCenter, UNUserNotificationCenter.currentNotificationCenter);
215+
curNotCenter.requestAuthorizationWithOptionsCompletionHandler(authorizationOptions, function (granted, error) {
216+
if (!error) {
217+
console.log("User granted push notifications? " + granted);
218+
// applicationSettings.setBoolean("registered", true);
219+
app.registerForRemoteNotifications();
220+
} else {
221+
console.log("Error requesting push notification auth: " + error);
222+
}
223+
});
224+
225+
firebase._userNotificationCenterDelegate = UNUserNotificationCenterDelegateImpl.new().initWithCallback(function (unnotification) {
226+
// if the app is in the foreground then this method will receive the notification
227+
// if the app is in the background, applicationDidReceiveRemoteNotificationFetchCompletionHandler will receive it
228+
var userInfo = unnotification.request.content.userInfo;
229+
var userInfoJSON = firebase.toJsObject(userInfo);
230+
userInfoJSON.foreground = true;
231+
firebase._pendingNotifications.push(userInfoJSON);
232+
if (firebase._receivedNotificationCallback !== null) {
233+
firebase._processPendingNotifications();
234+
}
235+
});
236+
curNotCenter.delegate = firebase._userNotificationCenterDelegate;
237+
238+
firebase._firebaseRemoteMessageDelegate = FIRMessagingDelegateImpl.new().initWithCallback(function (appDataDictionary) {
239+
var asJs = firebase.toJsObject(appDataDictionary.objectForKey("notification"));
240+
241+
var userInfoJSON = firebase.toJsObject(appDataDictionary);
242+
firebase._pendingNotifications.push(userInfoJSON);
243+
244+
userInfoJSON.title = asJs.title;
245+
userInfoJSON.body = asJs.body;
246+
247+
var app = utils.ios.getter(UIApplication, UIApplication.sharedApplication);
248+
if (app.applicationState === UIApplicationState.UIApplicationStateActive) {
249+
userInfoJSON.foreground = true;
250+
if (firebase._receivedNotificationCallback !== null) {
251+
firebase._processPendingNotifications();
252+
}
253+
} else {
254+
userInfoJSON.foreground = false;
255+
}
256+
});
257+
FIRMessaging.messaging().remoteMessageDelegate = firebase._firebaseRemoteMessageDelegate;
258+
259+
} else {
260+
var notificationTypes = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationActivationModeBackground;
261+
var notificationSettings = UIUserNotificationSettings.settingsForTypesCategories(notificationTypes, null);
262+
app.registerForRemoteNotifications(); // prompts the user to accept notifications
263+
app.registerUserNotificationSettings(notificationSettings);
264+
}
205265
};
206266

207267
// rather than hijacking the appDelegate for these we'll be a good citizen and listen to the notifications
@@ -294,9 +354,11 @@ firebase.toJsObject = function(objCObj) {
294354
var val = objCObj.valueForKey(key);
295355

296356
switch (types.getClass(val)) {
357+
case 'NSArray':
297358
case 'NSMutableArray':
298359
node[key] = firebase.toJsObject(val);
299360
break;
361+
case 'NSDictionary':
300362
case 'NSMutableDictionary':
301363
node[key] = firebase.toJsObject(val);
302364
break;
@@ -585,15 +647,15 @@ firebase.logout = function (arg) {
585647

586648
function toLoginResult(user) {
587649
return user && {
588-
uid: user.uid,
589-
// anonymous: user.anonymous,
590-
// provider: user.providerID,
591-
profileImageURL: user.photoURL ? user.photoURL.absoluteString : null,
592-
email: user.email,
593-
emailVerified: user.emailVerified,
594-
name: user.displayName,
595-
refreshToken: user.refreshToken
596-
};
650+
uid: user.uid,
651+
// anonymous: user.anonymous,
652+
// provider: user.providerID,
653+
profileImageURL: user.photoURL ? user.photoURL.absoluteString : null,
654+
email: user.email,
655+
emailVerified: user.emailVerified,
656+
name: user.displayName,
657+
refreshToken: user.refreshToken
658+
};
597659
}
598660

599661
firebase.getAuthToken = function (arg) {
@@ -775,28 +837,6 @@ firebase.login = function (arg) {
775837
});
776838
};
777839

778-
var GIDSignInDelegateImpl = (function (_super) {
779-
__extends(GIDSignInDelegateImpl, _super);
780-
function GIDSignInDelegateImpl() {
781-
_super.apply(this, arguments);
782-
}
783-
784-
GIDSignInDelegateImpl.new = function () {
785-
return _super.new.call(this);
786-
};
787-
GIDSignInDelegateImpl.prototype.initWithCallback = function (callback) {
788-
this._callback = callback;
789-
return this;
790-
};
791-
GIDSignInDelegateImpl.prototype.signInDidSignInForUserWithError = function (signIn, user, error) {
792-
this._callback(user, error);
793-
};
794-
if (typeof(GIDSignInDelegate) !== "undefined") {
795-
GIDSignInDelegateImpl.ObjCProtocols = [GIDSignInDelegate];
796-
}
797-
return GIDSignInDelegateImpl;
798-
})(NSObject);
799-
800840
firebase.resetPassword = function (arg) {
801841
return new Promise(function (resolve, reject) {
802842
try {
@@ -1350,33 +1390,103 @@ firebase.deleteFile = function (arg) {
13501390
};
13511391

13521392
/*
1353-
firebase.sendCrashLog = function (arg) {
1354-
return new Promise(function (resolve, reject) {
1355-
try {
1393+
firebase.sendCrashLog = function (arg) {
1394+
return new Promise(function (resolve, reject) {
1395+
try {
1396+
1397+
if (typeof(FIRCrashLog) === "undefined") {
1398+
reject("Make sure 'Firebase/Crash' is in the plugin's Podfile");
1399+
return;
1400+
}
1401+
1402+
if (!arg.log) {
1403+
reject("The mandatory 'log' argument is missing");
1404+
return;
1405+
}
1406+
1407+
if (showInConsole) {
1408+
FIRCrashNSLog(arg.log);
1409+
} else {
1410+
FIRCrashLog(arg.log);
1411+
}
1412+
1413+
resolve();
1414+
} catch (ex) {
1415+
console.log("Error in firebase.sendCrashLog: " + ex);
1416+
reject(ex);
1417+
}
1418+
});
1419+
};
1420+
*/
13561421

1357-
if (typeof(FIRCrashLog) === "undefined") {
1358-
reject("Make sure 'Firebase/Crash' is in the plugin's Podfile");
1359-
return;
1360-
}
1422+
var GIDSignInDelegateImpl = (function (_super) {
1423+
__extends(GIDSignInDelegateImpl, _super);
1424+
function GIDSignInDelegateImpl() {
1425+
_super.apply(this, arguments);
1426+
}
13611427

1362-
if (!arg.log) {
1363-
reject("The mandatory 'log' argument is missing");
1364-
return;
1365-
}
1428+
GIDSignInDelegateImpl.new = function () {
1429+
return _super.new.call(this);
1430+
};
1431+
GIDSignInDelegateImpl.prototype.initWithCallback = function (callback) {
1432+
this._callback = callback;
1433+
return this;
1434+
};
1435+
GIDSignInDelegateImpl.prototype.signInDidSignInForUserWithError = function (signIn, user, error) {
1436+
this._callback(user, error);
1437+
};
1438+
if (typeof(GIDSignInDelegate) !== "undefined") {
1439+
GIDSignInDelegateImpl.ObjCProtocols = [GIDSignInDelegate];
1440+
}
1441+
return GIDSignInDelegateImpl;
1442+
})(NSObject);
13661443

1367-
if (showInConsole) {
1368-
FIRCrashNSLog(arg.log);
1369-
} else {
1370-
FIRCrashLog(arg.log);
1371-
}
13721444

1373-
resolve();
1374-
} catch (ex) {
1375-
console.log("Error in firebase.sendCrashLog: " + ex);
1376-
reject(ex);
1377-
}
1378-
});
1379-
};
1380-
*/
1445+
// see https://developer.apple.com/reference/usernotifications/unusernotificationcenterdelegate?language=objc
1446+
var UNUserNotificationCenterDelegateImpl = (function (_super) {
1447+
__extends(UNUserNotificationCenterDelegateImpl, _super);
1448+
function UNUserNotificationCenterDelegateImpl() {
1449+
_super.apply(this, arguments);
1450+
}
1451+
1452+
UNUserNotificationCenterDelegateImpl.new = function () {
1453+
return _super.new.call(this);
1454+
};
1455+
UNUserNotificationCenterDelegateImpl.prototype.initWithCallback = function (callback) {
1456+
this._callback = callback;
1457+
return this;
1458+
};
1459+
UNUserNotificationCenterDelegateImpl.prototype.userNotificationCenterWillPresentNotificationWithCompletionHandler = function (unCenter, notification, completionHandler) {
1460+
this._callback(notification);
1461+
};
1462+
if (typeof(UNUserNotificationCenterDelegate) !== "undefined") {
1463+
UNUserNotificationCenterDelegateImpl.ObjCProtocols = [UNUserNotificationCenterDelegate];
1464+
}
1465+
return UNUserNotificationCenterDelegateImpl;
1466+
})(NSObject);
1467+
1468+
1469+
// see https://firebase.google.com/docs/reference/ios/firebasemessaging/api/reference/Protocols/FIRMessagingDelegate
1470+
var FIRMessagingDelegateImpl = (function (_super) {
1471+
__extends(FIRMessagingDelegateImpl, _super);
1472+
function FIRMessagingDelegateImpl() {
1473+
_super.apply(this, arguments);
1474+
}
1475+
1476+
FIRMessagingDelegateImpl.new = function () {
1477+
return _super.new.call(this);
1478+
};
1479+
FIRMessagingDelegateImpl.prototype.initWithCallback = function (callback) {
1480+
this._callback = callback;
1481+
return this;
1482+
};
1483+
FIRMessagingDelegateImpl.prototype.applicationReceivedRemoteMessage = function (firMessagingRemoteMessage) {
1484+
this._callback(firMessagingRemoteMessage.appData);
1485+
};
1486+
if (typeof(FIRMessagingDelegate) !== "undefined") {
1487+
FIRMessagingDelegateImpl.ObjCProtocols = [FIRMessagingDelegate];
1488+
}
1489+
return FIRMessagingDelegateImpl;
1490+
})(NSObject);
13811491

13821492
module.exports = firebase;

index.d.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ export interface GetRemoteConfigResult {
321321
* The returned object in the callback handler of the addOnMessageReceivedCallback function.
322322
*
323323
* Note that any custom data you send from your server will be available as
324-
* key/value properties on the Message object.
324+
* key/value properties on the Message object as well.
325325
*/
326326
export interface Message {
327327
/**
@@ -338,10 +338,6 @@ export interface Message {
338338
* Not available on Android when the notification was received in the background.
339339
*/
340340
title?: string;
341-
/**
342-
* iOS badge count, as sent from the server.
343-
*/
344-
badge?: number;
345341
}
346342

347343
export interface ProgressStatus {

0 commit comments

Comments
 (0)