From 6cc3ba74e578b1f1c7186a9b241f035ddfb8449b Mon Sep 17 00:00:00 2001 From: luckysmg <2539699336@qq.com> Date: Mon, 27 Mar 2023 18:42:52 +0800 Subject: [PATCH 1/5] Send unfocus message to framework when FlutterTextInputView resign first responder. --- .../platform/darwin/ios/framework/Source/FlutterEngine.mm | 8 +++++++- .../ios/framework/Source/FlutterTextInputDelegate.h | 3 ++- .../darwin/ios/framework/Source/FlutterTextInputPlugin.mm | 3 ++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index ff94acaa2797b..744714dbd5683 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -1095,7 +1095,13 @@ - (void)flutterTextInputView:(FlutterTextInputView*)textInputView arguments:@[ @(client) ]]; } -- (void)flutterTextInputViewDidResignFirstResponder:(FlutterTextInputView*)textInputView { +- (void)flutterTextInputViewDidResignFirstResponder:(FlutterTextInputView*)textInputView + client:(int)client { + // When flutter text input view resign first responder, send a message to + // framework to ensure the focus state is correct. This is useful when close + // keyboard from platform side. + [_textInputChannel.get() invokeMethod:@"TextInputClient.unfocus" arguments:@[ @(client) ]]; + // Platform view's first responder detection logic: // // All text input widgets (e.g. EditableText) are backed by a dummy UITextInput view diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h b/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h index 7ecda6a23bb93..d98a66226db52 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h @@ -59,7 +59,8 @@ typedef NS_ENUM(NSInteger, FlutterFloatingCursorDragState) { insertTextPlaceholderWithSize:(CGSize)size withClient:(int)client; - (void)flutterTextInputView:(FlutterTextInputView*)textInputView removeTextPlaceholder:(int)client; -- (void)flutterTextInputViewDidResignFirstResponder:(FlutterTextInputView*)textInputView; +- (void)flutterTextInputViewDidResignFirstResponder:(FlutterTextInputView*)textInputView + client:(int)client; @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm index 1ac316e819ab4..a5ba53478533a 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm @@ -1043,7 +1043,8 @@ - (BOOL)canBecomeFirstResponder { - (BOOL)resignFirstResponder { BOOL success = [super resignFirstResponder]; if (success) { - [self.textInputDelegate flutterTextInputViewDidResignFirstResponder:self]; + [self.textInputDelegate flutterTextInputViewDidResignFirstResponder:self + client:_textInputClient]; } return success; } From dbec70cf75b8f0341372ef3d67a22796a454462d Mon Sep 17 00:00:00 2001 From: luckysmg <2539699336@qq.com> Date: Tue, 28 Mar 2023 10:54:42 +0800 Subject: [PATCH 2/5] Add Test --- .../ios/framework/Source/FlutterEngineTest.mm | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm index 7bd90a6a5a597..473d9dd1870d2 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm @@ -13,9 +13,15 @@ #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterBinaryMessengerRelay.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Test.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h" FLUTTER_ASSERT_ARC +@interface FlutterEngine () +- (void)flutterTextInputViewDidResignFirstResponder:(FlutterTextInputView*)textInputView + client:(int)client; +@end + @interface FlutterEngineTest : XCTestCase @end @@ -313,4 +319,16 @@ - (void)testCanEnableDisableEmbedderAPIThroughInfoPlist { } } +- (void)testEngineFlutterTextInputViewDidResignFirstResponderWillUnfocusTextInputClient { + id mockBinaryMessenger = OCMClassMock([FlutterBinaryMessengerRelay class]); + FlutterEngine* engine = [[FlutterEngine alloc] init]; + [engine setBinaryMessenger:mockBinaryMessenger]; + [engine runWithEntrypoint:FlutterDefaultDartEntrypoint initialRoute:@"test"]; + [engine flutterTextInputViewDidResignFirstResponder:nil client:1]; + FlutterMethodCall* methodCall = + [FlutterMethodCall methodCallWithMethodName:@"TextInputClient.unfocus" arguments:@[ @(1) ]]; + NSData* encodedMethodCall = [[FlutterJSONMethodCodec sharedInstance] encodeMethodCall:methodCall]; + OCMVerify([mockBinaryMessenger sendOnChannel:@"flutter/textinput" message:encodedMethodCall]); +} + @end From fcf40edeb7b1d062514f440efdbf96d1ca19195f Mon Sep 17 00:00:00 2001 From: luckysmg <2539699336@qq.com> Date: Wed, 29 Mar 2023 11:10:03 +0800 Subject: [PATCH 3/5] Change channel --- shell/platform/darwin/ios/framework/Source/FlutterEngine.mm | 3 ++- .../darwin/ios/framework/Source/FlutterEngineTest.mm | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index 744714dbd5683..04d682f25ac8b 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -1100,7 +1100,8 @@ - (void)flutterTextInputViewDidResignFirstResponder:(FlutterTextInputView*)textI // When flutter text input view resign first responder, send a message to // framework to ensure the focus state is correct. This is useful when close // keyboard from platform side. - [_textInputChannel.get() invokeMethod:@"TextInputClient.unfocus" arguments:@[ @(client) ]]; + [_textInputChannel.get() invokeMethod:@"TextInputClient.onConnectionClosed" + arguments:@[ @(client) ]]; // Platform view's first responder detection logic: // diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm index 473d9dd1870d2..5aeb2d8c0406b 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm @@ -319,14 +319,15 @@ - (void)testCanEnableDisableEmbedderAPIThroughInfoPlist { } } -- (void)testEngineFlutterTextInputViewDidResignFirstResponderWillUnfocusTextInputClient { +- (void)testFlutterTextInputViewDidResignFirstResponderWillCallTextInputClientConnectionClosed { id mockBinaryMessenger = OCMClassMock([FlutterBinaryMessengerRelay class]); FlutterEngine* engine = [[FlutterEngine alloc] init]; [engine setBinaryMessenger:mockBinaryMessenger]; [engine runWithEntrypoint:FlutterDefaultDartEntrypoint initialRoute:@"test"]; [engine flutterTextInputViewDidResignFirstResponder:nil client:1]; FlutterMethodCall* methodCall = - [FlutterMethodCall methodCallWithMethodName:@"TextInputClient.unfocus" arguments:@[ @(1) ]]; + [FlutterMethodCall methodCallWithMethodName:@"TextInputClient.onConnectionClosed" + arguments:@[ @(1) ]]; NSData* encodedMethodCall = [[FlutterJSONMethodCodec sharedInstance] encodeMethodCall:methodCall]; OCMVerify([mockBinaryMessenger sendOnChannel:@"flutter/textinput" message:encodedMethodCall]); } From 0f877f48b9c908379119774a6f168b11959728e9 Mon Sep 17 00:00:00 2001 From: luckysmg <2539699336@qq.com> Date: Wed, 29 Mar 2023 11:46:40 +0800 Subject: [PATCH 4/5] ++ --- .../darwin/ios/framework/Source/FlutterEngineTest.mm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm index 5aeb2d8c0406b..a488a98a4c974 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm @@ -17,9 +17,8 @@ FLUTTER_ASSERT_ARC -@interface FlutterEngine () -- (void)flutterTextInputViewDidResignFirstResponder:(FlutterTextInputView*)textInputView - client:(int)client; +@interface FlutterEngine () + @end @interface FlutterEngineTest : XCTestCase From 1725876b23dc154ae1191e9045cf760d8d2245a3 Mon Sep 17 00:00:00 2001 From: luckysmg <2539699336@qq.com> Date: Wed, 29 Mar 2023 12:34:47 +0800 Subject: [PATCH 5/5] ++ --- shell/platform/darwin/ios/framework/Source/FlutterEngine.mm | 4 ++-- .../darwin/ios/framework/Source/FlutterEngineTest.mm | 2 +- .../darwin/ios/framework/Source/FlutterTextInputDelegate.h | 5 ++--- .../darwin/ios/framework/Source/FlutterTextInputPlugin.mm | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index 04d682f25ac8b..422a6155e40c1 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -1095,8 +1095,8 @@ - (void)flutterTextInputView:(FlutterTextInputView*)textInputView arguments:@[ @(client) ]]; } -- (void)flutterTextInputViewDidResignFirstResponder:(FlutterTextInputView*)textInputView - client:(int)client { +- (void)flutterTextInputView:(FlutterTextInputView*)textInputView + didResignFirstResponderWithTextInputClient:(int)client { // When flutter text input view resign first responder, send a message to // framework to ensure the focus state is correct. This is useful when close // keyboard from platform side. diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm index a488a98a4c974..b4dfb9502f511 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm @@ -323,7 +323,7 @@ - (void)testFlutterTextInputViewDidResignFirstResponderWillCallTextInputClientCo FlutterEngine* engine = [[FlutterEngine alloc] init]; [engine setBinaryMessenger:mockBinaryMessenger]; [engine runWithEntrypoint:FlutterDefaultDartEntrypoint initialRoute:@"test"]; - [engine flutterTextInputViewDidResignFirstResponder:nil client:1]; + [engine flutterTextInputView:nil didResignFirstResponderWithTextInputClient:1]; FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"TextInputClient.onConnectionClosed" arguments:@[ @(1) ]]; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h b/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h index d98a66226db52..cea4dd88daed6 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h @@ -59,9 +59,8 @@ typedef NS_ENUM(NSInteger, FlutterFloatingCursorDragState) { insertTextPlaceholderWithSize:(CGSize)size withClient:(int)client; - (void)flutterTextInputView:(FlutterTextInputView*)textInputView removeTextPlaceholder:(int)client; -- (void)flutterTextInputViewDidResignFirstResponder:(FlutterTextInputView*)textInputView - client:(int)client; - +- (void)flutterTextInputView:(FlutterTextInputView*)textInputView + didResignFirstResponderWithTextInputClient:(int)client; @end #endif // SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERTEXTINPUTDELEGATE_H_ diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm index a5ba53478533a..19aebe126a690 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm @@ -1043,8 +1043,8 @@ - (BOOL)canBecomeFirstResponder { - (BOOL)resignFirstResponder { BOOL success = [super resignFirstResponder]; if (success) { - [self.textInputDelegate flutterTextInputViewDidResignFirstResponder:self - client:_textInputClient]; + [self.textInputDelegate flutterTextInputView:self + didResignFirstResponderWithTextInputClient:_textInputClient]; } return success; }