Skip to content

Commit 4736e05

Browse files
Add a boolean value on whether to use direct channel callback for all ios versions (#1875)
1 parent b11aab6 commit 4736e05

File tree

7 files changed

+145
-15
lines changed

7 files changed

+145
-15
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright 2018 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import <XCTest/XCTest.h>
18+
19+
#import <OCMock/OCMock.h>
20+
21+
#import <FirebaseInstanceID/FirebaseInstanceID.h>
22+
23+
#import "FIRMessaging.h"
24+
#import "FIRMessaging_Private.h"
25+
26+
@interface FIRMessagingReceiverTest : XCTestCase
27+
@property(nonatomic, readonly, strong) FIRMessaging *messaging;
28+
29+
@end
30+
31+
@implementation FIRMessagingReceiverTest
32+
- (void)setUp {
33+
[super setUp];
34+
35+
_messaging = [FIRMessaging messaging];
36+
[[NSUserDefaults standardUserDefaults]
37+
removePersistentDomainForName:[NSBundle mainBundle].bundleIdentifier];
38+
}
39+
40+
- (void)testUseMessagingDelegate {
41+
XCTAssertFalse(_messaging.useMessagingDelegateForDirectChannel);
42+
43+
_messaging.useMessagingDelegateForDirectChannel = YES;
44+
XCTAssertTrue(_messaging.useMessagingDelegateForDirectChannel);
45+
}
46+
47+
- (void)testUseMessagingDelegateFlagOverridedByPlistWithFalseValue {
48+
id bundleMock = OCMPartialMock([NSBundle mainBundle]);
49+
OCMStub([bundleMock objectForInfoDictionaryKey:kFIRMessagingPlistUseMessagingDelegate])
50+
.andReturn(nil);
51+
XCTAssertFalse(_messaging.useMessagingDelegateForDirectChannel);
52+
53+
[bundleMock stopMocking];
54+
}
55+
56+
- (void)testUseMessagingDelegateFlagOverridedByPlistWithTrueValue {
57+
id bundleMock = OCMPartialMock([NSBundle mainBundle]);
58+
OCMStub([bundleMock objectForInfoDictionaryKey:kFIRMessagingPlistUseMessagingDelegate])
59+
.andReturn(@YES);
60+
XCTAssertTrue(_messaging.useMessagingDelegateForDirectChannel);
61+
62+
[bundleMock stopMocking];
63+
}
64+
@end

Firebase/Messaging/FIRMessaging.m

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,15 @@ - (void)notifyDelegateOfFCMTokenAvailability {
621621
}
622622
}
623623

624+
625+
- (void)setUseMessagingDelegateForDirectChannel:(BOOL)useMessagingDelegateForDirectChannel {
626+
self.receiver.useDirectChannel = useMessagingDelegateForDirectChannel;
627+
}
628+
629+
- (BOOL)useMessagingDelegateForDirectChannel {
630+
return self.receiver.useDirectChannel;
631+
}
632+
624633
#pragma mark - Application State Changes
625634

626635
- (void)applicationStateChanged {

Firebase/Messaging/FIRMessagingReceiver.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525

2626
@end
2727

28-
2928
@interface FIRMessagingReceiver : NSObject <FIRMessagingDataMessageManagerDelegate>
29+
3030
@property(nonatomic, weak, nullable) id<FIRMessagingReceiverDelegate> delegate;
31+
/// Whether to use direct channel for direct channel message callback handler in all iOS versions.
32+
@property(nonatomic, assign) BOOL useDirectChannel;
33+
3134
@end

Firebase/Messaging/FIRMessagingReceiver.m

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,21 @@
1818

1919
#import <UIKit/UIKit.h>
2020

21+
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
22+
2123
#import "FIRMessaging.h"
2224
#import "FIRMessagingLogger.h"
2325
#import "FIRMessagingUtilities.h"
2426
#import "FIRMessaging_Private.h"
2527

2628
static NSString *const kUpstreamMessageIDUserInfoKey = @"messageID";
2729
static NSString *const kUpstreamErrorUserInfoKey = @"error";
28-
29-
// Copied from Apple's header in case it is missing in some cases.
30-
#ifndef NSFoundationVersionNumber_iOS_9_x_Max
31-
#define NSFoundationVersionNumber_iOS_9_x_Max 1299
32-
#endif
30+
/// "Should use Messaging delegate" key stored in NSUserDefaults
31+
NSString *const kFIRMessagingUserDefaultsKeyUseMessagingDelegate =
32+
@"com.firebase.messaging.useMessagingDelegate";
33+
/// "Should use Messaging Delegate" key stored in Info.plist
34+
NSString *const kFIRMessagingPlistUseMessagingDelegate =
35+
@"FirebaseMessagingUseMessagingDelegateForDirectChannel";
3336

3437
static int downstreamMessageID = 0;
3538

@@ -42,8 +45,9 @@ - (void)didReceiveMessage:(NSDictionary *)message withIdentifier:(nullable NSStr
4245
messageID = [[self class] nextMessageID];
4346
}
4447

45-
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_9_x_Max) {
46-
// Use delegate method for iOS 10
48+
NSInteger majorOSVersion = [[GULAppEnvironmentUtil systemVersion] integerValue];
49+
if (majorOSVersion >= 10 || self.useDirectChannel) {
50+
// iOS 10 and above or use direct channel is enabled.
4751
[self scheduleIos10NotificationForMessage:message withIdentifier:messageID];
4852
} else {
4953
// Post notification directly to AppDelegate handlers. This is valid pre-iOS 10.
@@ -146,4 +150,33 @@ + (NSString *)nextMessageID {
146150
}
147151
}
148152

153+
- (BOOL)useDirectChannel {
154+
// Check storage
155+
NSUserDefaults *messagingDefaults = [NSUserDefaults standardUserDefaults];
156+
id shouldUseMessagingDelegate =
157+
[messagingDefaults objectForKey:kFIRMessagingUserDefaultsKeyUseMessagingDelegate];
158+
if (shouldUseMessagingDelegate) {
159+
return [shouldUseMessagingDelegate boolValue];
160+
}
161+
162+
// Check Info.plist
163+
shouldUseMessagingDelegate =
164+
[[NSBundle mainBundle] objectForInfoDictionaryKey:kFIRMessagingPlistUseMessagingDelegate];
165+
if (shouldUseMessagingDelegate) {
166+
return [shouldUseMessagingDelegate boolValue];
167+
}
168+
// If none of above exists, we go back to default behavior which is NO.
169+
return NO;
170+
}
171+
172+
- (void)setUseDirectChannel:(BOOL)useDirectChannel {
173+
NSUserDefaults *messagingDefaults = [NSUserDefaults standardUserDefaults];
174+
BOOL shouldUseMessagingDelegate = [self useDirectChannel];
175+
if (useDirectChannel != shouldUseMessagingDelegate) {
176+
[messagingDefaults setBool:useDirectChannel
177+
forKey:kFIRMessagingUserDefaultsKeyUseMessagingDelegate];
178+
[messagingDefaults synchronize];
179+
}
180+
}
181+
149182
@end

Firebase/Messaging/FIRMessaging_Private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ typedef NS_ENUM(int8_t, FIRMessagingNetworkStatus) {
2727

2828
FOUNDATION_EXPORT NSString *const kFIRMessagingPlistAutoInitEnabled;
2929
FOUNDATION_EXPORT NSString *const kFIRMessagingUserDefaultsKeyAutoInitEnabled;
30+
FOUNDATION_EXPORT NSString *const kFIRMessagingUserDefaultsKeyUseMessagingDelegate;
31+
FOUNDATION_EXPORT NSString *const kFIRMessagingPlistUseMessagingDelegate;
3032

3133
@interface FIRMessagingRemoteMessage ()
3234

Firebase/Messaging/Public/FIRMessaging.h

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,11 @@ NS_SWIFT_NAME(MessagingDelegate)
260260
didReceiveRegistrationToken:(NSString *)fcmToken
261261
NS_SWIFT_NAME(messaging(_:didReceiveRegistrationToken:));
262262

263-
/// This method is called on iOS 10 devices to handle data messages received via FCM through its
264-
/// direct channel (not via APNS). For iOS 9 and below, the FCM data message is delivered via the
265-
/// UIApplicationDelegate's -application:didReceiveRemoteNotification: method.
263+
/// This method is called on iOS 10+ devices to handle data messages received via FCM
264+
/// direct channel (not via APNS). For iOS 9 and below, the direct channel data message
265+
/// is handled by the UIApplicationDelegate's -application:didReceiveRemoteNotification: method.
266+
/// You can enable all direct channel data messages to be delivered in FIRMessagingDelegate
267+
/// by setting the flag `useMessagingDelegateForDirectMessages` to true.
266268
- (void)messaging:(FIRMessaging *)messaging
267269
didReceiveMessage:(FIRMessagingRemoteMessage *)remoteMessage
268270
NS_SWIFT_NAME(messaging(_:didReceive:))
@@ -277,14 +279,14 @@ NS_SWIFT_NAME(MessagingDelegate)
277279
* registration token from FIRInstanceID. This token authorizes an
278280
* app server to send messages to an app instance.
279281
*
280-
* In order to receive FIRMessaging messages, declare `application:didReceiveRemoteNotification:`.
282+
* In order to receive FIRMessaging messages, declare
283+
* `application:didReceiveRemoteNotification::fetchCompletionHandler:`.
281284
*/
282285
NS_SWIFT_NAME(Messaging)
283286
@interface FIRMessaging : NSObject
284287

285288
/**
286-
* Delegate to handle FCM token refreshes, and remote data messages received via FCM for devices
287-
* running iOS 10 or above.
289+
* Delegate to handle FCM token refreshes, and remote data messages received via FCM direct channel.
288290
*/
289291
@property(nonatomic, weak, nullable) id<FIRMessagingDelegate> delegate;
290292

@@ -301,6 +303,22 @@ NS_SWIFT_NAME(Messaging)
301303
*/
302304
@property(nonatomic, readonly) BOOL isDirectChannelEstablished;
303305

306+
/*
307+
* Whether direct channel message should only use FIRMessagingDelegate messaging(_:didReceive:)
308+
* for message delivery callback. The default value is false. If you need to change
309+
* the default, set FirebaseMessagingUseMessagingDelegateForDirectChannel to true in
310+
* your application’s Info.plist.
311+
*
312+
* If false, the message via direct channel for iOS 9 and below is still delivered in
313+
* `-UIApplicationDelegate application(_:didReceiveRemoteNotification:fetchCompletionHandler:)`,
314+
* and the FIRMessagingRemoteMessage object and its associated data will be unavailable.
315+
* For iOS 10 and above, it is still delivered in `FIRMessagingDelegate messaging(_:didReceive:)`.
316+
*
317+
* If true, the data message sent by direct channel will be delivered via
318+
* `FIRMessagingDelegate messaging(_:didReceive:)` and across all iOS versions.
319+
*/
320+
@property(nonatomic, assign) BOOL useMessagingDelegateForDirectChannel;
321+
304322
/**
305323
* FIRMessaging
306324
*
@@ -413,7 +431,7 @@ NS_SWIFT_NAME(Messaging)
413431
NS_SWIFT_NAME(deleteFCMToken(forSenderID:completion:));
414432

415433

416-
#pragma mark - Connect
434+
#pragma mark - FCM Direct Channel
417435

418436
/**
419437
* Create a FIRMessaging data connection which will be used to send the data notifications

FirebaseMessaging.podspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,6 @@ device, and it is completely free.
3939
s.dependency 'FirebaseCore', '~> 5.0'
4040
s.dependency 'FirebaseInstanceID', '~> 3.0'
4141
s.dependency 'GoogleUtilities/Reachability', '~> 5.2'
42+
s.dependency 'GoogleUtilities/Environment', '~> 5.2'
4243
s.dependency 'Protobuf', '~> 3.1'
4344
end

0 commit comments

Comments
 (0)