I arrived here after wasting an entire day chasing the same problem. Basically, overriding (in my case, swizzling) an implementation of textInputMode no longer has the expected behavior. iOS will call your implementation but then ignore the return value. Therefore, the keyboard remains with whatever language the user last selected rather than the language you return from textInputMode.
I was debugging with iOS 13.3.1 all day before a gut feeling made me try an older 12.4.5 device, where it works perfectly.
Here's the relevant code (just a hack at this stage):
void swizzle(Class thisClass, Class targetClass) {
SEL originalSelector = @selector(textInputMode);
SEL swizzledSelector = @selector(replacementTextInputMode);
Method originalMethod = class_getInstanceMethod(targetClass, originalSelector);
Method swizzledMethod = class_getInstanceMethod(thisClass, swizzledSelector);
BOOL didAddMethod = class_addMethod(targetClass, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(targetClass, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class thisClass = [self class];
swizzle(thisClass, [UIView class]);
});
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
NSString* langFromLocale(NSString* locale) {
NSRange r = [locale rangeOfString:@"_"];
if (r.length == 0) r.location = locale.length;
NSRange r2 = [locale rangeOfString:@"-"];
if (r2.length == 0) r2.location = locale.length;
return [[locale substringToIndex:MIN(r.location, r2.location)] lowercaseString];
}
UITextInputMode* getTextInputModeForLanguage(NSString* language) {
for (UITextInputMode *tim in [UITextInputMode activeInputModes]) {
NSString* languageLocale = langFromLocale(language);
NSString* primaryLanguageLocale = langFromLocale(tim.primaryLanguage);
if ([languageLocale isEqualToString:primaryLanguageLocale]) {
return tim;
}
}
return nil;
}
- (UITextInputMode*)replacementTextInputMode {
NSLog(@"Swizzled called!");
NSObject* obj = (NSObject*)self;
NSLog(@"DEBUG DESCRIPTION: %@", obj.debugDescription);
UITextInputMode* forcedLanguage = getTextInputModeForLanguage(@"th-TH");
return forcedLanguage;
}
With iOS 13, the keyboard will remain on English (or whatever language the user last selected). With iOS 12, it will switch to (in this case) Thai.