未验证 提交 49b6de8c 编写于 作者: C Chris Yang 提交者: GitHub

Dynamically add certain iOS AppDelegate methods. (#8843)

上级 58eff77e
......@@ -677,6 +677,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatfor
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate_internal.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterStandardCodec.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterStandardCodec_Internal.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h
......
......@@ -14,6 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
*/
FLUTTER_EXPORT
@interface FlutterPluginAppLifeCycleDelegate : NSObject
/**
* Registers `delegate` to receive life cycle callbacks via this FlutterPluginAppLifecycleDelegate
* as long as it is alive.
......
......@@ -3,8 +3,14 @@
// found in the LICENSE file.
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h"
#include "flutter/fml/logging.h"
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h"
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate_internal.h"
static NSString* kUIBackgroundMode = @"UIBackgroundModes";
static NSString* kRemoteNotificationCapabitiliy = @"remote-notification";
static NSString* kBackgroundFetchCapatibility = @"fetch";
@implementation FlutterAppDelegate {
FlutterPluginAppLifeCycleDelegate* _lifeCycleDelegate;
......@@ -86,14 +92,6 @@
didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
- (void)application:(UIApplication*)application
didReceiveRemoteNotification:(NSDictionary*)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
[_lifeCycleDelegate application:application
didReceiveRemoteNotification:userInfo
fetchCompletionHandler:completionHandler];
}
- (void)application:(UIApplication*)application
didReceiveLocalNotification:(UILocalNotification*)notification {
[_lifeCycleDelegate application:application didReceiveLocalNotification:notification];
......@@ -147,11 +145,6 @@
completionHandler:completionHandler];
}
- (void)application:(UIApplication*)application
performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
[_lifeCycleDelegate application:application performFetchWithCompletionHandler:completionHandler];
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 120000
- (BOOL)application:(UIApplication*)application
continueUserActivity:(NSUserActivity*)userActivity
......@@ -195,10 +188,60 @@
return nil;
}
#pragma mark - FlutterAppLifeCycleProvider methods
#pragma mark - Selectors handling
- (void)addApplicationLifeCycleDelegate:(NSObject<FlutterPlugin>*)delegate {
[_lifeCycleDelegate addDelegate:delegate];
}
#pragma mark - UIApplicationDelegate method dynamic implementation
- (BOOL)respondsToSelector:(SEL)selector {
if ([_lifeCycleDelegate isSelectorAddedDynamically:selector]) {
return [self delegateRespondsSelectorToPlugins:selector];
}
return [super respondsToSelector:selector];
}
- (BOOL)delegateRespondsSelectorToPlugins:(SEL)selector {
if ([_lifeCycleDelegate hasPluginThatRespondsToSelector:selector]) {
return [_lifeCycleDelegate respondsToSelector:selector];
} else {
return NO;
}
}
- (id)forwardingTargetForSelector:(SEL)aSelector {
if ([_lifeCycleDelegate isSelectorAddedDynamically:aSelector]) {
[self logCapabilityConfigurationWarningIfNeeded:aSelector];
return _lifeCycleDelegate;
}
return [super forwardingTargetForSelector:aSelector];
}
// Mimic the logging from Apple when the capability is not set for the selectors.
// However the difference is that Apple logs these message when the app launches, we only
// log it when the method is invoked. We can possibly also log it when the app launches, but
// it will cause an additional scan over all the plugins.
- (void)logCapabilityConfigurationWarningIfNeeded:(SEL)selector {
NSArray* backgroundModesArray =
[[NSBundle mainBundle] objectForInfoDictionaryKey:kUIBackgroundMode];
NSSet* backgroundModesSet = [[[NSSet alloc] initWithArray:backgroundModesArray] autorelease];
if (selector == @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)) {
if (![backgroundModesSet containsObject:kRemoteNotificationCapabitiliy]) {
NSLog(
@"You've implemented -[<UIApplicationDelegate> "
@"application:didReceiveRemoteNotification:fetchCompletionHandler:], but you still need "
@"to add \"remote-notification\" to the list of your supported UIBackgroundModes in your "
@"Info.plist.");
}
} else if (selector == @selector(application:performFetchWithCompletionHandler:)) {
if (![backgroundModesSet containsObject:kBackgroundFetchCapatibility]) {
NSLog(@"You've implemented -[<UIApplicationDelegate> "
@"application:performFetchWithCompletionHandler:], but you still need to add \"fetch\" "
@"to the list of your supported UIBackgroundModes in your Info.plist.");
}
}
}
@end
......@@ -11,6 +11,10 @@
static const char* kCallbackCacheSubDir = "Library/Caches/";
static const SEL selectorsHandledByPlugins[] = {
@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:),
@selector(application:performFetchWithCompletionHandler:)};
@implementation FlutterPluginAppLifeCycleDelegate {
UIBackgroundTaskIdentifier _debugBackgroundTask;
......@@ -36,6 +40,27 @@ static BOOL isPowerOfTwo(NSUInteger x) {
return x != 0 && (x & (x - 1)) == 0;
}
- (BOOL)isSelectorAddedDynamically:(SEL)selector {
for (const SEL& aSelector : selectorsHandledByPlugins) {
if (selector == aSelector) {
return YES;
}
}
return NO;
}
- (BOOL)hasPluginThatRespondsToSelector:(SEL)selector {
for (id<FlutterPlugin> plugin in [_pluginDelegates allObjects]) {
if (!plugin) {
continue;
}
if ([plugin respondsToSelector:selector]) {
return YES;
}
}
return NO;
}
- (void)addDelegate:(NSObject<FlutterPlugin>*)delegate {
[_pluginDelegates addPointer:(__bridge void*)delegate];
if (isPowerOfTwo([_pluginDelegates count])) {
......
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@interface FlutterPluginAppLifeCycleDelegate ()
/**
* Check whether the selector should be handled dynamically.
*/
- (BOOL)isSelectorAddedDynamically:(SEL)selector;
/**
* Check whether there is at least one plugin responds to the selector.
*/
- (BOOL)hasPluginThatRespondsToSelector:(SEL)selector;
@end
;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册