Skip to content

Commit 62538d7

Browse files
Ensure sound is assigned with right type (#8203)
1 parent 6a769f2 commit 62538d7

File tree

4 files changed

+166
-50
lines changed

4 files changed

+166
-50
lines changed

FirebaseMessaging/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# 2021-06 -- v8.2.0
2+
- [fixed] Fixed an issue that local scheduled notification is not set correctly due to sound type. (#8172)
3+
14
# 2021-05 -- v8.1.0
25
- [fixed] Fixed an issue that notification open is not logged to Analytics correctly when app is completely shut off. (#7707, #8128).
36

FirebaseMessaging/Sources/FIRMessagingContextManagerService.m

Lines changed: 62 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -136,62 +136,75 @@ + (BOOL)handleContextManagerLocalTimeMessage:(NSDictionary *)message {
136136
return YES;
137137
}
138138

139-
+ (void)scheduleiOS10LocalNotificationForMessage:(NSDictionary *)message atDate:(NSDate *)date {
139+
+ (void)scheduleiOS10LocalNotificationForMessage:(NSDictionary *)message
140+
atDate:(NSDate *)date
141+
API_AVAILABLE(macosx(10.14), ios(10.0), watchos(3.0), tvos(10.0)) {
140142
NSCalendar *calendar = [NSCalendar currentCalendar];
141-
if (@available(macOS 10.14, iOS 10.0, watchOS 3.0, tvOS 10.0, *)) {
142-
NSCalendarUnit unit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay |
143-
NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
144-
NSDateComponents *dateComponents = [calendar components:(NSCalendarUnit)unit fromDate:date];
145-
UNCalendarNotificationTrigger *trigger =
146-
[UNCalendarNotificationTrigger triggerWithDateMatchingComponents:dateComponents repeats:NO];
147-
148-
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
149-
NSDictionary *apsDictionary = message;
150-
151-
// Badge is universal
152-
if (apsDictionary[kFIRMessagingContextManagerBadgeKey]) {
153-
content.badge = apsDictionary[kFIRMessagingContextManagerBadgeKey];
154-
}
143+
NSCalendarUnit unit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay |
144+
NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
145+
NSDateComponents *dateComponents = [calendar components:(NSCalendarUnit)unit fromDate:date];
146+
UNCalendarNotificationTrigger *trigger =
147+
[UNCalendarNotificationTrigger triggerWithDateMatchingComponents:dateComponents repeats:NO];
148+
149+
UNMutableNotificationContent *content = [self contentFromContextualMessage:message];
150+
NSString *identifier = message[kFIRMessagingID];
151+
if (!identifier) {
152+
identifier = [NSUUID UUID].UUIDString;
153+
}
154+
155+
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier
156+
content:content
157+
trigger:trigger];
158+
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
159+
[center
160+
addNotificationRequest:request
161+
withCompletionHandler:^(NSError *_Nullable error) {
162+
if (error) {
163+
FIRMessagingLoggerError(kFIRMessagingMessageCodeContextManagerServiceFailedLocalSchedule,
164+
@"Failed scheduling local timezone notification: %@.", error);
165+
}
166+
}];
167+
}
168+
169+
+ (UNMutableNotificationContent *)contentFromContextualMessage:(NSDictionary *)message
170+
API_AVAILABLE(macosx(10.14), ios(10.0), watchos(3.0), tvos(10.0)) {
171+
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
172+
NSDictionary *apsDictionary = message;
173+
174+
// Badge is universal
175+
if (apsDictionary[kFIRMessagingContextManagerBadgeKey]) {
176+
content.badge = apsDictionary[kFIRMessagingContextManagerBadgeKey];
177+
}
155178
#if TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_WATCH
156-
// The following fields are not available on tvOS
157-
if ([apsDictionary[kFIRMessagingContextManagerBodyKey] length]) {
158-
content.body = apsDictionary[kFIRMessagingContextManagerBodyKey];
159-
}
160-
if ([apsDictionary[kFIRMessagingContextManagerTitleKey] length]) {
161-
content.title = apsDictionary[kFIRMessagingContextManagerTitleKey];
162-
}
179+
// The following fields are not available on tvOS
180+
if ([apsDictionary[kFIRMessagingContextManagerBodyKey] length]) {
181+
content.body = apsDictionary[kFIRMessagingContextManagerBodyKey];
182+
}
163183

164-
if (apsDictionary[kFIRMessagingContextManagerSoundKey]) {
165-
content.sound = apsDictionary[kFIRMessagingContextManagerSoundKey];
166-
}
184+
if ([apsDictionary[kFIRMessagingContextManagerTitleKey] length]) {
185+
content.title = apsDictionary[kFIRMessagingContextManagerTitleKey];
186+
}
167187

168-
if (apsDictionary[kFIRMessagingContextManagerCategoryKey]) {
169-
content.categoryIdentifier = apsDictionary[kFIRMessagingContextManagerCategoryKey];
170-
}
188+
if (apsDictionary[kFIRMessagingContextManagerSoundKey]) {
189+
#if !TARGET_OS_WATCH
190+
// UNNotificationSound soundNamded: is not available in watchOS
191+
content.sound =
192+
[UNNotificationSound soundNamed:apsDictionary[kFIRMessagingContextManagerSoundKey]];
193+
#else // !TARGET_OS_WATCH
194+
content.sound = [UNNotificationSound defaultSound];
195+
#endif // !TARGET_OS_WATCH
196+
}
171197

172-
NSDictionary *userInfo = [self parseDataFromMessage:message];
173-
if (userInfo.count) {
174-
content.userInfo = userInfo;
175-
}
176-
#endif
177-
NSString *identifier = apsDictionary[kFIRMessagingID];
178-
if (!identifier) {
179-
identifier = [NSUUID UUID].UUIDString;
180-
}
198+
if (apsDictionary[kFIRMessagingContextManagerCategoryKey]) {
199+
content.categoryIdentifier = apsDictionary[kFIRMessagingContextManagerCategoryKey];
200+
}
181201

182-
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier
183-
content:content
184-
trigger:trigger];
185-
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
186-
[center addNotificationRequest:request
187-
withCompletionHandler:^(NSError *_Nullable error) {
188-
if (error) {
189-
FIRMessagingLoggerError(
190-
kFIRMessagingMessageCodeContextManagerServiceFailedLocalSchedule,
191-
@"Failed scheduling local timezone notification: %@.", error);
192-
}
193-
}];
202+
NSDictionary *userInfo = [self parseDataFromMessage:message];
203+
if (userInfo.count) {
204+
content.userInfo = userInfo;
194205
}
206+
#endif // TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_WATCH
207+
return content;
195208
}
196209

197210
+ (void)scheduleLocalNotificationForMessage:(NSDictionary *)message atDate:(NSDate *)date {

FirebaseMessaging/Tests/UnitTests/FIRMessagingContextManagerServiceTest.m

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,21 @@
2424
#import "FirebaseMessaging/Sources/FIRMessagingContextManagerService.h"
2525

2626
static NSString *const kBody = @"Save 20% off!";
27+
static NSString *const kTitle = @"Sparky WFH";
28+
static NSString *const kSoundName = @"default";
29+
static NSString *const kAction = @"open";
2730
static NSString *const kUserInfoKey1 = @"level";
2831
static NSString *const kUserInfoKey2 = @"isPayUser";
2932
static NSString *const kUserInfoValue1 = @"5";
3033
static NSString *const kUserInfoValue2 = @"Yes";
3134
static NSString *const kMessageIdentifierKey = @"gcm.message_id";
3235
static NSString *const kMessageIdentifierValue = @"1584748495200141";
3336

37+
@interface FIRMessagingContextManagerService (ExposedForTest)
38+
+ (void)scheduleiOS10LocalNotificationForMessage:(NSDictionary *)message atDate:(NSDate *)date;
39+
+ (UNMutableNotificationContent *)contentFromContextualMessage:(NSDictionary *)message;
40+
@end
41+
3442
API_AVAILABLE(macos(10.14))
3543
@interface FIRMessagingContextManagerServiceTest : XCTestCase
3644

@@ -269,4 +277,85 @@ - (void)mockSchedulingLocalNotifications {
269277
#endif
270278
}
271279

280+
- (void)testScheduleiOS10LocalNotification {
281+
if (@available(macOS 10.14, iOS 10.0, watchOS 3.0, tvOS 10.0, *)) {
282+
id mockContextManagerService = OCMClassMock([FIRMessagingContextManagerService class]);
283+
NSDictionary *message = @{};
284+
285+
[FIRMessagingContextManagerService scheduleiOS10LocalNotificationForMessage:message
286+
atDate:[NSDate date]];
287+
OCMVerify([mockContextManagerService contentFromContextualMessage:message]);
288+
[mockContextManagerService stopMocking];
289+
}
290+
}
291+
292+
- (void)testContentFromConetxtualMessage {
293+
if (@available(macOS 10.14, iOS 10.0, watchOS 3.0, tvOS 10.0, *)) {
294+
NSDictionary *message = @{
295+
@"aps" : @{@"content-available" : @1},
296+
@"gcm.message_id" : @1623702615599207,
297+
@"gcm.n.e" : @1,
298+
@"gcm.notification.badge" : @1,
299+
@"gcm.notification.body" : kBody,
300+
@"gcm.notification.image" :
301+
@"https://firebasestorage.googleapis.com/v0/b/fir-ios-app-extensions.appspot.com/o/"
302+
@"sparkyWFH.png?alt=media&token=f4dc1533-4d80-4ed6-9870-8df528593157",
303+
@"gcm.notification.mutable_content" : @1,
304+
@"gcm.notification.sound" : kSoundName,
305+
@"gcm.notification.sound2" : kSoundName,
306+
@"gcm.notification.title" : kTitle,
307+
// This field is not popped out from console
308+
// Manual add here to test unit test
309+
@"gcm.notification.click_action" : kAction,
310+
@"gcms" : @"gcm.gmsproc.cm",
311+
@"google.c.a.c_id" : @2159728303499680621,
312+
@"google.c.a.c_l" : @"test local send with sound",
313+
@"google.c.a.e" : @1,
314+
@"google.c.a.ts" : @1623753000,
315+
@"google.c.a.udt" : @1,
316+
@"google.c.cm.lt_end" : @"2021-07-13 10:30:00",
317+
@"google.c.cm.lt_start" : @"2021-06-15 10:30:00",
318+
@"google.c.sender.id" : @449451107265,
319+
};
320+
UNMutableNotificationContent *content =
321+
[FIRMessagingContextManagerService contentFromContextualMessage:message];
322+
XCTAssertEqualObjects(content.badge, @1);
323+
324+
#if TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_WATCH
325+
XCTAssertEqualObjects(content.body, kBody);
326+
XCTAssertEqualObjects(content.title, kTitle);
327+
#if !TARGET_OS_WATCH
328+
XCTAssertEqualObjects(content.sound, [UNNotificationSound soundNamed:kSoundName]);
329+
#else // !TARGET_OS_WATCH
330+
XCTAssertEqualObjects(content.sound, [UNNotificationSound defaultSound]);
331+
#endif // !TARGET_OS_WATCH
332+
XCTAssertEqualObjects(content.categoryIdentifier, kAction);
333+
NSDictionary *userInfo = @{
334+
@"gcm.message_id" : @1623702615599207,
335+
@"gcm.n.e" : @1,
336+
@"gcm.notification.badge" : @1,
337+
@"gcm.notification.body" : kBody,
338+
@"gcm.notification.image" :
339+
@"https://firebasestorage.googleapis.com/v0/b/fir-ios-app-extensions.appspot.com/o/"
340+
@"sparkyWFH.png?alt=media&token=f4dc1533-4d80-4ed6-9870-8df528593157",
341+
@"gcm.notification.mutable_content" : @1,
342+
@"gcm.notification.sound" : kSoundName,
343+
@"gcm.notification.sound2" : kSoundName,
344+
@"gcm.notification.title" : kTitle,
345+
// This field is not popped out from console
346+
// Manual add here to test unit test
347+
@"gcm.notification.click_action" : kAction,
348+
@"gcms" : @"gcm.gmsproc.cm",
349+
@"google.c.a.c_id" : @2159728303499680621,
350+
@"google.c.a.c_l" : @"test local send with sound",
351+
@"google.c.a.e" : @1,
352+
@"google.c.a.ts" : @1623753000,
353+
@"google.c.a.udt" : @1,
354+
@"google.c.sender.id" : @449451107265
355+
};
356+
XCTAssertEqualObjects(content.userInfo, userInfo);
357+
#endif // TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_WATCH
358+
}
359+
}
360+
272361
@end

FirebaseMessaging/Tests/UnitTests/FIRMessagingUtilitiesTest.m

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,21 @@ - (void)testAppVersionReturnsEmptyStringWhenNotFound {
6868
}
6969

7070
- (void)testAppIdentifierReturnsExpectedValue {
71+
#if TARGET_OS_WATCH
72+
NSString *bundleIdentifier = @"com.me.myapp.watchkit.watchkitextensions";
73+
NSString *expectedIdentifier = @"com.me.myapp.watchkit";
74+
#else
75+
NSString *bundleIdentifier = @"com.me.myapp";
7176
NSString *expectedIdentifier = @"com.me.myapp";
72-
[[[_mainBundleMock stub] andReturn:expectedIdentifier] bundleIdentifier];
77+
#endif
78+
79+
[[[_mainBundleMock stub] andReturn:bundleIdentifier] bundleIdentifier];
7380
NSString *appIdentifier = FIRMessagingAppIdentifier();
81+
#if TARGET_OS_WATCH
82+
XCTAssertEqualObjects(appIdentifier, expectedIdentifier);
83+
#else
7484
XCTAssertEqualObjects(appIdentifier, expectedIdentifier);
85+
#endif
7586
}
7687

7788
- (void)testAppIdentifierReturnsEmptyStringWhenNotFound {

0 commit comments

Comments
 (0)