From da9b932e286798a00ff2e97eafc188f0d06f7768 Mon Sep 17 00:00:00 2001 From: hellohuanlin <41930132+hellohuanlin@users.noreply.github.com> Date: Wed, 2 Aug 2023 11:20:17 -0700 Subject: [PATCH] [ios][autocorrection]disable auto-correction highlight in iOS 17 (flutter/engine#44176) This PR disables the "auto-correction highlight" feature in iOS 17. This feature was introduced in https://github.com/flutter/flutter/pull/45354 and https://github.com/flutter/engine/pull/13959/ (CC: @LongCatIsLooong who was the original author) I have created [a new issue](https://github.com/flutter/flutter/issues/131622) to find other approaches to re-enable this feature. **Note that "auto-correction" itself still works, it's only the "highlight" part is disabled:** - iOS 16 with highlight: https://github.com/flutter/engine/assets/41930132/2fe7bbf6-f2db-4212-a020-e420ad8dd5e6 - iOS 17 without highlight: https://github.com/flutter/engine/assets/41930132/34f34743-6bef-4e93-80d2-d04c92ba59bf ## Why disable this feature? The original PR uses `UITextInput::firstRectForRange` API for auto-correction, since Apple does not provide any other API when auto-correction should show up, so the original PR used this API as a workaround. In iOS 17, Apple changed a few `UITextInput` behaviors: - UIKit does not query `UITextInput::firstRectForRange` for text range of the auto-corrected word any more. - But instead, it repeatedly queries every single character of the current word (after entering or deleting a character), regardless whether the word should be auto-corrected or not. I have tried all other `UITextInput` APIs that takes a text range, and none are suitable for auto-correction feature. As a result, I have to disable this feature for iOS 17 for now. *List which issues are fixed by this PR. You must list at least one issue.* Fixes https://github.com/flutter/flutter/issues/128406 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- .../Source/FlutterTextInputPlugin.mm | 19 +++++++++++---- .../Source/FlutterTextInputPluginTest.mm | 24 ++++++++++++++----- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm index 9c16ec3070..a1ec6bdc85 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm @@ -1632,10 +1632,21 @@ static BOOL IsSelectionRectBoundaryCloserToPoint(CGPoint point, if (_scribbleInteractionStatus == FlutterScribbleInteractionStatusNone && _scribbleFocusStatus == FlutterScribbleFocusStatusUnfocused) { - [self.textInputDelegate flutterTextInputView:self - showAutocorrectionPromptRectForStart:start - end:end - withClient:_textInputClient]; + if (@available(iOS 17.0, *)) { + // Disable auto-correction highlight feature for iOS 17+. + // In iOS 17+, whenever a character is inserted or deleted, the system will always query + // the rect for every single character of the current word. + // GitHub Issue: https://github.com/flutter/flutter/issues/128406 + } else { + // This tells the framework to show the highlight for incorrectly spelled word that is + // about to be auto-corrected. + // There is no other UITextInput API that informs about the auto-correction highlight. + // So we simply add the call here as a workaround. + [self.textInputDelegate flutterTextInputView:self + showAutocorrectionPromptRectForStart:start + end:end + withClient:_textInputClient]; + } } NSUInteger first = start; diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm index 6fae2c6d76..f39168fdeb 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm @@ -313,15 +313,22 @@ FLUTTER_ASSERT_ARC XCTAssertNil(textInputPlugin.activeView.inputViewController); } -- (void)testAutocorrectionPromptRectAppears { +- (void)testAutocorrectionPromptRectAppearsBeforeIOS17AndDoesNotAppearAfterIOS17 { FlutterTextInputView* inputView = [[FlutterTextInputView alloc] initWithOwner:textInputPlugin]; [inputView firstRectForRange:[FlutterTextRange rangeWithNSRange:NSMakeRange(0, 1)]]; - // Verify behavior. - OCMVerify([engine flutterTextInputView:inputView - showAutocorrectionPromptRectForStart:0 - end:1 - withClient:0]); + if (@available(iOS 17.0, *)) { + // Auto-correction prompt is disabled in iOS 17+. + OCMVerify(never(), [engine flutterTextInputView:inputView + showAutocorrectionPromptRectForStart:0 + end:1 + withClient:0]); + } else { + OCMVerify([engine flutterTextInputView:inputView + showAutocorrectionPromptRectForStart:0 + end:1 + withClient:0]); + } } - (void)testIgnoresSelectionChangeIfSelectionIsDisabled { @@ -353,6 +360,11 @@ FLUTTER_ASSERT_ARC } - (void)testAutocorrectionPromptRectDoesNotAppearDuringScribble { + // Auto-correction prompt is disabled in iOS 17+. + if (@available(iOS 17.0, *)) { + return; + } + if (@available(iOS 14.0, *)) { FlutterTextInputView* inputView = [[FlutterTextInputView alloc] initWithOwner:textInputPlugin];