Skip to content

Commit 47ff756

Browse files
sfshaza2johnpryan
andauthored
Add a note on working around a potential crash on iOS (#13244)
Fixes #13243 --------- Co-authored-by: John Ryan <ryjohn@google.com>
1 parent b9d3325 commit 47ff756

2 files changed

Lines changed: 41 additions & 35 deletions

File tree

src/content/platform-integration/ios/platform-views.md

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -169,21 +169,18 @@ modify the App's `AppDelegate.swift`:
169169
import Flutter
170170
import UIKit
171171

172-
@UIApplicationMain
173-
@objc class AppDelegate: FlutterAppDelegate {
174-
override func application(
175-
_ application: UIApplication,
176-
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?
177-
) -> Bool {
178-
GeneratedPluginRegistrant.register(with: self)
172+
@main
173+
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
174+
175+
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
176+
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
179177

180-
guard let pluginRegistrar = self.registrar(forPlugin: "plugin-name") else { return false }
178+
guard let pluginRegistrar = engineBridge.pluginRegistry.registrar(forPlugin: "plugin-name") else { return }
181179

182180
let factory = FLNativeViewFactory(messenger: pluginRegistrar.messenger())
183181
pluginRegistrar.register(
184182
factory,
185183
withId: "<platform-view-type>")
186-
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
187184
}
188185
}
189186
```
@@ -298,19 +295,16 @@ modify the App's `AppDelegate.m`:
298295

299296
@implementation AppDelegate
300297

301-
- (BOOL)application:(UIApplication *)application
302-
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
303-
[GeneratedPluginRegistrant registerWithRegistry:self];
298+
- (void)didInitializeImplicitFlutterEngine:(NSObject<FlutterImplicitEngineBridge>*)engineBridge {
299+
[GeneratedPluginRegistrant registerWithRegistry:engineBridge.pluginRegistry];
304300

305-
NSObject<FlutterPluginRegistrar>* registrar =
306-
[self registrarForPlugin:@"plugin-name"];
301+
NSObject<FlutterPluginRegistrar>* registrar =
302+
[engineBridge.pluginRegistry registrarForPlugin:@"plugin-name"];
307303

308304
FLNativeViewFactory* factory =
309305
[[FLNativeViewFactory alloc] initWithMessenger:registrar.messenger];
310306

311-
[[self registrarForPlugin:@"<plugin-name>"] registerViewFactory:factory
312-
withId:@"<platform-view-type>"];
313-
return [super application:application didFinishLaunchingWithOptions:launchOptions];
307+
[registrar registerViewFactory:factory withId:@"<platform-view-type>"];
314308
}
315309

316310
@end

src/content/platform-integration/platform-channels.md

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -612,24 +612,30 @@ Override the `application:didFinishLaunchingWithOptions:` function and create
612612
a `FlutterMethodChannel` tied to the channel name
613613
`samples.flutter.dev/battery`:
614614

615+
:::note
616+
If your app adopts the `UISceneDelegate` lifecycle (default in Flutter 3.41+),
617+
`window` will be `nil` during `application(_:didFinishLaunchingWithOptions:)`.
618+
To avoid a crash, use the `FlutterImplicitEngineDelegate` protocol and
619+
create your `FlutterMethodChannel` in the `didInitializeImplicitFlutterEngine` method.
620+
:::
621+
615622
```swift title="AppDelegate.swift"
616623
@main
617-
@objc class AppDelegate: FlutterAppDelegate {
618-
override func application(
619-
_ application: UIApplication,
620-
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
621-
622-
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
623-
let batteryChannel = FlutterMethodChannel(name: "samples.flutter.dev/battery",
624-
binaryMessenger: controller.binaryMessenger)
624+
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
625+
626+
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
627+
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
628+
629+
let batteryChannel = FlutterMethodChannel(
630+
name: "samples.flutter.dev/battery",
631+
binaryMessenger: engineBridge.applicationRegistrar.messenger()
632+
)
633+
625634
batteryChannel.setMethodCallHandler({
626635
[weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
627636
// This method is invoked on the UI thread.
628637
// Handle battery messages.
629638
})
630-
631-
GeneratedPluginRegistrant.register(with: self)
632-
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
633639
}
634640
}
635641
```
@@ -695,26 +701,32 @@ didFinishLaunchingWithOptions:` method.
695701
Make sure to use the same channel name
696702
as was used on the Flutter client side.
697703

704+
:::note
705+
If your app adopts the `UISceneDelegate` lifecycle (default in Flutter 3.41+),
706+
`window` will be `nil` during `application:didFinishLaunchingWithOptions:`.
707+
To avoid a crash, use the `FlutterImplicitEngineDelegate` protocol and
708+
create your `FlutterMethodChannel` in the `didInitializeImplicitFlutterEngine` method.
709+
:::
710+
698711
```objc title="AppDelegate.m"
699712
#import <Flutter/Flutter.h>
700713
#import "GeneratedPluginRegistrant.h"
701714

702715
@implementation AppDelegate
703-
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
704-
FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
716+
717+
- (void)didInitializeImplicitFlutterEngine:(NSObject<FlutterImplicitEngineBridge>*)engineBridge {
718+
[GeneratedPluginRegistrant registerWithRegistry:engineBridge.pluginRegistry];
705719

706720
FlutterMethodChannel* batteryChannel = [FlutterMethodChannel
707-
methodChannelWithName:@"samples.flutter.dev/battery"
708-
binaryMessenger:controller.binaryMessenger];
721+
methodChannelWithName:@"samples.flutter.dev/battery"
722+
binaryMessenger:engineBridge.applicationRegistrar.messenger];
709723

710724
[batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
711725
// This method is invoked on the UI thread.
712726
// TODO
713727
}];
714-
715-
[GeneratedPluginRegistrant registerWithRegistry:self];
716-
return [super application:application didFinishLaunchingWithOptions:launchOptions];
717728
}
729+
@end
718730
```
719731
720732
Next, add the iOS ObjectiveC code that uses the iOS battery APIs to

0 commit comments

Comments
 (0)