diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm index 9358431cf5a6f..4ba6ed66a58a6 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm @@ -1290,7 +1290,14 @@ - (NSString*)textInRange:(UITextRange*)range { NSAssert([range isKindOfClass:[FlutterTextRange class]], @"Expected a FlutterTextRange for range (got %@).", [range class]); NSRange textRange = ((FlutterTextRange*)range).range; - NSAssert(textRange.location != NSNotFound, @"Expected a valid text range."); + if (textRange.location == NSNotFound) { + // Avoids [crashes](https://github.com/flutter/flutter/issues/138464) from an assertion + // against NSNotFound. + // TODO(hellohuanlin): This is a temp workaround, but we should look into why + // framework is providing NSNotFound to the engine. + // https://github.com/flutter/flutter/issues/160100 + return nil; + } // Sanitize the range to prevent going out of bounds. NSUInteger location = MIN(textRange.location, self.text.length); NSUInteger length = MIN(self.text.length - location, textRange.length); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm index be00f6e1e63d4..8e93046ccab93 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm @@ -516,6 +516,19 @@ - (void)testTextInRange { XCTAssertEqual(substring.length, 0ul); } +- (void)testTextInRangeAcceptsNSNotFoundLocationGracefully { + NSDictionary* config = self.mutableTemplateCopy; + [self setClientId:123 configuration:config]; + NSArray* inputFields = self.installedInputViews; + FlutterTextInputView* inputView = inputFields[0]; + + [inputView insertText:@"text"]; + UITextRange* range = [FlutterTextRange rangeWithNSRange:NSMakeRange(NSNotFound, 0)]; + + NSString* substring = [inputView textInRange:range]; + XCTAssertNil(substring); +} + - (void)testStandardEditActions { NSDictionary* config = self.mutableTemplateCopy; [self setClientId:123 configuration:config]; diff --git a/shell/platform/darwin/ios/framework/Source/TextInputSemanticsObject.mm b/shell/platform/darwin/ios/framework/Source/TextInputSemanticsObject.mm index f258367ae7f84..0057d05e0effc 100644 --- a/shell/platform/darwin/ios/framework/Source/TextInputSemanticsObject.mm +++ b/shell/platform/darwin/ios/framework/Source/TextInputSemanticsObject.mm @@ -42,7 +42,14 @@ - (NSString*)textInRange:(UITextRange*)range { NSAssert([range isKindOfClass:[FlutterTextRange class]], @"Expected a FlutterTextRange for range (got %@).", [range class]); NSRange textRange = ((FlutterTextRange*)range).range; - NSAssert(textRange.location != NSNotFound, @"Expected a valid text range."); + if (textRange.location == NSNotFound) { + // Avoids [crashes](https://github.com/flutter/flutter/issues/138464) from an assertion + // against NSNotFound. + // TODO(hellohuanlin): This is a temp workaround, but we should look into why + // framework is providing NSNotFound to the engine. + // https://github.com/flutter/flutter/issues/160100 + return nil; + } return [self.text substringWithRange:textRange]; }