-
Notifications
You must be signed in to change notification settings - Fork 6k
Build iOS with -fapplication-extension flag #40972
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,7 @@ import("//flutter/shell/platform/darwin/common/framework_shared.gni") | |
| import("//flutter/testing/testing.gni") | ||
|
|
||
| _flutter_framework_dir = "$root_out_dir/Flutter.framework" | ||
| _flutter_xcframework_dir = "$root_out_dir/Flutter.xcframework" | ||
|
|
||
| shell_gpu_configuration("ios_gpu_configuration") { | ||
| enable_software = true | ||
|
|
@@ -44,6 +45,9 @@ source_set("flutter_framework_source_arc") { | |
| cflags_objcc = flutter_cflags_objcc_arc | ||
|
|
||
| defines = [ "FLUTTER_FRAMEWORK=1" ] | ||
| if (darwin_extension_safe) { | ||
| defines += [ "APPLICATION_EXTENSION_API_ONLY=1" ] | ||
| } | ||
| allow_circular_includes_from = [ ":flutter_framework_source" ] | ||
| deps = [ | ||
| ":flutter_framework_source", | ||
|
|
@@ -153,6 +157,9 @@ source_set("flutter_framework_source") { | |
| sources += _flutter_framework_headers | ||
|
|
||
| defines = [ "FLUTTER_FRAMEWORK=1" ] | ||
| if (darwin_extension_safe) { | ||
| defines += [ "APPLICATION_EXTENSION_API_ONLY=1" ] | ||
| } | ||
|
|
||
| if (shell_enable_metal) { | ||
| sources += [ | ||
|
|
@@ -321,6 +328,10 @@ shared_library("create_flutter_framework_dylib") { | |
|
|
||
| ldflags = [ "-Wl,-install_name,@rpath/Flutter.framework/Flutter" ] | ||
|
|
||
| if (darwin_extension_safe) { | ||
| ldflags += [ "-fapplication-extension" ] | ||
| } | ||
|
|
||
| public = _flutter_framework_headers | ||
|
|
||
| deps = [ | ||
|
|
@@ -411,10 +422,24 @@ copy("copy_license") { | |
| shared_library("copy_and_verify_framework_module") { | ||
| framework_search_path = rebase_path("$root_out_dir") | ||
| visibility = [ ":*" ] | ||
| cflags_objc = [ "-F$framework_search_path" ] | ||
| cflags_objc = [ | ||
| "-F$framework_search_path", | ||
| "-fapplication-extension", | ||
| ] | ||
|
|
||
| if (darwin_extension_safe) { | ||
| ldflags = [ | ||
| "-F$framework_search_path", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Surprised this wasn't needed before... maybe |
||
| "-fapplication-extension", | ||
| "-Xlinker", | ||
| "-fatal_warnings", | ||
| ] | ||
| frameworks = [ "Flutter.framework" ] | ||
| deps = [ ":copy_dylib" ] | ||
| } | ||
|
|
||
| sources = [ "framework/Source/FlutterUmbrellaImport.m" ] | ||
| deps = [ | ||
| deps += [ | ||
| ":copy_framework_headers", | ||
| ":copy_framework_info_plist", | ||
| ":copy_framework_module_map", | ||
|
|
@@ -439,7 +464,7 @@ group("universal_flutter_framework") { | |
|
|
||
| action("flutter_framework") { | ||
| script = "//flutter/sky/tools/create_xcframework.py" | ||
| outputs = [ "$root_out_dir/Flutter.xcframework" ] | ||
| outputs = [ "$_flutter_xcframework_dir" ] | ||
| args = [ | ||
| "--frameworks", | ||
| rebase_path("$_flutter_framework_dir"), | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -158,6 +158,7 @@ - (void)setSystemChromeApplicationSwitcherDescription:(NSDictionary*)object { | |
| } | ||
|
|
||
| - (void)setSystemChromeEnabledSystemUIOverlays:(NSArray*)overlays { | ||
| #if !APPLICATION_EXTENSION_API_ONLY | ||
| // Checks if the top status bar should be visible. This platform ignores all | ||
| // other overlays | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't do this in my prototype PR, but ideally we could get rid of as many @property(readonly, nonatomic,getter=isStatusBarHidden) BOOL statusBarHidden API_UNAVAILABLE(tvos) API_DEPRECATED("Use the statusBarManager property of the window scene instead.", ios(2.0, 13.0));Can you instead swap this to using the new API when 13 is From the I'm not sure if it's meaningful to have a status bar in an extension, though. |
||
|
|
@@ -175,9 +176,11 @@ - (void)setSystemChromeEnabledSystemUIOverlays:(NSArray*)overlays { | |
| postNotificationName:FlutterViewControllerHideHomeIndicator | ||
| object:nil]; | ||
| } | ||
| #endif | ||
| } | ||
|
|
||
| - (void)setSystemChromeEnabledSystemUIMode:(NSString*)mode { | ||
| #if !APPLICATION_EXTENSION_API_ONLY | ||
| // Checks if the top status bar should be visible, reflected by edge to edge setting. This | ||
| // platform ignores all other system ui modes. | ||
|
|
||
|
|
@@ -195,6 +198,7 @@ - (void)setSystemChromeEnabledSystemUIMode:(NSString*)mode { | |
| postNotificationName:FlutterViewControllerHideHomeIndicator | ||
| object:nil]; | ||
| } | ||
| #endif | ||
| } | ||
|
|
||
| - (void)restoreSystemChromeSystemUIOverlays { | ||
|
|
@@ -231,9 +235,11 @@ - (void)setSystemChromeSystemUIOverlayStyle:(NSDictionary*)message { | |
| object:nil | ||
| userInfo:@{@(kOverlayStyleUpdateNotificationKey) : @(statusBarStyle)}]; | ||
| } else { | ||
| #if !APPLICATION_EXTENSION_API_ONLY | ||
| // Note: -[UIApplication setStatusBarStyle] is deprecated in iOS9 | ||
| // in favor of delegating to the view controller | ||
| [[UIApplication sharedApplication] setStatusBarStyle:statusBarStyle]; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
- (void)setStatusBarStyle:(UIStatusBarStyle)statusBarStyle animated:(BOOL)animated API_DEPRECATED("Use -[UIViewController preferredStatusBarStyle]", ios(2.0, 9.0)) API_UNAVAILABLE(tvos);
Though I don't really understand the |
||
| #endif | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -249,11 +255,15 @@ - (void)popSystemNavigator:(BOOL)isAnimated { | |
| if (navigationController) { | ||
| [navigationController popViewControllerAnimated:isAnimated]; | ||
| } else { | ||
| #if !APPLICATION_EXTENSION_API_ONLY | ||
| UIViewController* rootViewController = | ||
| [UIApplication sharedApplication].keyWindow.rootViewController; | ||
| if (engineViewController != rootViewController) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if we still need to check something here in the share extension to avoid regressing #30939. |
||
| #endif | ||
| [engineViewController dismissViewControllerAnimated:isAnimated completion:nil]; | ||
| #if !APPLICATION_EXTENSION_API_ONLY | ||
| } | ||
| #endif | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -813,9 +813,14 @@ - (void)viewDidAppear:(BOOL)animated { | |
| if ([_engine.get() viewController] == self) { | ||
| [self onUserSettingsChanged:nil]; | ||
| [self onAccessibilityStatusChanged:nil]; | ||
|
|
||
| #if !APPLICATION_EXTENSION_API_ONLY | ||
| if (UIApplication.sharedApplication.applicationState == UIApplicationStateActive) { | ||
| #endif | ||
| [[_engine.get() lifecycleChannel] sendMessage:@"AppLifecycleState.resumed"]; | ||
| #if !APPLICATION_EXTENSION_API_ONLY | ||
| } | ||
| #endif | ||
| } | ||
| [super viewDidAppear:animated]; | ||
| } | ||
|
|
@@ -1287,8 +1292,13 @@ - (void)viewDidLayoutSubviews { | |
| // There is no guarantee that UIKit will layout subviews when the application is active. Creating | ||
| // the surface when inactive will cause GPU accesses from the background. Only wait for the first | ||
| // frame to render when the application is actually active. | ||
| bool applicationIsActive = | ||
| BOOL applicationIsActive = | ||
|
|
||
| #if APPLICATION_EXTENSION_API_ONLY | ||
| YES; | ||
| #else | ||
| [UIApplication sharedApplication].applicationState == UIApplicationStateActive; | ||
| #endif | ||
|
|
||
| // This must run after updateViewportMetrics so that the surface creation tasks are queued after | ||
| // the viewport metrics update tasks. | ||
|
|
@@ -1808,6 +1818,10 @@ - (void)performOrientationUpdate:(UIInterfaceOrientationMask)new_preferences { | |
| _orientationPreferences = new_preferences; | ||
|
|
||
| if (@available(iOS 16.0, *)) { | ||
| #if APPLICATION_EXTENSION_API_ONLY | ||
| UIWindowScene* windowScene = self.viewIfLoaded.window.windowScene; | ||
| [self performOrientationUpdateOnWindowScene:windowScene]; | ||
|
Comment on lines
+1822
to
+1823
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you could just use this logic instead of anything in the |
||
| #else | ||
| for (UIScene* scene in UIApplication.sharedApplication.connectedScenes) { | ||
| if (![scene isKindOfClass:[UIWindowScene class]]) { | ||
| continue; | ||
|
|
@@ -1825,7 +1839,9 @@ - (void)performOrientationUpdate:(UIInterfaceOrientationMask)new_preferences { | |
| }]; | ||
| [self setNeedsUpdateOfSupportedInterfaceOrientations]; | ||
| } | ||
| #endif | ||
| } else { | ||
| #if !APPLICATION_EXTENSION_API_ONLY | ||
| UIInterfaceOrientationMask currentInterfaceOrientation = | ||
| 1 << [[UIApplication sharedApplication] statusBarOrientation]; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If |
||
| if (!(_orientationPreferences & currentInterfaceOrientation)) { | ||
|
|
@@ -1848,10 +1864,28 @@ - (void)performOrientationUpdate:(UIInterfaceOrientationMask)new_preferences { | |
| forKey:@"orientation"]; | ||
| } | ||
| } | ||
| #endif | ||
| } | ||
| } | ||
| } | ||
|
|
||
| - (void)performOrientationUpdateOnWindowScene:(UIWindowScene*)windowScene API_AVAILABLE(ios(16.0)) { | ||
| if (windowScene == nil) { | ||
| return; | ||
| } | ||
|
|
||
| UIWindowSceneGeometryPreferencesIOS* preference = [[UIWindowSceneGeometryPreferencesIOS alloc] | ||
| initWithInterfaceOrientations:_orientationPreferences]; | ||
| [windowScene | ||
| requestGeometryUpdateWithPreferences:preference | ||
| errorHandler:^(NSError* error) { | ||
| os_log_error(OS_LOG_DEFAULT, | ||
| "Failed to change device orientation: %@", error); | ||
| }]; | ||
| [self setNeedsUpdateOfSupportedInterfaceOrientations]; | ||
| [preference release]; | ||
| } | ||
|
|
||
| - (void)onHideHomeIndicatorNotification:(NSNotification*)notification { | ||
| self.isHomeIndicatorHidden = YES; | ||
| } | ||
|
|
@@ -1951,7 +1985,12 @@ - (void)onUserSettingsChanged:(NSNotification*)notification { | |
| } | ||
|
|
||
| - (CGFloat)textScaleFactor { | ||
| #if APPLICATION_EXTENSION_API_ONLY | ||
| UIContentSizeCategory category = | ||
| self.mainScreenIfViewLoaded.traitCollection.preferredContentSizeCategory; | ||
|
Comment on lines
+1989
to
+1990
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can just use this in all cases since this is all available on iOS 10+, but I didn't test it so I put it in the macro for safety in my PR. |
||
| #else | ||
| UIContentSizeCategory category = [UIApplication sharedApplication].preferredContentSizeCategory; | ||
| #endif | ||
| // The delta is computed by approximating Apple's typography guidelines: | ||
| // https://developer.apple.com/ios/human-interface-guidelines/visual-design/typography/ | ||
| // | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
macOS doesn't fail when building with this flag, but macOS does contain NSApplication code. I'm confused here.
@jmagman @cbracken
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't get this working either, might take more investigation to see how what flags Xcode is passing through when it shows the warning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested the locally built mac engine.
Without with this flag, I got the warning when linking a share extension to the framework.
With this flag, there is no warning.
So it seemed like it is just working (which clearly is not since the mac os code does contain NSApplication.)
Will investigate more.
(I should have marked this PR as draft, it is not intended for reviewing yet before this macOS mystery is resolved)
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked into the headers, on iOS:
@property(class, nonatomic, readonly) UIApplication *sharedApplication NS_EXTENSION_UNAVAILABLE_IOS("Use view controller based solutions where appropriate instead.");The shared application is marked as extension unavailable.
However, on macOS it is not.
@property (class, readonly, strong) __kindof NSApplication *sharedApplication;In the document: https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionOverview.html#//apple_ref/doc/uid/TP40014214-CH2-SW6 only linked to the UIApplication.sharedApplication, didn't mention NSApplication.
I create a sample mac framework having
Require Only App-Extension-safe APIturned on and having NSApplication.SharedApplication. It successfully compiled and a share extension can link to it without warning.So I believe NSApplication.sharedApplication is compatible with extensions? So on mac, as long as the
-fapplication-extensionis in the build flags and there is no compile error, it will work.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!!!
From my reading of the docs when they said
sharedApplicationwithout specifying an object I thought they meant eitherUIApplicationorNSApplication.If we don't need to do anything other than documentation for macOS that would be amazing!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And also you could pull that very simple macOS flag-only work out of this so it would start working in the next stable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By "next stable" I just mean it can be available now-ish without needing to wait for all the iOS work to be correct.