Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

avoid calling [UIApplication sharedApplication] in app extensions #1503

Merged
merged 4 commits into from
Jul 9, 2018
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Firebase/Messaging/FIRMessaging.m
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ - (void)handleIncomingLinkIfNeededFromMessage:(NSDictionary *)message {
});
return;
}
UIApplication *application = [UIApplication sharedApplication];
UIApplication *application = FIRMessagingUIApplication();
id<UIApplicationDelegate> appDelegate = application.delegate;
SEL continueUserActivitySelector =
@selector(application:continueUserActivity:restorationHandler:);
Expand Down Expand Up @@ -611,7 +611,8 @@ - (BOOL)shouldBeConnectedAutomatically {
// We require a token from Instance ID
NSString *token = self.defaultFcmToken;
// Only on foreground connections
UIApplicationState applicationState = [UIApplication sharedApplication].applicationState;
UIApplication *application = FIRMessagingUIApplication();
UIApplicationState applicationState = application.applicationState;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may return UIApplicationStateActive for extensions regardless of the host application state. Is that the correct behavior?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We haven't finalized the official support for extensions so any function is called in extensions is not guarantee to be working. This CL just to ensure compilation works.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If developer wants to establish a MCS connection in app extensions, it should probably work so the application state is for extension app.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually no, the application object would be nil, so there's no way to check the application state in extensions. Basically we should return no for this case.

I'm also adding nil check for all the cases here.

BOOL shouldBeConnected = _shouldEstablishDirectChannel &&
(token.length > 0) &&
applicationState == UIApplicationStateActive;
Expand Down
4 changes: 3 additions & 1 deletion Firebase/Messaging/FIRMessagingContextManagerService.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#import "FIRMessagingDefines.h"
#import "FIRMessagingLogger.h"
#import "FIRMessagingUtilities.h"

#define kFIRMessagingContextManagerPrefixKey @"google.c.cm."
#define kFIRMessagingContextManagerNotificationKeyPrefix @"gcm.notification."
Expand Down Expand Up @@ -174,7 +175,8 @@ + (void)scheduleLocalNotificationForMessage:(NSDictionary *)message
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
UIApplication *application = FIRMessagingUIApplication();
[application scheduleLocalNotification:notification];
#pragma clang diagnostic pop
}

Expand Down
16 changes: 9 additions & 7 deletions Firebase/Messaging/FIRMessagingReceiver.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
#import <UIKit/UIKit.h>

#import "FIRMessaging.h"
#import "FIRMessaging_Private.h"
#import "FIRMessagingLogger.h"
#import "FIRMessagingUtilities.h"
#import "FIRMessaging_Private.h"

static NSString *const kUpstreamMessageIDUserInfoKey = @"messageID";
static NSString *const kUpstreamErrorUserInfoKey = @"error";
Expand Down Expand Up @@ -111,19 +112,20 @@ - (void)scheduleNotificationForMessage:(NSDictionary *)message {
SEL oldNotificationSelector = @selector(application:didReceiveRemoteNotification:);

dispatch_async(dispatch_get_main_queue(), ^{
id<UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
UIApplication *application = FIRMessagingUIApplication();
id<UIApplicationDelegate> appDelegate = [application delegate];
if ([appDelegate respondsToSelector:newNotificationSelector]) {
// Try the new remote notification callback
[appDelegate application:[UIApplication sharedApplication]
didReceiveRemoteNotification:message
fetchCompletionHandler:^(UIBackgroundFetchResult result) {}];
[appDelegate application:application
didReceiveRemoteNotification:message
fetchCompletionHandler:^(UIBackgroundFetchResult result) {
}];

} else if ([appDelegate respondsToSelector:oldNotificationSelector]) {
// Try the old remote notification callback
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[appDelegate application:
[UIApplication sharedApplication] didReceiveRemoteNotification:message];
[appDelegate application:application didReceiveRemoteNotification:message];
#pragma clang diagnostic pop
} else {
FIRMessagingLoggerError(kFIRMessagingMessageCodeReceiver005,
Expand Down
4 changes: 3 additions & 1 deletion Firebase/Messaging/FIRMessagingRemoteNotificationsProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#import "FIRMessagingConstants.h"
#import "FIRMessagingLogger.h"
#import "FIRMessagingUtilities.h"
#import "FIRMessaging_Private.h"

static const BOOL kDefaultAutoRegisterEnabledValue = YES;
Expand Down Expand Up @@ -98,7 +99,8 @@ - (void)swizzleMethodsIfPossible {
return;
}

NSObject<UIApplicationDelegate> *appDelegate = [[UIApplication sharedApplication] delegate];
UIApplication *application = FIRMessagingUIApplication();
NSObject<UIApplicationDelegate> *appDelegate = [application delegate];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be a nil-check here before swizzling?

[self swizzleAppDelegateMethods:appDelegate];

// Add KVO listener on [UNUserNotificationCenter currentNotificationCenter]'s delegate property
Expand Down
6 changes: 5 additions & 1 deletion Firebase/Messaging/FIRMessagingUtilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

typedef NS_ENUM(int8_t, FIRMessagingProtoTag) {
kFIRMessagingProtoTagInvalid = -1,
Expand Down Expand Up @@ -51,4 +51,8 @@ FOUNDATION_EXPORT int64_t FIRMessagingCurrentTimestampInMilliseconds(void);
FOUNDATION_EXPORT NSString *FIRMessagingCurrentAppVersion(void);
FOUNDATION_EXPORT NSString *FIRMessagingAppIdentifier(void);

#pragma mark - Others

FOUNDATION_EXPORT uint64_t FIRMessagingGetFreeDiskSpaceInMB(void);
FOUNDATION_EXPORT UIApplication *FIRMessagingUIApplication(void);

15 changes: 15 additions & 0 deletions Firebase/Messaging/FIRMessagingUtilities.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#import "FIRMessagingLogger.h"

#import <GoogleUtilities/GULAppEnvironmentUtil.h>

// Convert the macro to a string
#define STR_EXPAND(x) #x
#define STR(x) STR_EXPAND(x)
Expand Down Expand Up @@ -171,3 +173,16 @@ uint64_t FIRMessagingGetFreeDiskSpaceInMB(void) {
return 0;
}
}

UIApplication *FIRMessagingUIApplication(void) {
static Class applicationClass = nil;
// iOS App extensions should not call [UIApplication sharedApplication], even if UIApplication
// responds to it.
if (![GULAppEnvironmentUtil isAppExtension]) {
Class cls = NSClassFromString(@"UIApplication");
if (cls && [cls respondsToSelector:NSSelectorFromString(@"sharedApplication")]) {
applicationClass = cls;
}
}
return [applicationClass sharedApplication];
}