Add Search Web to selection controls on iOS (flutter/engine#43324)

In native iOS, users are able to select text and initiate a web search on the selected text. Specifically, this will launch a search using the users selected default search engine. Apple provides a custom url scheme in the form of "x-web-search://?[term]" which will automatically launch a search using the user's preferred browser in Safari. Additionally, this also correctly handles the country code top level domain eg. a user with a selected region in the UK with a preferred Google search engine will automatically have the .co.uk domain appended to the end of the search.

This PR is the engine portion of the changes that will allow Search Web to be implemented
This PR addresses https://github.com/flutter/flutter/issues/82907
More details are available in this [design doc](https://github.com/flutter/engine/pull/flutter.dev/go/add-missing-features-to-selection-controls)
This commit is contained in:
LouiseHsu 2023-08-02 13:43:39 -07:00 committed by GitHub
parent 64028157f8
commit 7ee4615b80
2 changed files with 40 additions and 0 deletions

View File

@ -16,6 +16,7 @@ namespace {
constexpr char kTextPlainFormat[] = "text/plain";
const UInt32 kKeyPressClickSoundId = 1306;
const NSString* searchURLPrefix = @"x-web-search://?";
} // namespace
@ -115,6 +116,9 @@ using namespace flutter;
result([self clipboardHasStrings]);
} else if ([method isEqualToString:@"LiveText.isLiveTextInputAvailable"]) {
result(@([self isLiveTextInputAvailable]));
} else if ([method isEqualToString:@"SearchWeb.invoke"]) {
[self searchWeb:args];
result(nil);
} else if ([method isEqualToString:@"LookUp.invoke"]) {
[self showLookUpViewController:args];
result(nil);
@ -123,6 +127,17 @@ using namespace flutter;
}
}
- (void)searchWeb:(NSString*)searchTerm {
NSString* escapedText = [searchTerm
stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet
URLHostAllowedCharacterSet]];
NSString* searchURL = [NSString stringWithFormat:@"%@%@", searchURLPrefix, escapedText];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:searchURL]
options:@{}
completionHandler:nil];
}
- (void)playSystemSound:(NSString*)soundType {
if ([soundType isEqualToString:@"SystemSoundType.click"]) {
// All feedback types are specific to Android and are treated as equal on

View File

@ -17,6 +17,7 @@
@interface FlutterPlatformPlugin ()
- (BOOL)isLiveTextInputAvailable;
- (void)searchWeb:(NSString*)searchTerm;
- (void)showLookUpViewController:(NSString*)term;
@end
@ -27,6 +28,30 @@
@end
@implementation FlutterPlatformPluginTest
- (void)testSearchWebInvoked {
FlutterEngine* engine = [[[FlutterEngine alloc] initWithName:@"test" project:nil] autorelease];
std::unique_ptr<fml::WeakPtrFactory<FlutterEngine>> _weakFactory =
std::make_unique<fml::WeakPtrFactory<FlutterEngine>>(engine);
[engine runWithEntrypoint:nil];
XCTestExpectation* invokeExpectation =
[self expectationWithDescription:@"Web search launched with search term"];
FlutterPlatformPlugin* plugin =
[[[FlutterPlatformPlugin alloc] initWithEngine:_weakFactory->GetWeakPtr()] autorelease];
FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"SearchWeb.invoke"
arguments:@"Test"];
FlutterResult result = ^(id result) {
OCMVerify([mockPlugin searchWeb:@"Test"]);
[invokeExpectation fulfill];
};
[mockPlugin handleMethodCall:methodCall result:result];
[self waitForExpectationsWithTimeout:1 handler:nil];
}
- (void)testLookUpCallInitiated {
FlutterEngine* engine = [[[FlutterEngine alloc] initWithName:@"test" project:nil] autorelease];