From ea76eb34a6ebd4be4596505ff2de61405ff3b62b Mon Sep 17 00:00:00 2001 From: Louise Hsu Date: Wed, 28 Jun 2023 12:56:30 -0700 Subject: [PATCH 1/6] initial working prototype --- .../ios/framework/Source/FlutterPlatformPlugin.mm | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm index 6d79dcee5179b..2bd775d8eb7c9 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm @@ -115,6 +115,19 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { result([self clipboardHasStrings]); } else if ([method isEqualToString:@"LiveText.isLiveTextInputAvailable"]) { result(@([self isLiveTextInputAvailable])); + }≈ else if ([method isEqualToString:@"SearchWeb.initiate"]) { + NSLog(@"Search web engine"); + // x-web-search://?[query] + //https://google.com/search?q= + NSString *googleURL = @"x-web-search://?"; + NSString *escapedText = [args stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]; + NSString *searchURL = [NSString stringWithFormat:@"%@%@", googleURL, escapedText]; + + + [[UIApplication sharedApplication] openURL:[NSURL URLWithString: searchURL] options:@{} completionHandler:nil]; + + NSLog(@"%@", searchURL); + result(nil); } else { result(FlutterMethodNotImplemented); } From a6a6ae41c4155775de463520c884eb21626d9471 Mon Sep 17 00:00:00 2001 From: Louise Hsu Date: Wed, 28 Jun 2023 16:43:21 -0700 Subject: [PATCH 2/6] small refactor + add test --- .../framework/Source/FlutterPlatformPlugin.mm | 24 +++++++++---------- .../Source/FlutterPlatformPluginTest.mm | 20 ++++++++++++++++ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm index 2bd775d8eb7c9..1f1317a1356be 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm @@ -115,24 +115,22 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { result([self clipboardHasStrings]); } else if ([method isEqualToString:@"LiveText.isLiveTextInputAvailable"]) { result(@([self isLiveTextInputAvailable])); - }≈ else if ([method isEqualToString:@"SearchWeb.initiate"]) { - NSLog(@"Search web engine"); - // x-web-search://?[query] - //https://google.com/search?q= - NSString *googleURL = @"x-web-search://?"; - NSString *escapedText = [args stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]; - NSString *searchURL = [NSString stringWithFormat:@"%@%@", googleURL, escapedText]; - - - [[UIApplication sharedApplication] openURL:[NSURL URLWithString: searchURL] options:@{} completionHandler:nil]; - - NSLog(@"%@", searchURL); - result(nil); + } else if ([method isEqualToString:@"SearchWeb.initiate"]) { + [self handleSearchWebWithSelection:args]; + result(nil); } else { result(FlutterMethodNotImplemented); } } +- (void)handleSearchWebWithSelection:(NSString*)selection { + NSString *searchURLPrefix = @"x-web-search://?"; + NSString *escapedText = [selection 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 diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm index b07261352abaf..2bc4678889c5c 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm @@ -17,9 +17,29 @@ @interface FlutterPlatformPluginTest : XCTestCase @interface FlutterPlatformPlugin () - (BOOL)isLiveTextInputAvailable; +- (void)handleSearchWebWithSelection:(NSString*)selection; @end @implementation FlutterPlatformPluginTest +- (void)testSearchWebInvokedCorrectly { + FlutterEngine* engine = [[[FlutterEngine alloc] initWithName:@"test" project:nil] autorelease]; + std::unique_ptr> _weakFactory = + std::make_unique>(engine); + XCTestExpectation* invokeExpectation = + [self expectationWithDescription:@"isSearchWebInitiated"]; + FlutterPlatformPlugin* plugin = + [[[FlutterPlatformPlugin alloc] initWithEngine:_weakFactory->GetWeakPtr()] autorelease]; + FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin); + FlutterMethodCall* methodCall = + [FlutterMethodCall methodCallWithMethodName:@"SearchWeb.initiate" + arguments:@"Test"]; + FlutterResult result = ^(id result) { + OCMVerify([mockPlugin handleSearchWebWithSelection:@"Test"]); + [invokeExpectation fulfill]; + }; + [mockPlugin handleMethodCall:methodCall result:result]; + [self waitForExpectationsWithTimeout:1 handler:nil]; +} - (void)testClipboardHasCorrectStrings { [UIPasteboard generalPasteboard].string = nil; From 575892ac2ef6f6cc2dff1a0750854c5e450c8c4a Mon Sep 17 00:00:00 2001 From: Louise Hsu Date: Wed, 28 Jun 2023 16:47:09 -0700 Subject: [PATCH 3/6] formatting --- .../ios/framework/Source/FlutterPlatformPlugin.mm | 14 +++++++++----- .../framework/Source/FlutterPlatformPluginTest.mm | 8 +++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm index 1f1317a1356be..f14b51bafced0 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm @@ -124,11 +124,15 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { } - (void)handleSearchWebWithSelection:(NSString*)selection { - NSString *searchURLPrefix = @"x-web-search://?"; - NSString *escapedText = [selection stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]; - NSString *searchURL = [NSString stringWithFormat:@"%@%@", searchURLPrefix, escapedText]; - - [[UIApplication sharedApplication] openURL:[NSURL URLWithString: searchURL] options:@{} completionHandler:nil]; + NSString* searchURLPrefix = @"x-web-search://?"; + NSString* escapedText = [selection + stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet + URLHostAllowedCharacterSet]]; + NSString* searchURL = [NSString stringWithFormat:@"%@%@", searchURLPrefix, escapedText]; + + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:searchURL] + options:@{} + completionHandler:nil]; } - (void)playSystemSound:(NSString*)soundType { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm index 2bc4678889c5c..05406e555d1b1 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm @@ -25,14 +25,12 @@ - (void)testSearchWebInvokedCorrectly { FlutterEngine* engine = [[[FlutterEngine alloc] initWithName:@"test" project:nil] autorelease]; std::unique_ptr> _weakFactory = std::make_unique>(engine); - XCTestExpectation* invokeExpectation = - [self expectationWithDescription:@"isSearchWebInitiated"]; + XCTestExpectation* invokeExpectation = [self expectationWithDescription:@"isSearchWebInitiated"]; FlutterPlatformPlugin* plugin = [[[FlutterPlatformPlugin alloc] initWithEngine:_weakFactory->GetWeakPtr()] autorelease]; FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin); - FlutterMethodCall* methodCall = - [FlutterMethodCall methodCallWithMethodName:@"SearchWeb.initiate" - arguments:@"Test"]; + FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"SearchWeb.initiate" + arguments:@"Test"]; FlutterResult result = ^(id result) { OCMVerify([mockPlugin handleSearchWebWithSelection:@"Test"]); [invokeExpectation fulfill]; From 25976dff66fce8a3479822ad3816d1331b6765c8 Mon Sep 17 00:00:00 2001 From: Louise Hsu Date: Mon, 31 Jul 2023 15:42:35 -0700 Subject: [PATCH 4/6] rewrite test, clean up --- .../framework/Source/FlutterPlatformPlugin.mm | 17 +++++++++++------ .../Source/FlutterPlatformPluginTest.mm | 18 +++++++++++++----- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm index a11ac664c033e..656ddc57ef505 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm @@ -16,6 +16,8 @@ constexpr char kTextPlainFormat[] = "text/plain"; const UInt32 kKeyPressClickSoundId = 1306; +const NSString* searchURLPrefix = @"x-web-search://?"; + } // namespace @@ -115,8 +117,8 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { result([self clipboardHasStrings]); } else if ([method isEqualToString:@"LiveText.isLiveTextInputAvailable"]) { result(@([self isLiveTextInputAvailable])); - } else if ([method isEqualToString:@"SearchWeb.initiate"]) { - [self handleSearchWebWithSelection:args]; + } else if ([method isEqualToString:@"SearchWeb.invoke"]) { + result(@([self searchWeb:args])); } else if ([method isEqualToString:@"LookUp.invoke"]) { [self showLookUpViewController:args]; result(nil); @@ -125,16 +127,19 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { } } -- (void)handleSearchWebWithSelection:(NSString*)selection { - NSString* searchURLPrefix = @"x-web-search://?"; - NSString* escapedText = [selection +- (BOOL)searchWeb:(NSString*)searchTerm { + NSString* escapedText = [searchTerm stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]; NSString* searchURL = [NSString stringWithFormat:@"%@%@", searchURLPrefix, escapedText]; + __block BOOL result; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:searchURL] options:@{} - completionHandler:nil]; + completionHandler:^(BOOL success) { + result = success; + }]; + return result; } - (void)playSystemSound:(NSString*)soundType { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm index 72f444e685419..b29b985a5687c 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm @@ -17,7 +17,7 @@ @interface FlutterPlatformPluginTest : XCTestCase @interface FlutterPlatformPlugin () - (BOOL)isLiveTextInputAvailable; -- (void)handleSearchWebWithSelection:(NSString*)selection; +- (BOOL)searchWeb:(NSString*)searchTerm; - (void)showLookUpViewController:(NSString*)term; @end @@ -28,20 +28,28 @@ - (void)presentViewController:(UIViewController*)viewControllerToPresent @end @implementation FlutterPlatformPluginTest -- (void)testSearchWebInvokedCorrectly { +- (void)testSearchWebInvoked { FlutterEngine* engine = [[[FlutterEngine alloc] initWithName:@"test" project:nil] autorelease]; std::unique_ptr> _weakFactory = std::make_unique>(engine); - XCTestExpectation* invokeExpectation = [self expectationWithDescription:@"isSearchWebInitiated"]; + [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.initiate" + + FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"SearchWeb.invoke" arguments:@"Test"]; + FlutterResult result = ^(id result) { - OCMVerify([mockPlugin handleSearchWebWithSelection:@"Test"]); + OCMVerify([mockPlugin searchWeb:@"Test"]); + XCTAssertTrue(result); [invokeExpectation fulfill]; }; + [mockPlugin handleMethodCall:methodCall result:result]; [self waitForExpectationsWithTimeout:1 handler:nil]; } From 6202c942c179adcf0da4cc852038bd93030551ef Mon Sep 17 00:00:00 2001 From: Louise Hsu Date: Mon, 31 Jul 2023 15:43:37 -0700 Subject: [PATCH 5/6] formatting --- .../darwin/ios/framework/Source/FlutterPlatformPlugin.mm | 1 - 1 file changed, 1 deletion(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm index 656ddc57ef505..cfb0489c1f08a 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm @@ -18,7 +18,6 @@ const UInt32 kKeyPressClickSoundId = 1306; const NSString* searchURLPrefix = @"x-web-search://?"; - } // namespace namespace flutter { From 7ec0371277bc13013d028235d36d8daf437a40a7 Mon Sep 17 00:00:00 2001 From: Louise Hsu Date: Tue, 1 Aug 2023 11:27:37 -0700 Subject: [PATCH 6/6] remove extraneous return value --- .../ios/framework/Source/FlutterPlatformPlugin.mm | 11 ++++------- .../ios/framework/Source/FlutterPlatformPluginTest.mm | 3 +-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm index cfb0489c1f08a..12dbe5eeafd61 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm @@ -117,7 +117,8 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { } else if ([method isEqualToString:@"LiveText.isLiveTextInputAvailable"]) { result(@([self isLiveTextInputAvailable])); } else if ([method isEqualToString:@"SearchWeb.invoke"]) { - result(@([self searchWeb:args])); + [self searchWeb:args]; + result(nil); } else if ([method isEqualToString:@"LookUp.invoke"]) { [self showLookUpViewController:args]; result(nil); @@ -126,19 +127,15 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { } } -- (BOOL)searchWeb:(NSString*)searchTerm { +- (void)searchWeb:(NSString*)searchTerm { NSString* escapedText = [searchTerm stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]; NSString* searchURL = [NSString stringWithFormat:@"%@%@", searchURLPrefix, escapedText]; - __block BOOL result; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:searchURL] options:@{} - completionHandler:^(BOOL success) { - result = success; - }]; - return result; + completionHandler:nil]; } - (void)playSystemSound:(NSString*)soundType { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm index b29b985a5687c..9069f81bcf895 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm @@ -17,7 +17,7 @@ @interface FlutterPlatformPluginTest : XCTestCase @interface FlutterPlatformPlugin () - (BOOL)isLiveTextInputAvailable; -- (BOOL)searchWeb:(NSString*)searchTerm; +- (void)searchWeb:(NSString*)searchTerm; - (void)showLookUpViewController:(NSString*)term; @end @@ -46,7 +46,6 @@ - (void)testSearchWebInvoked { FlutterResult result = ^(id result) { OCMVerify([mockPlugin searchWeb:@"Test"]); - XCTAssertTrue(result); [invokeExpectation fulfill]; };