提交 bf2166b6 编写于 作者: M Mikkel Nygaard Ravn 提交者: GitHub

iOS plugin registry (#3645)

上级 b273d1ad
......@@ -23,6 +23,7 @@ shared_library("flutter_framework_dylib") {
"framework/Headers/FlutterCodecs.h",
"framework/Headers/FlutterDartProject.h",
"framework/Headers/FlutterMacros.h",
"framework/Headers/FlutterPlugin.h",
"framework/Headers/FlutterViewController.h",
"framework/Source/FlutterAppDelegate.mm",
"framework/Source/FlutterChannels.mm",
......@@ -163,6 +164,7 @@ copy("framework_headers") {
"framework/Headers/FlutterCodecs.h",
"framework/Headers/FlutterDartProject.h",
"framework/Headers/FlutterMacros.h",
"framework/Headers/FlutterPlugin.h",
"framework/Headers/FlutterViewController.h",
]
outputs = [
......
......@@ -11,6 +11,7 @@
#include "FlutterCodecs.h"
#include "FlutterDartProject.h"
#include "FlutterMacros.h"
#include "FlutterPlugin.h"
#include "FlutterViewController.h"
#endif // FLUTTER_FLUTTER_H_
......@@ -8,6 +8,7 @@
#import <UIKit/UIKit.h>
#include "FlutterMacros.h"
#include "FlutterPlugin.h"
/**
* UIApplicationDelegate subclass for simple apps that want default behavior.
......@@ -23,7 +24,8 @@
* code as necessary from FlutterAppDelegate.mm.
*/
FLUTTER_EXPORT
@interface FlutterAppDelegate : UIResponder<UIApplicationDelegate>
@interface FlutterAppDelegate
: UIResponder<UIApplicationDelegate, FlutterPluginRegistry>
@property(strong, nonatomic) UIWindow* window;
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_FLUTTERPLUGIN_H_
#define FLUTTER_FLUTTERPLUGIN_H_
#include "FlutterBinaryMessenger.h"
#include "FlutterChannels.h"
#include "FlutterCodecs.h"
NS_ASSUME_NONNULL_BEGIN
@protocol FlutterPluginRegistrar;
@protocol FlutterPlugin<NSObject>
@required
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar;
@optional
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result;
- (BOOL)application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions;
- (void)applicationDidBecomeActive:(UIApplication*)application;
- (void)applicationWillResignActive:(UIApplication*)application;
- (void)applicationDidEnterBackground:(UIApplication*)application;
- (void)applicationWillEnterForeground:(UIApplication*)application;
- (void)applicationWillTerminate:(UIApplication*)application;
- (void)application:(UIApplication*)application
didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings;
- (void)application:(UIApplication*)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken;
- (BOOL)application:(UIApplication*)application
didReceiveRemoteNotification:(NSDictionary*)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler;
- (BOOL)application:(UIApplication*)application
openURL:(NSURL*)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id>*)options;
@end
@protocol FlutterPluginRegistrar<NSObject>
- (NSObject<FlutterBinaryMessenger>*)messenger;
- (void)publish:(NSObject*)value;
- (void)addMethodCallDelegate:(NSObject<FlutterPlugin>*)delegate
channel:(FlutterMethodChannel*)channel;
- (void)addApplicationDelegate:(NSObject<FlutterPlugin>*)delegate;
@end
@protocol FlutterPluginRegistry<NSObject>
- (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey;
- (BOOL)hasPlugin:(NSString*)pluginKey;
- (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey;
@end
NS_ASSUME_NONNULL_END;
#endif // FLUTTER_FLUTTERPLUGIN_H_
......@@ -6,10 +6,45 @@
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
#include "lib/ftl/logging.h"
@interface FlutterAppDelegate ()
@property(readonly, nonatomic) NSMutableArray* pluginDelegates;
@property(readonly, nonatomic) NSMutableDictionary* pluginPublications;
@end
@interface FlutterAppDelegateRegistrar : NSObject<FlutterPluginRegistrar>
- (instancetype)initWithPlugin:(NSString*)pluginKey appDelegate:(FlutterAppDelegate*)delegate;
@end
@implementation FlutterAppDelegate {
UIBackgroundTaskIdentifier _debugBackgroundTask;
}
- (instancetype)init {
if (self = [super init]) {
_pluginDelegates = [NSMutableArray new];
_pluginPublications = [NSMutableDictionary new];
}
return self;
}
- (void)dealloc {
[_pluginDelegates release];
[_pluginPublications release];
[super dealloc];
}
- (BOOL)application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
for (id<FlutterPlugin> plugin in _pluginDelegates) {
if ([plugin respondsToSelector:_cmd]) {
if (![plugin application:application didFinishLaunchingWithOptions:launchOptions]) {
return NO;
}
}
}
return YES;
}
// Returns the key window's rootViewController, if it's a FlutterViewController.
// Otherwise, returns nil.
- (FlutterViewController*)rootFlutterViewController {
......@@ -29,25 +64,161 @@
}
}
- (void)applicationDidEnterBackground:(UIApplication*)application {
#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
- (void)applicationDidEnterBackground:(UIApplication *)application {
// The following keeps the Flutter session alive when the device screen locks
// in debug mode. It allows continued use of features like hot reload and
// in debug mode. It allows continued use of features like hot reload and
// taking screenshots once the device unlocks again.
//
// Note the name is not an identifier and multiple instances can exist.
_debugBackgroundTask = [application beginBackgroundTaskWithName:@"Flutter debug task"
expirationHandler:^{
FTL_LOG(WARNING) << "\nThe OS has terminated the Flutter debug connection for being "
"inactive in the background for too long.\n\n"
"There are no errors with your Flutter application.\n\n"
"To reconnect, launch your application again via 'flutter run";
}];
// Note the name is not an identifier and multiple instances can exist.
_debugBackgroundTask = [application
beginBackgroundTaskWithName:@"Flutter debug task"
expirationHandler:^{
FTL_LOG(WARNING)
<< "\nThe OS has terminated the Flutter debug connection for being "
"inactive in the background for too long.\n\n"
"There are no errors with your Flutter application.\n\n"
"To reconnect, launch your application again via 'flutter run";
}];
#endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
for (id<FlutterPlugin> plugin in _pluginDelegates) {
if ([plugin respondsToSelector:_cmd]) {
[plugin applicationDidEnterBackground:application];
}
}
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
[application endBackgroundTask: _debugBackgroundTask];
}
- (void)applicationWillEnterForeground:(UIApplication*)application {
#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
[application endBackgroundTask:_debugBackgroundTask];
#endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
for (id<FlutterPlugin> plugin in _pluginDelegates) {
if ([plugin respondsToSelector:_cmd]) {
[plugin applicationWillEnterForeground:application];
}
}
}
- (void)applicationWillResignActive:(UIApplication*)application {
for (id<FlutterPlugin> plugin in _pluginDelegates) {
if ([plugin respondsToSelector:_cmd]) {
[plugin applicationWillResignActive:application];
}
}
}
- (void)applicationDidBecomeActive:(UIApplication*)application {
for (id<FlutterPlugin> plugin in _pluginDelegates) {
if ([plugin respondsToSelector:_cmd]) {
[plugin applicationDidBecomeActive:application];
}
}
}
- (void)applicationWillTerminate:(UIApplication*)application {
for (id<FlutterPlugin> plugin in _pluginDelegates) {
if ([plugin respondsToSelector:_cmd]) {
[plugin applicationWillTerminate:application];
}
}
}
- (void)application:(UIApplication*)application
didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings {
for (id<FlutterPlugin> plugin in _pluginDelegates) {
if ([plugin respondsToSelector:_cmd]) {
[plugin application:application didRegisterUserNotificationSettings:notificationSettings];
}
}
}
- (void)application:(UIApplication*)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
for (id<FlutterPlugin> plugin in _pluginDelegates) {
if ([plugin respondsToSelector:_cmd]) {
[plugin application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
}
}
- (void)application:(UIApplication*)application
didReceiveRemoteNotification:(NSDictionary*)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
for (id<FlutterPlugin> plugin in _pluginDelegates) {
if ([plugin respondsToSelector:_cmd]) {
if ([plugin application:application
didReceiveRemoteNotification:userInfo
fetchCompletionHandler:completionHandler]) {
return;
}
}
}
}
- (BOOL)application:(UIApplication*)application
openURL:(NSURL*)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id>*)options {
for (id<FlutterPlugin> plugin in _pluginDelegates) {
if ([plugin respondsToSelector:_cmd]) {
if ([plugin application:application openURL:url options:options]) {
return YES;
}
}
}
return NO;
}
- (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey {
NSAssert(self.pluginPublications[pluginKey] == nil, @"Duplicate plugin key: %@", pluginKey);
self.pluginPublications[pluginKey] = [NSNull null];
return
[[[FlutterAppDelegateRegistrar alloc] initWithPlugin:pluginKey appDelegate:self] autorelease];
}
- (BOOL)hasPlugin:(NSString*)pluginKey {
return _pluginPublications[pluginKey] != nil;
}
- (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
return _pluginPublications[pluginKey];
}
@end
@implementation FlutterAppDelegateRegistrar {
NSString* _pluginKey;
FlutterAppDelegate* _appDelegate;
}
- (instancetype)initWithPlugin:(NSString*)pluginKey appDelegate:(FlutterAppDelegate*)appDelegate {
self = [super init];
NSAssert(self, @"Super init cannot be nil");
_pluginKey = [pluginKey retain];
_appDelegate = [appDelegate retain];
return self;
}
- (void)dealloc {
[_pluginKey release];
[_appDelegate release];
[super dealloc];
}
- (NSObject<FlutterBinaryMessenger>*)messenger {
return (FlutterViewController*)_appDelegate.window.rootViewController;
}
- (void)publish:(NSObject*)value {
_appDelegate.pluginPublications[_pluginKey] = value;
}
- (void)addMethodCallDelegate:(NSObject<FlutterPlugin>*)delegate
channel:(FlutterMethodChannel*)channel {
[channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
[delegate handleMethodCall:call result:result];
}];
}
- (void)addApplicationDelegate:(NSObject<FlutterPlugin>*)delegate {
[_appDelegate.pluginDelegates addObject:delegate];
}
@end
......@@ -1437,6 +1437,7 @@ FILE: ../../../flutter/shell/platform/android/platform_view_android_jni.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterBinaryMessenger.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterChannels.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterCodecs.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterChannels.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCodecs.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterStandardCodec.mm
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册