FlutterAppDelegate.mm 10.5 KB
Newer Older
C
Chinmay Garde 已提交
1 2 3 4
// Copyright 2015 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.

5
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h"
6
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
7 8 9 10 11 12 13 14 15 16
#include "lib/fxl/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
17

18
@implementation FlutterAppDelegate {
19
  UIBackgroundTaskIdentifier _debugBackgroundTask;
20
}
C
Chinmay Garde 已提交
21

22 23
- (instancetype)init {
  if (self = [super init]) {
24 25
    _pluginDelegates = [NSMutableArray new];
    _pluginPublications = [NSMutableDictionary new];
26 27 28 29 30
  }
  return self;
}

- (void)dealloc {
31 32
  [_pluginDelegates release];
  [_pluginPublications release];
33 34 35 36 37
  [super dealloc];
}

- (BOOL)application:(UIApplication*)application
    didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
38 39 40 41 42 43 44 45
  for (id<FlutterPlugin> plugin in _pluginDelegates) {
    if ([plugin respondsToSelector:_cmd]) {
      if (![plugin application:application didFinishLaunchingWithOptions:launchOptions]) {
        return NO;
      }
    }
  }
  return YES;
46 47
}

48 49 50
// Returns the key window's rootViewController, if it's a FlutterViewController.
// Otherwise, returns nil.
- (FlutterViewController*)rootFlutterViewController {
51
  UIViewController* viewController = [UIApplication sharedApplication].keyWindow.rootViewController;
52 53 54 55 56 57
  if ([viewController isKindOfClass:[FlutterViewController class]]) {
    return (FlutterViewController*)viewController;
  }
  return nil;
}

58
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
59 60 61 62 63 64 65 66
  [super touchesBegan:touches withEvent:event];

  // Pass status bar taps to key window Flutter rootViewController.
  if (self.rootFlutterViewController != nil) {
    [self.rootFlutterViewController handleStatusBarTouches:event];
  }
}

67
- (void)applicationDidEnterBackground:(UIApplication*)application {
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
  // 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
  // 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:^{
                  FXL_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];
    }
  }
89 90
}

91
- (void)applicationWillEnterForeground:(UIApplication*)application {
92 93 94 95 96 97 98 99
#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];
    }
  }
100 101 102
}

- (void)applicationWillResignActive:(UIApplication*)application {
103 104 105 106 107
  for (id<FlutterPlugin> plugin in _pluginDelegates) {
    if ([plugin respondsToSelector:_cmd]) {
      [plugin applicationWillResignActive:application];
    }
  }
108 109 110
}

- (void)applicationDidBecomeActive:(UIApplication*)application {
111 112 113 114 115
  for (id<FlutterPlugin> plugin in _pluginDelegates) {
    if ([plugin respondsToSelector:_cmd]) {
      [plugin applicationDidBecomeActive:application];
    }
  }
116 117 118
}

- (void)applicationWillTerminate:(UIApplication*)application {
119 120 121 122 123
  for (id<FlutterPlugin> plugin in _pluginDelegates) {
    if ([plugin respondsToSelector:_cmd]) {
      [plugin applicationWillTerminate:application];
    }
  }
124 125 126 127
}

- (void)application:(UIApplication*)application
    didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings {
128 129 130 131 132
  for (id<FlutterPlugin> plugin in _pluginDelegates) {
    if ([plugin respondsToSelector:_cmd]) {
      [plugin application:application didRegisterUserNotificationSettings:notificationSettings];
    }
  }
133
}
134

135 136
- (void)application:(UIApplication*)application
    didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
137 138 139 140 141
  for (id<FlutterPlugin> plugin in _pluginDelegates) {
    if ([plugin respondsToSelector:_cmd]) {
      [plugin application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
    }
  }
142 143 144 145 146
}

- (void)application:(UIApplication*)application
    didReceiveRemoteNotification:(NSDictionary*)userInfo
          fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
147 148 149 150 151 152 153 154 155
  for (id<FlutterPlugin> plugin in _pluginDelegates) {
    if ([plugin respondsToSelector:_cmd]) {
      if ([plugin application:application
              didReceiveRemoteNotification:userInfo
                    fetchCompletionHandler:completionHandler]) {
        return;
      }
    }
  }
156 157
}

158 159 160
- (BOOL)application:(UIApplication*)application
            openURL:(NSURL*)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey, id>*)options {
161 162 163 164 165 166 167 168
  for (id<FlutterPlugin> plugin in _pluginDelegates) {
    if ([plugin respondsToSelector:_cmd]) {
      if ([plugin application:application openURL:url options:options]) {
        return YES;
      }
    }
  }
  return NO;
169 170
}

171
- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url {
172 173 174 175 176 177 178 179
  for (id<FlutterPlugin> plugin in _pluginDelegates) {
    if ([plugin respondsToSelector:_cmd]) {
      if ([plugin application:application handleOpenURL:url]) {
        return YES;
      }
    }
  }
  return NO;
180 181
}

182
- (BOOL)application:(UIApplication*)application
183 184 185
              openURL:(NSURL*)url
    sourceApplication:(NSString*)sourceApplication
           annotation:(id)annotation {
186 187 188 189 190 191 192 193 194 195 196
  for (id<FlutterPlugin> plugin in _pluginDelegates) {
    if ([plugin respondsToSelector:_cmd]) {
      if ([plugin application:application
                        openURL:url
              sourceApplication:sourceApplication
                     annotation:annotation]) {
        return YES;
      }
    }
  }
  return NO;
197 198
}

199 200
- (void)application:(UIApplication*)application
    performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
201
               completionHandler:(void (^)(BOOL succeeded))completionHandler NS_AVAILABLE_IOS(9_0) {
202 203 204 205 206 207 208 209 210
  for (id<FlutterPlugin> plugin in _pluginDelegates) {
    if ([plugin respondsToSelector:_cmd]) {
      if ([plugin application:application
              performActionForShortcutItem:shortcutItem
                         completionHandler:completionHandler]) {
        return;
      }
    }
  }
211 212
}

213 214 215
- (void)application:(UIApplication*)application
    handleEventsForBackgroundURLSession:(nonnull NSString*)identifier
                      completionHandler:(nonnull void (^)())completionHandler {
216 217 218 219 220 221 222 223 224
  for (id<FlutterPlugin> plugin in _pluginDelegates) {
    if ([plugin respondsToSelector:_cmd]) {
      if ([plugin application:application
              handleEventsForBackgroundURLSession:identifier
                                completionHandler:completionHandler]) {
        return;
      }
    }
  }
225 226 227 228
}

- (void)application:(UIApplication*)application
    performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
229 230 231 232 233 234 235
  for (id<FlutterPlugin> plugin in _pluginDelegates) {
    if ([plugin respondsToSelector:_cmd]) {
      if ([plugin application:application performFetchWithCompletionHandler:completionHandler]) {
        return;
      }
    }
  }
236 237
}

238 239
// TODO(xster): move when doing https://github.com/flutter/flutter/issues/3671.
- (NSObject<FlutterBinaryMessenger>*)binaryMessenger {
240
  UIViewController* rootViewController = _window.rootViewController;
241 242
  if ([rootViewController conformsToProtocol:@protocol(FlutterBinaryMessenger)]) {
    return (NSObject<FlutterBinaryMessenger>*)rootViewController;
243 244
  }
  return nil;
245 246
}

247
- (NSObject<FlutterTextureRegistry>*)textures {
248
  UIViewController* rootViewController = _window.rootViewController;
249 250
  if ([rootViewController conformsToProtocol:@protocol(FlutterTextureRegistry)]) {
    return (NSObject<FlutterTextureRegistry>*)rootViewController;
251 252 253 254
  }
  return nil;
}

255 256 257 258 259 260 261 262 263 264 265
- (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;
}

266
- (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
  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 [_appDelegate binaryMessenger];
292
}
293

294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
- (NSObject<FlutterTextureRegistry>*)textures {
  return [_appDelegate textures];
}

- (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];
}

- (NSString*)lookupKeyForAsset:(NSString*)asset {
  return [FlutterDartProject lookupKeyForAsset:asset];
}
316

317 318
- (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
  return [FlutterDartProject lookupKeyForAsset:asset fromPackage:package];
319 320
}

C
Chinmay Garde 已提交
321
@end