[flutter roll] Revert "ios: remove shared_application and support app extension build" (flutter/engine#45250)

Reverts flutter/engine#44732

context: b/297654739
Synced with Chris and the error message is related to the PR
This commit is contained in:
Xilai Zhang 2023-08-29 16:15:04 -07:00 committed by GitHub
parent 0293da1f4c
commit d4b4f3e830
12 changed files with 53 additions and 169 deletions

View File

@ -9,12 +9,12 @@
NS_ASSUME_NONNULL_BEGIN
// Finds a bundle with the named `flutterFrameworkBundleID` within `searchURL`.
// Finds a bundle with the named `bundleID` within `searchURL`.
//
// Returns `nil` if the bundle cannot be found or if errors are encountered.
NSBundle* FLTFrameworkBundleInternal(NSString* flutterFrameworkBundleID, NSURL* searchURL);
NSBundle* FLTFrameworkBundleInternal(NSString* bundleID, NSURL* searchURL);
// Finds a bundle with the named `flutterFrameworkBundleID`.
// Finds a bundle with the named `bundleID`.
//
// `+[NSBundle bundleWithIdentifier:]` is slow, and can take in the order of
// tens of milliseconds in a minimal flutter app, and closer to 100 milliseconds
@ -28,20 +28,7 @@ NSBundle* FLTFrameworkBundleInternal(NSString* flutterFrameworkBundleID, NSURL*
// frameworks used by this file are placed. If the desired bundle cannot be
// found here, the implementation falls back to
// `+[NSBundle bundleWithIdentifier:]`.
NSBundle* FLTFrameworkBundleWithIdentifier(NSString* flutterFrameworkBundleID);
// Finds the bundle of the application.
//
// Returns [NSBundle mainBundle] if the current running process is the application.
NSBundle* FLTGetApplicationBundle();
// Finds the Flutter asset directory from `bundle`.
//
// The raw path can be set by the application via info.plist's `FLTAssetsPath` key.
// If the key is not set, `flutter_assets` is used as the raw path value.
//
// If no valid asset is found under the raw path, returns nil.
NSURL* FLTAssetsURLFromBundle(NSBundle* bundle);
NSBundle* FLTFrameworkBundleWithIdentifier(NSString* bundleID);
NS_ASSUME_NONNULL_END

View File

@ -8,7 +8,7 @@
FLUTTER_ASSERT_ARC
NSBundle* FLTFrameworkBundleInternal(NSString* flutterFrameworkBundleID, NSURL* searchURL) {
NSBundle* FLTFrameworkBundleInternal(NSString* bundleID, NSURL* searchURL) {
NSDirectoryEnumerator<NSURL*>* frameworkEnumerator = [NSFileManager.defaultManager
enumeratorAtURL:searchURL
includingPropertiesForKeys:nil
@ -18,46 +18,19 @@ NSBundle* FLTFrameworkBundleInternal(NSString* flutterFrameworkBundleID, NSURL*
errorHandler:nil];
for (NSURL* candidate in frameworkEnumerator) {
NSBundle* flutterFrameworkBundle = [NSBundle bundleWithURL:candidate];
if ([flutterFrameworkBundle.bundleIdentifier isEqualToString:flutterFrameworkBundleID]) {
return flutterFrameworkBundle;
NSBundle* bundle = [NSBundle bundleWithURL:candidate];
if ([bundle.bundleIdentifier isEqualToString:bundleID]) {
return bundle;
}
}
return nil;
}
NSBundle* FLTGetApplicationBundle() {
NSBundle* mainBundle = [NSBundle mainBundle];
// App extension bundle is in <AppName>.app/PlugIns/Extension.appex.
if ([mainBundle.bundleURL.pathExtension isEqualToString:@"appex"]) {
// Up two levels.
return [NSBundle bundleWithURL:mainBundle.bundleURL.URLByDeletingLastPathComponent
.URLByDeletingLastPathComponent];
NSBundle* FLTFrameworkBundleWithIdentifier(NSString* bundleID) {
NSBundle* bundle = FLTFrameworkBundleInternal(bundleID, NSBundle.mainBundle.privateFrameworksURL);
if (bundle != nil) {
return bundle;
}
return mainBundle;
}
NSBundle* FLTFrameworkBundleWithIdentifier(NSString* flutterFrameworkBundleID) {
NSBundle* appBundle = FLTGetApplicationBundle();
NSBundle* flutterFrameworkBundle =
FLTFrameworkBundleInternal(flutterFrameworkBundleID, appBundle.privateFrameworksURL);
if (flutterFrameworkBundle == nil) {
// Fallback to slow implementation.
flutterFrameworkBundle = [NSBundle bundleWithIdentifier:flutterFrameworkBundleID];
}
if (flutterFrameworkBundle == nil) {
flutterFrameworkBundle = [NSBundle mainBundle];
}
return flutterFrameworkBundle;
}
NSURL* FLTAssetsURLFromBundle(NSBundle* bundle) {
NSString* assetsPathFromInfoPlist = [bundle objectForInfoDictionaryKey:@"FLTAssetsPath"];
NSString* flutterAssetsPath = assetsPathFromInfoPlist ?: @"flutter_assets";
NSURL* assets = [bundle URLForResource:flutterAssetsPath withExtension:nil];
if ([assets checkResourceIsReachableAndReturnError:NULL]) {
return assets;
}
return nil;
// Fallback to slow implementation.
return [NSBundle bundleWithIdentifier:bundleID];
}

View File

@ -348,10 +348,6 @@ 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 = [
@ -442,10 +438,7 @@ 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",
"-fapplication-extension",
]
cflags_objc = [ "-F$framework_search_path" ]
sources = [ "framework/Source/FlutterUmbrellaImport.m" ]
deps = [
@ -453,17 +446,6 @@ shared_library("copy_and_verify_framework_module") {
":copy_framework_info_plist",
":copy_framework_module_map",
]
if (darwin_extension_safe) {
ldflags = [
"-F$framework_search_path",
"-fapplication-extension",
"-Xlinker",
"-fatal_warnings",
]
deps += [ ":copy_dylib" ]
frameworks = [ "Flutter.framework" ]
}
}
group("universal_flutter_framework") {

View File

@ -353,8 +353,7 @@ typedef enum {
*
* @param delegate The receiving object, such as the plugin's main class.
*/
- (void)addApplicationDelegate:(NSObject<FlutterPlugin>*)delegate
NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in plugins used in app extensions");
- (void)addApplicationDelegate:(NSObject<FlutterPlugin>*)delegate;
/**
* Returns the file name for the given asset.

View File

@ -41,13 +41,16 @@ flutter::Settings FLTDefaultSettingsForBundle(NSBundle* bundle, NSProcessInfo* p
// 3. Settings from the NSBundle with the default bundle ID.
// 4. Settings from the main NSBundle and default values.
NSBundle* mainBundle = FLTGetApplicationBundle();
NSBundle* mainBundle = [NSBundle mainBundle];
NSBundle* engineBundle = [NSBundle bundleForClass:[FlutterViewController class]];
bool hasExplicitBundle = bundle != nil;
if (bundle == nil) {
bundle = FLTFrameworkBundleWithIdentifier([FlutterDartProject defaultBundleIdentifier]);
}
if (bundle == nil) {
bundle = mainBundle;
}
auto settings = flutter::SettingsFromCommandLine(command_line);
@ -119,24 +122,29 @@ flutter::Settings FLTDefaultSettingsForBundle(NSBundle* bundle, NSProcessInfo* p
// Checks to see if the flutter assets directory is already present.
if (settings.assets_path.empty()) {
NSURL* assetsURL = FLTAssetsURLFromBundle(bundle);
NSString* assetsName = [FlutterDartProject flutterAssetsName:bundle];
NSString* assetsPath = [bundle pathForResource:assetsName ofType:@""];
if (!assetsURL) {
NSLog(@"Failed to find assets path for 1\"%@\"", bundle);
if (assetsPath.length == 0) {
assetsPath = [mainBundle pathForResource:assetsName ofType:@""];
}
if (assetsPath.length == 0) {
NSLog(@"Failed to find assets path for \"%@\"", assetsName);
} else {
settings.assets_path = assetsURL.path.UTF8String;
settings.assets_path = assetsPath.UTF8String;
// Check if there is an application kernel snapshot in the assets directory we could
// potentially use. Looking for the snapshot makes sense only if we have a VM that can use
// it.
if (!flutter::DartVM::IsRunningPrecompiledCode()) {
NSURL* applicationKernelSnapshotURL =
[assetsURL URLByAppendingPathComponent:@(kApplicationKernelSnapshotFileName)];
NSError* error;
if ([applicationKernelSnapshotURL checkResourceIsReachableAndReturnError:&error]) {
[NSURL URLWithString:@(kApplicationKernelSnapshotFileName)
relativeToURL:[NSURL fileURLWithPath:assetsPath]];
if ([[NSFileManager defaultManager] fileExistsAtPath:applicationKernelSnapshotURL.path]) {
settings.application_kernel_asset = applicationKernelSnapshotURL.path.UTF8String;
} else {
NSLog(@"Failed to find snapshot at %@: %@", applicationKernelSnapshotURL.path, error);
NSLog(@"Failed to find snapshot: %@", applicationKernelSnapshotURL.path);
}
}
}
@ -331,7 +339,9 @@ flutter::Settings FLTDefaultSettingsForBundle(NSBundle* bundle, NSProcessInfo* p
if (bundle == nil) {
bundle = FLTFrameworkBundleWithIdentifier([FlutterDartProject defaultBundleIdentifier]);
}
if (bundle == nil) {
bundle = [NSBundle mainBundle];
}
NSString* flutterAssetsName = [bundle objectForInfoDictionaryKey:@"FLTAssetsPath"];
if (flutterAssetsName == nil) {
flutterAssetsName = @"Frameworks/App.framework/flutter_assets";

View File

@ -73,20 +73,6 @@ FLUTTER_ASSERT_ARC
XCTAssertNotNil(found);
}
- (void)testFLTGetApplicationBundleWhenCurrentTargetIsNotExtension {
NSBundle* bundle = FLTGetApplicationBundle();
XCTAssertEqual(bundle, [NSBundle mainBundle]);
}
- (void)testFLTGetApplicationBundleWhenCurrentTargetIsExtension {
id mockMainBundle = OCMPartialMock([NSBundle mainBundle]);
NSURL* url = [[NSBundle mainBundle].bundleURL URLByAppendingPathComponent:@"foo/ext.appex"];
OCMStub([mockMainBundle bundleURL]).andReturn(url);
NSBundle* bundle = FLTGetApplicationBundle();
[mockMainBundle stopMocking];
XCTAssertEqualObjects(bundle.bundleURL, [NSBundle mainBundle].bundleURL);
}
- (void)testDisableImpellerSettingIsCorrectlyParsed {
id mockMainBundle = OCMPartialMock([NSBundle mainBundle]);
OCMStub([mockMainBundle objectForInfoDictionaryKey:@"FLTEnableImpeller"]).andReturn(@"NO");

View File

@ -1515,8 +1515,7 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
}];
}
- (void)addApplicationDelegate:(NSObject<FlutterPlugin>*)delegate
NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in plugins used in app extensions") {
- (void)addApplicationDelegate:(NSObject<FlutterPlugin>*)delegate {
id<UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
if ([appDelegate conformsToProtocol:@protocol(FlutterAppLifeCycleProvider)]) {
id<FlutterAppLifeCycleProvider> lifeCycleProvider =

View File

@ -17,10 +17,7 @@ namespace {
constexpr char kTextPlainFormat[] = "text/plain";
const UInt32 kKeyPressClickSoundId = 1306;
#if not APPLICATION_EXTENSION_API_ONLY
const NSString* searchURLPrefix = @"x-web-search://?";
#endif
} // namespace
@ -40,24 +37,6 @@ const char* const kOverlayStyleUpdateNotificationKey =
using namespace flutter;
static void SetStatusBarHiddenForSharedApplication(BOOL hidden) {
#if APPLICATION_EXTENSION_API_ONLY
[UIApplication sharedApplication].statusBarHidden = hidden;
#else
FML_LOG(WARNING) << "Application based status bar styling is not available in app extension.";
#endif
}
static void SetStatusBarStyleForSharedApplication(UIStatusBarStyle style) {
#if APPLICATION_EXTENSION_API_ONLY
// Note: -[UIApplication setStatusBarStyle] is deprecated in iOS9
// in favor of delegating to the view controller.
[[UIApplication sharedApplication] setStatusBarStyle:style];
#else
FML_LOG(WARNING) << "Application based status bar styling is not available in app extension.";
#endif
}
@interface FlutterPlatformPlugin ()
/**
@ -162,9 +141,6 @@ static void SetStatusBarStyleForSharedApplication(UIStatusBarStyle style) {
}
- (void)searchWeb:(NSString*)searchTerm {
#if APPLICATION_EXTENSION_API_ONLY
FML_LOG(WARNING) << "SearchWeb.invoke is not availabe in app extension.";
#else
NSString* escapedText = [searchTerm
stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet
URLHostAllowedCharacterSet]];
@ -173,7 +149,6 @@ static void SetStatusBarStyleForSharedApplication(UIStatusBarStyle style) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:searchURL]
options:@{}
completionHandler:nil];
#endif
}
- (void)playSystemSound:(NSString*)soundType {
@ -256,7 +231,7 @@ static void SetStatusBarStyleForSharedApplication(UIStatusBarStyle style) {
// We opt out of view controller based status bar visibility since we want
// to be able to modify this on the fly. The key used is
// UIViewControllerBasedStatusBarAppearance.
SetStatusBarHiddenForSharedApplication(statusBarShouldBeHidden);
[UIApplication sharedApplication].statusBarHidden = statusBarShouldBeHidden;
}
}
@ -271,7 +246,7 @@ static void SetStatusBarStyleForSharedApplication(UIStatusBarStyle style) {
// We opt out of view controller based status bar visibility since we want
// to be able to modify this on the fly. The key used is
// UIViewControllerBasedStatusBarAppearance.
SetStatusBarHiddenForSharedApplication(!edgeToEdge);
[UIApplication sharedApplication].statusBarHidden = !edgeToEdge;
}
[[NSNotificationCenter defaultCenter]
postNotificationName:edgeToEdge ? FlutterViewControllerShowHomeIndicator
@ -309,7 +284,9 @@ static void SetStatusBarStyleForSharedApplication(UIStatusBarStyle style) {
object:nil
userInfo:@{@(kOverlayStyleUpdateNotificationKey) : @(statusBarStyle)}];
} else {
SetStatusBarStyleForSharedApplication(statusBarStyle);
// Note: -[UIApplication setStatusBarStyle] is deprecated in iOS9
// in favor of delegating to the view controller.
[[UIApplication sharedApplication] setStatusBarStyle:statusBarStyle];
}
}

View File

@ -50,11 +50,9 @@
FlutterResult result = ^(id result) {
OCMVerify([mockPlugin searchWeb:@"Testing Word!"]);
#if not APPLICATION_EXTENSION_API_ONLY
OCMVerify([mockApplication openURL:[NSURL URLWithString:@"x-web-search://?Testing%20Word!"]
options:@{}
completionHandler:nil]);
#endif
[invokeExpectation fulfill];
};
@ -84,11 +82,9 @@
FlutterResult result = ^(id result) {
OCMVerify([mockPlugin searchWeb:@"Test"]);
#if not APPLICATION_EXTENSION_API_ONLY
OCMVerify([mockApplication openURL:[NSURL URLWithString:@"x-web-search://?Test"]
options:@{}
completionHandler:nil]);
#endif
[invokeExpectation fulfill];
};

View File

@ -17,16 +17,11 @@ static const SEL kSelectorsHandledByPlugins[] = {
@selector(application:performFetchWithCompletionHandler:)};
@interface FlutterPluginAppLifeCycleDelegate ()
- (void)handleDidEnterBackground:(NSNotification*)notification
NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions");
- (void)handleWillEnterForeground:(NSNotification*)notification
NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions");
- (void)handleWillResignActive:(NSNotification*)notification
NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions");
- (void)handleDidBecomeActive:(NSNotification*)notification
NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions");
- (void)handleWillTerminate:(NSNotification*)notification
NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions");
- (void)handleDidEnterBackground:(NSNotification*)notification;
- (void)handleWillEnterForeground:(NSNotification*)notification;
- (void)handleWillResignActive:(NSNotification*)notification;
- (void)handleDidBecomeActive:(NSNotification*)notification;
- (void)handleWillTerminate:(NSNotification*)notification;
@end
@implementation FlutterPluginAppLifeCycleDelegate {
@ -51,7 +46,6 @@ static const SEL kSelectorsHandledByPlugins[] = {
_notificationUnsubscribers = [[NSMutableArray alloc] init];
std::string cachePath = fml::paths::JoinPaths({getenv("HOME"), kCallbackCacheSubDir});
[FlutterCallbackCache setCachePath:[NSString stringWithUTF8String:cachePath.c_str()]];
#if not APPLICATION_EXTENSION_API_ONLY
[self addObserverFor:UIApplicationDidEnterBackgroundNotification
selector:@selector(handleDidEnterBackground:)];
[self addObserverFor:UIApplicationWillEnterForegroundNotification
@ -62,7 +56,6 @@ static const SEL kSelectorsHandledByPlugins[] = {
selector:@selector(handleDidBecomeActive:)];
[self addObserverFor:UIApplicationWillTerminateNotification
selector:@selector(handleWillTerminate:)];
#endif
_delegates = [[NSPointerArray weakObjectsPointerArray] retain];
_debugBackgroundTask = UIBackgroundTaskInvalid;
}
@ -141,8 +134,7 @@ static BOOL IsPowerOfTwo(NSUInteger x) {
return YES;
}
- (void)handleDidEnterBackground:(NSNotification*)notification
NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
- (void)handleDidEnterBackground:(NSNotification*)notification {
UIApplication* application = [UIApplication sharedApplication];
#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
// The following keeps the Flutter session alive when the device screen locks
@ -174,8 +166,7 @@ static BOOL IsPowerOfTwo(NSUInteger x) {
}
}
- (void)handleWillEnterForeground:(NSNotification*)notification
NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
- (void)handleWillEnterForeground:(NSNotification*)notification {
UIApplication* application = [UIApplication sharedApplication];
#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
if (_debugBackgroundTask != UIBackgroundTaskInvalid) {
@ -193,8 +184,7 @@ static BOOL IsPowerOfTwo(NSUInteger x) {
}
}
- (void)handleWillResignActive:(NSNotification*)notification
NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
- (void)handleWillResignActive:(NSNotification*)notification {
UIApplication* application = [UIApplication sharedApplication];
for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in _delegates) {
if (!delegate) {
@ -206,8 +196,7 @@ static BOOL IsPowerOfTwo(NSUInteger x) {
}
}
- (void)handleDidBecomeActive:(NSNotification*)notification
NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
- (void)handleDidBecomeActive:(NSNotification*)notification {
UIApplication* application = [UIApplication sharedApplication];
for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in _delegates) {
if (!delegate) {
@ -219,8 +208,7 @@ static BOOL IsPowerOfTwo(NSUInteger x) {
}
}
- (void)handleWillTerminate:(NSNotification*)notification
NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in app extensions") {
- (void)handleWillTerminate:(NSNotification*)notification {
UIApplication* application = [UIApplication sharedApplication];
for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in _delegates) {
if (!delegate) {

View File

@ -20,7 +20,6 @@ FLUTTER_ASSERT_ARC
XCTAssertNotNil(delegate);
}
#if not APPLICATION_EXTENSION_API_ONLY
- (void)testDidEnterBackground {
XCTNSNotificationExpectation* expectation = [[XCTNSNotificationExpectation alloc]
initWithName:UIApplicationDidEnterBackgroundNotification];
@ -89,6 +88,5 @@ FLUTTER_ASSERT_ARC
[self waitForExpectations:@[ expectation ] timeout:5.0];
OCMVerify([plugin applicationWillTerminate:[UIApplication sharedApplication]]);
}
#endif
@end

View File

@ -1973,7 +1973,7 @@ static flutter::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch)
#endif
[self requestGeometryUpdateForWindowScenes:scenes];
} else {
UIInterfaceOrientationMask currentInterfaceOrientation = 0;
UIInterfaceOrientationMask currentInterfaceOrientation;
if (@available(iOS 13.0, *)) {
UIWindowScene* windowScene = [self flutterWindowSceneIfViewLoaded];
if (!windowScene) {
@ -1983,13 +1983,7 @@ static flutter::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch)
}
currentInterfaceOrientation = 1 << windowScene.interfaceOrientation;
} else {
#if APPLICATION_EXTENSION_API_ONLY
FML_LOG(ERROR) << "Application based status bar orentiation update is not supported in "
"app extension. Orientation: "
<< currentInterfaceOrientation;
#else
currentInterfaceOrientation = 1 << [[UIApplication sharedApplication] statusBarOrientation];
#endif
}
if (!(_orientationPreferences & currentInterfaceOrientation)) {
[UIViewController attemptRotationToDeviceOrientation];
@ -2114,10 +2108,6 @@ static flutter::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch)
}
- (CGFloat)textScaleFactor {
#if APPLICATION_EXTENSION_API_ONLY
FML_LOG(WARNING) << "Dynamic content size update is not supported in app extension.";
return 1.0;
#else
UIContentSizeCategory category = [UIApplication sharedApplication].preferredContentSizeCategory;
// The delta is computed by approximating Apple's typography guidelines:
// https://developer.apple.com/ios/human-interface-guidelines/visual-design/typography/
@ -2168,7 +2158,6 @@ static flutter::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch)
} else {
return 1.0;
}
#endif
}
- (BOOL)isAlwaysUse24HourFormat {