diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm index 038a40d378c63..b8f9cfd803006 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm @@ -55,6 +55,14 @@ #pragma mark - Static Functions +// "TextInputType.none" is a made-up input type that's typically +// used when there's an in-app virtual keyboard. If +// "TextInputType.none" is specified, disable the system +// keyboard. +static BOOL shouldShowSystemKeyboard(NSDictionary* type) { + NSString* inputType = type[@"name"]; + return ![inputType isEqualToString:@"TextInputType.none"]; +} static UIKeyboardType ToUIKeyboardType(NSDictionary* type) { NSString* inputType = type[@"name"]; if ([inputType isEqualToString:@"TextInputType.address"]) @@ -516,7 +524,12 @@ @implementation FlutterTextInputView { int _textInputClient; const char* _selectionAffinity; FlutterTextRange* _selectedTextRange; + UIInputViewController* _inputViewController; CGRect _cachedFirstRect; + // Whether to show the system keyboard when this view + // becomes the first responder. Typically set to false + // when the app shows its own in-flutter keyboard. + bool _isSystemKeyboardEnabled; bool _isFloatingCursorActive; // The view has reached end of life, and is no longer // allowed to access its textInputDelegate. @@ -579,6 +592,8 @@ - (void)configureWithDictionary:(NSDictionary*)configuration { NSDictionary* autofill = configuration[kAutofillProperties]; self.secureTextEntry = [configuration[kSecureTextEntry] boolValue]; + + _isSystemKeyboardEnabled = shouldShowSystemKeyboard(inputType); self.keyboardType = ToUIKeyboardType(inputType); self.returnKeyType = ToUIReturnKeyType(configuration[kInputAction]); self.autocapitalizationType = ToUITextAutoCapitalizationType(configuration); @@ -625,6 +640,17 @@ - (UITextContentType)textContentType { return _textContentType; } +- (UIInputViewController*)inputViewController { + if (_isSystemKeyboardEnabled) { + return nil; + } + + if (!_inputViewController) { + _inputViewController = [UIInputViewController new]; + } + return _inputViewController; +} + - (id)textInputDelegate { return _decommissioned ? nil : _textInputDelegate; } @@ -649,6 +675,7 @@ - (void)dealloc { [_selectedTextRange release]; [_tokenizer release]; [_autofillId release]; + [_inputViewController release]; [super dealloc]; } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.m b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.m index d52359ecb387f..def757b915926 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.m +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.m @@ -194,6 +194,20 @@ - (void)testKeyboardType { XCTAssertEqual(inputView.keyboardType, UIKeyboardTypeURL); } +- (void)testSettingKeyboardTypeNoneDisablesSystemKeyboard { + NSDictionary* config = self.mutableTemplateCopy; + [config setValue:@{@"name" : @"TextInputType.none"} forKey:@"inputType"]; + [self setClientId:123 configuration:config]; + + // Verify the view's inputViewController is not nil; + XCTAssertNotNil(textInputPlugin.activeView.inputViewController); + + [config setValue:@{@"name" : @"TextInputType.url"} forKey:@"inputType"]; + [self setClientId:124 configuration:config]; + XCTAssertNotNil(textInputPlugin.activeView); + XCTAssertNil(textInputPlugin.activeView.inputViewController); +} + - (void)testAutocorrectionPromptRectAppears { FlutterTextInputView* inputView = [[FlutterTextInputView alloc] initWithFrame:CGRectZero]; inputView.textInputDelegate = engine;