Commit 6476026b authored by Lidan Hifi's avatar Lidan Hifi

added local notifications support

parent 46a443b8
......@@ -5,4 +5,4 @@ Handle push notifications for your app, including remote and local notifications
**Work in progress, please notice that this library is not production-ready yet!**
## TODO
- Better support of local notifications.
- Android support.
......@@ -48,7 +48,7 @@ RCT_ENUM_CONVERTER(UIUserNotificationActionBehavior, (@{
{
NSDictionary<NSString *, id> *details = [self NSDictionary:json];
UIMutableUserNotificationAction* action =[[UIMutableUserNotificationAction alloc] init];
UIMutableUserNotificationAction* action =[UIMutableUserNotificationAction new];
action.activationMode = [RCTConvert UIUserNotificationActivationMode:details[@"activationMode"]];
action.behavior = [RCTConvert UIUserNotificationActionBehavior:details[@"behavior"]];
action.authenticationRequired = [RCTConvert BOOL:details[@"authenticationRequired"]];
......@@ -65,11 +65,11 @@ RCT_ENUM_CONVERTER(UIUserNotificationActionBehavior, (@{
{
NSDictionary<NSString *, id> *details = [self NSDictionary:json];
UIMutableUserNotificationCategory* category = [[UIMutableUserNotificationCategory alloc] init];
UIMutableUserNotificationCategory* category = [UIMutableUserNotificationCategory new];
category.identifier = details[@"identifier"];
// category actions
NSMutableArray* actions = [[NSMutableArray alloc] init];
NSMutableArray* actions = [NSMutableArray new];
for (NSDictionary* actionJson in [RCTConvert NSArray:details[@"actions"]]) {
[actions addObject:[RCTConvert UIMutableUserNotificationAction:actionJson]];
}
......@@ -80,6 +80,24 @@ RCT_ENUM_CONVERTER(UIUserNotificationActionBehavior, (@{
}
@end
@implementation RCTConvert (UILocalNotification)
+ (UILocalNotification *)UILocalNotification:(id)json
{
NSDictionary<NSString *, id> *details = [self NSDictionary:json];
UILocalNotification* notification = [UILocalNotification new];
notification.fireDate = [RCTConvert NSDate:details[@"fireDate"]];
notification.alertBody = [RCTConvert NSString:details[@"alertBody"]];
notification.alertTitle = [RCTConvert NSString:details[@"alertTitle"]];
notification.alertAction = [RCTConvert NSString:details[@"alertAction"]];
notification.soundName = [RCTConvert NSString:details[@"soundName"]] ?: UILocalNotificationDefaultSoundName;
notification.userInfo = [RCTConvert NSDictionary:details[@"userInfo"]] ?: @{};
notification.category = [RCTConvert NSString:details[@"category"]];
return notification;
}
@end
@implementation RNNotifications
RCT_EXPORT_MODULE()
......@@ -163,7 +181,9 @@ RCT_EXPORT_MODULE()
{
UIApplicationState state = [UIApplication sharedApplication].applicationState;
if (state == UIApplicationStateInactive) {
if (state == UIApplicationStateActive) {
[self didReceiveNotificationOnForegroundState:notification.userInfo];
} else if (state == UIApplicationStateInactive) {
NSString* notificationId = [notification.userInfo objectForKey:@"notificationId"];
if (notificationId) {
[self clearNotificationFromNotificationsCenter:notificationId];
......@@ -243,7 +263,7 @@ RCT_EXPORT_MODULE()
&& alert) {
// trigger new client push notification
UILocalNotification* note = [[UILocalNotification alloc] init];
UILocalNotification* note = [UILocalNotification new];
note.alertTitle = [alert objectForKey:@"title"];
note.alertBody = [alert objectForKey:@"body"];
note.userInfo = notification;
......@@ -393,7 +413,7 @@ RCT_EXPORT_METHOD(requestPermissionsWithCategories:(NSArray *)json)
NSMutableSet* categories = nil;
if ([json count] > 0) {
categories = [[NSMutableSet alloc] init];
categories = [NSMutableSet new];
for (NSDictionary* categoryJson in json) {
[categories addObject:[RCTConvert UIMutableUserNotificationCategory:categoryJson]];
}
......@@ -445,4 +465,13 @@ RCT_EXPORT_METHOD(consumeBackgroundQueue)
[RNNotificationsBridgeQueue sharedInstance].jsIsReady = YES;
}
RCT_EXPORT_METHOD(localNotification:(NSDictionary *)notification)
{
if ([notification objectForKey:@"fireDate"] != nil) {
[RCTSharedApplication() scheduleLocalNotification:[RCTConvert UILocalNotification:notification]];
} else {
[RCTSharedApplication() presentLocalNotificationNow:[RCTConvert UILocalNotification:notification]];
}
}
@end
......@@ -58,6 +58,8 @@ class NotificationsExampleApp extends Component {
NotificationsIOS.addEventListener('notificationReceivedForeground', this.onNotificationReceivedForeground.bind(this));
NotificationsIOS.addEventListener('notificationReceivedBackground', this.onNotificationReceivedBackground.bind(this));
NotificationsIOS.addEventListener('notificationOpened', this.onNotificationOpened.bind(this));
}
onPushRegistered(deviceToken) {
......@@ -75,6 +77,15 @@ class NotificationsExampleApp extends Component {
onNotificationReceivedBackground(notification) {
NotificationsIOS.log("Notification Received Background: " + JSON.stringify(notification));
NotificationsIOS.localNotification({
alertBody: "Received background notificiation!",
alertTitle: "Local Notification Title",
alertAction: "Click here to open",
soundName: "chime.aiff",
category: "SOME_CATEGORY",
userInfo: notification.getData()
});
// NotificationsIOS.backgroundTimeRemaining(time => NotificationsIOS.log("remaining background time: " + time));
}
......
......@@ -161,7 +161,24 @@ export default class NotificationsIOS {
NativeRNNotifications.consumeBackgroundQueue();
}
static log(message) {
static log(message: string) {
NativeRNNotifications.log(message);
}
/**
* Presenting local notification
*
* notification is an object containing:
*
* - `alertBody` : The message displayed in the notification alert.
* - `alertTitle` : The message title displayed in the notification.
* - `alertAction` : The "action" displayed beneath an actionable notification. Defaults to "view";
* - `soundName` : The sound played when the notification is fired (optional).
* - `category` : The category of this notification, required for actionable notifications (optional).
* - `userInfo` : An optional object containing additional notification data.
* - `fireDate` : The date and time when the system should deliver the notification. if not specified, the notification will be dispatched immediately.
*/
static localNotification(notification: Object) {
NativeRNNotifications.localNotification(notification);
}
}
......@@ -23,7 +23,8 @@ describe("NotificationsIOS", () => {
nativeAbandonPermissions,
nativeRegisterPushKit,
nativeBackgroundTimeRemaining,
nativeConsumeBackgroundQueue;
nativeConsumeBackgroundQueue,
nativeLocalNotification;
let NotificationsIOS, NotificationAction, NotificationCategory;
let someHandler = () => {};
/*eslint-enable indent*/
......@@ -38,6 +39,7 @@ describe("NotificationsIOS", () => {
nativeRegisterPushKit = sinon.spy();
nativeBackgroundTimeRemaining = sinon.spy();
nativeConsumeBackgroundQueue = sinon.spy();
nativeLocalNotification = sinon.spy();
let libUnderTest = proxyquire("../index.ios", {
"react-native": {
......@@ -47,7 +49,8 @@ describe("NotificationsIOS", () => {
abandonPermissions: nativeAbandonPermissions,
registerPushKit: nativeRegisterPushKit,
backgroundTimeRemaining: nativeBackgroundTimeRemaining,
consumeBackgroundQueue: nativeConsumeBackgroundQueue
consumeBackgroundQueue: nativeConsumeBackgroundQueue,
localNotification: nativeLocalNotification
}
},
NativeAppEventEmitter: {
......@@ -83,6 +86,7 @@ describe("NotificationsIOS", () => {
nativeRegisterPushKit.reset();
nativeBackgroundTimeRemaining.reset();
nativeConsumeBackgroundQueue.reset();
nativeLocalNotification.reset();
});
after(() => {
......@@ -95,6 +99,7 @@ describe("NotificationsIOS", () => {
nativeRegisterPushKit = null;
nativeBackgroundTimeRemaining = null;
nativeConsumeBackgroundQueue = null;
nativeLocalNotification = null;
NotificationsIOS = null;
NotificationAction = null;
......@@ -216,11 +221,30 @@ describe("NotificationsIOS", () => {
});
});
describe("Get background remaining time", () => {
describe("Consume background queue which holds background notificiations and actions until js thread is ready", () => {
it("should call native consume background queue method", () => {
NotificationsIOS.consumeBackgroundQueue();
expect(nativeConsumeBackgroundQueue).to.have.been.called;
});
});
describe("Get background remaining time", () => {
it("should call native consume background queue method", () => {
let someLocalNotification = {
alertBody: "some body",
alertTitle: "some title",
alertAction: "some action",
soundName: "sound",
category: "SOME_CATEGORY",
userInfo: {
"key": "value"
}
};
NotificationsIOS.localNotification(someLocalNotification);
expect(nativeLocalNotification).to.have.been.calledWith(someLocalNotification);
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment