From 70232f479e1c0edfdbda8b5ddb18ab39ae440596 Mon Sep 17 00:00:00 2001 From: Tony Homer Date: Tue, 26 Apr 2016 17:03:22 -0400 Subject: [PATCH 01/10] initial implementation with swizzle tracking --- src/ios/IonicKeyboard.h | 4 +- src/ios/IonicKeyboard.m | 94 +++++++++++++++++++++--------- src/ios/UIWebViewExtension.h | 4 -- src/ios/UIWebViewExtension.m | 109 ----------------------------------- www/ios/keyboard.js | 3 +- 5 files changed, 70 insertions(+), 144 deletions(-) delete mode 100644 src/ios/UIWebViewExtension.h delete mode 100644 src/ios/UIWebViewExtension.m diff --git a/src/ios/IonicKeyboard.h b/src/ios/IonicKeyboard.h index 773a46b..16206d4 100644 --- a/src/ios/IonicKeyboard.h +++ b/src/ios/IonicKeyboard.h @@ -3,9 +3,11 @@ @interface IonicKeyboard : CDVPlugin { @protected id _keyboardShowObserver, _keyboardHideObserver; + NSMapTable* _swizzledViewToOriginalClass; + NSMutableDictionary* _swizzledClassNameToClass; } -// @property (readwrite, assign) BOOL hideKeyboardAccessoryBar; +@property (readwrite, assign) BOOL hideKeyboardAccessoryBar; @property (readwrite, assign) BOOL disableScroll; //@property (readwrite, assign) BOOL styleDark; diff --git a/src/ios/IonicKeyboard.m b/src/ios/IonicKeyboard.m index cd3048d..2d855fe 100644 --- a/src/ios/IonicKeyboard.m +++ b/src/ios/IonicKeyboard.m @@ -1,10 +1,11 @@ #import "IonicKeyboard.h" // #import "UIWebViewExtension.h" #import +#import @implementation IonicKeyboard -// @synthesize hideKeyboardAccessoryBar = _hideKeyboardAccessoryBar; +@synthesize hideKeyboardAccessoryBar = _hideKeyboardAccessoryBar; @synthesize disableScroll = _disableScroll; //@synthesize styleDark = _styleDark; @@ -14,7 +15,9 @@ - (void)pluginInitialize { __weak IonicKeyboard* weakSelf = self; //set defaults - // self.hideKeyboardAccessoryBar = YES; + _swizzledViewToOriginalClass = [[NSMapTable alloc] init]; + _swizzledClassNameToClass = [[NSMutableDictionary alloc] init]; + self.hideKeyboardAccessoryBar = YES; self.disableScroll = NO; //self.styleDark = NO; @@ -42,6 +45,7 @@ - (void)pluginInitialize { [weakSelf.commandDelegate evalJs:@"cordova.fireWindowEvent('native.hidekeyboard'); "]; }]; } + - (BOOL)disableScroll { return _disableScroll; } @@ -62,24 +66,58 @@ - (void)setDisableScroll:(BOOL)disableScroll { _disableScroll = disableScroll; } +-(id)nil_inputAccessoryView { + return nil; +} + +- (void)unswizzleInputAccessoryView { + UIView* view; + while (view = [_swizzledViewToOriginalClass.keyEnumerator nextObject]) { + object_setClass(view, [_swizzledViewToOriginalClass objectForKey:view]); + } + [_swizzledViewToOriginalClass removeAllObjects]; +} + +- (Class)getSwizzledSubclassOfView:(Class)viewClass { + NSString* swizzledClassName = [NSString stringWithFormat:@"swizzled_%@", NSStringFromClass(viewClass)]; + Class newClass = [_swizzledClassNameToClass objectForKey:swizzledClassName]; + if(newClass == nil) { + newClass = objc_allocateClassPair(viewClass, [swizzledClassName UTF8String], 0); + [_swizzledClassNameToClass setObject:newClass forKey:swizzledClassName]; + IMP nilImp = [self methodForSelector:@selector(nil_inputAccessoryView)]; + class_addMethod(newClass, @selector(inputAccessoryView), nilImp, "@@:"); + objc_registerClassPair(newClass); + } + return newClass; +} + +- (void)swizzleInputAccessoryView { + for (UIView* view in self.webView.scrollView.subviews) { + if(![_swizzledViewToOriginalClass.keyEnumerator.allObjects containsObject:view]) { + [_swizzledViewToOriginalClass setObject:view.class forKey:[NSValue valueWithNonretainedObject:view]]; + Class swizzledClass = [self getSwizzledSubclassOfView:view.class]; + object_setClass(view, swizzledClass); + } + } +} + +- (BOOL)hideKeyboardAccessoryBar { + return _hideKeyboardAccessoryBar; +} -// - (BOOL)hideKeyboardAccessoryBar { -// return _hideKeyboardAccessoryBar; -// } -// -// - (void)setHideKeyboardAccessoryBar:(BOOL)hideKeyboardAccessoryBar { -// if (hideKeyboardAccessoryBar == _hideKeyboardAccessoryBar || ![self.webView isKindOfClass:[UIWebView class]]) { -// return; -// } -// if (hideKeyboardAccessoryBar) { -// ((UIWebView*)self.webView).hackishlyHidesInputAccessoryView = YES; -// } -// else { -// ((UIWebView*)self.webView).hackishlyHidesInputAccessoryView = NO; -// } -// -// _hideKeyboardAccessoryBar = hideKeyboardAccessoryBar; -// } +- (void)setHideKeyboardAccessoryBar:(BOOL)hideKeyboardAccessoryBar { + if (hideKeyboardAccessoryBar == _hideKeyboardAccessoryBar || ![self.webView isKindOfClass:[UIWebView class]]) { + return; + } + if (hideKeyboardAccessoryBar) { + [self swizzleInputAccessoryView]; + } + else { + [self unswizzleInputAccessoryView]; + } + + _hideKeyboardAccessoryBar = hideKeyboardAccessoryBar; +} /* - (BOOL)styleDark { @@ -129,15 +167,15 @@ - (void) disableScroll:(CDVInvokedUrlCommand*)command { } } -// - (void) hideKeyboardAccessoryBar:(CDVInvokedUrlCommand*)command { -// if (!command.arguments || ![command.arguments count]){ -// return; -// } -// id value = [command.arguments objectAtIndex:0]; -// if (value != [NSNull null]) { -// self.hideKeyboardAccessoryBar = [value boolValue]; -// } -// } +- (void) hideKeyboardAccessoryBar:(CDVInvokedUrlCommand*)command { + if (!command.arguments || ![command.arguments count]){ + return; + } + id value = [command.arguments objectAtIndex:0]; + if (value != [NSNull null]) { + self.hideKeyboardAccessoryBar = [value boolValue]; + } +} - (void) close:(CDVInvokedUrlCommand*)command { [self.webView endEditing:YES]; diff --git a/src/ios/UIWebViewExtension.h b/src/ios/UIWebViewExtension.h deleted file mode 100644 index 67555f5..0000000 --- a/src/ios/UIWebViewExtension.h +++ /dev/null @@ -1,4 +0,0 @@ -// @interface UIWebView (HackishAccessoryHiding) -// @property (nonatomic, assign) BOOL hackishlyHidesInputAccessoryView; -// //@property (nonatomic, assign) BOOL styleDark; -// @end diff --git a/src/ios/UIWebViewExtension.m b/src/ios/UIWebViewExtension.m deleted file mode 100644 index 75fde6c..0000000 --- a/src/ios/UIWebViewExtension.m +++ /dev/null @@ -1,109 +0,0 @@ -// #import -// #import -// #import "UIWebViewExtension.h" -// -// //Credit: https://gist.github.com/bjhomer/2048571 -// //Also: http://stackoverflow.com/a/23398487/1091751 -// @implementation UIWebView (HackishAccessoryHiding) -// -// static const char * const hackishFixClassName = "UIWebBrowserViewMinusAccessoryView"; -// static Class hackishFixClass = Nil; -// -// - (UIView *)hackishlyFoundBrowserView { -// UIScrollView *scrollView = self.scrollView; -// -// UIView *browserView = nil; -// for (UIView *subview in scrollView.subviews) { -// if ([NSStringFromClass([subview class]) hasPrefix:@"UIWebBrowserView"]) { -// browserView = subview; -// break; -// } -// } -// return browserView; -// } -// -// - (id)methodReturningNil { -// return nil; -// } -// -// - (void)ensureHackishSubclassExistsOfBrowserViewClass:(Class)browserViewClass { -// if (!hackishFixClass) { -// Class newClass = objc_allocateClassPair(browserViewClass, hackishFixClassName, 0); -// IMP nilImp = [self methodForSelector:@selector(methodReturningNil)]; -// class_addMethod(newClass, @selector(inputAccessoryView), nilImp, "@@:"); -// objc_registerClassPair(newClass); -// -// hackishFixClass = newClass; -// } -// } -// -// - (BOOL) hackishlyHidesInputAccessoryView { -// UIView *browserView = [self hackishlyFoundBrowserView]; -// return [browserView class] == hackishFixClass; -// } -// -// - (void) setHackishlyHidesInputAccessoryView:(BOOL)value { -// UIView *browserView = [self hackishlyFoundBrowserView]; -// if (browserView == nil) { -// return; -// } -// [self ensureHackishSubclassExistsOfBrowserViewClass:[browserView class]]; -// -// if (value) { -// object_setClass(browserView, hackishFixClass); -// } -// else { -// Class normalClass = objc_getClass("UIWebBrowserView"); -// object_setClass(browserView, normalClass); -// } -// [browserView reloadInputViews]; -// } -// /* ---------------------------------------------------------------- */ -// -// /* -// - (UIKeyboardAppearance) darkKeyboardAppearanceTemplateMethod { -// return UIKeyboardAppearanceDark; -// } -// -// - (UIKeyboardAppearance) lightKeyboardAppearanceTemplateMethod { -// return UIKeyboardAppearanceLight; -// } -// -// - (BOOL) styleDark { -// UIView *browserView = [self hackishlyFoundBrowserView]; -// if (browserView == nil) { -// return false; -// } -// -// Method m = class_getInstanceMethod( [self class], @selector( darkKeyboardAppearanceTemplateMethod ) ); -// IMP imp = method_getImplementation( m ); -// -// Method m2 = class_getInstanceMethod( [browserView class], @selector(keyboardAppearance) ); -// IMP imp2 = method_getImplementation( m2 ); -// -// return imp == imp2; -// } -// -// - (void) setStyleDark:(BOOL)styleDark { -// UIView *browserView = [self hackishlyFoundBrowserView]; -// if (browserView == nil) { -// return; -// } -// -// if ( styleDark ) { -// Method m = class_getInstanceMethod( [self class], @selector( darkKeyboardAppearanceTemplateMethod ) ); -// IMP imp = method_getImplementation( m ); -// const char* typeEncoding = method_getTypeEncoding( m ); -// class_replaceMethod( [browserView class], @selector(keyboardAppearance), imp, typeEncoding ); -// } -// else { -// Method m = class_getInstanceMethod( [self class], @selector( lightKeyboardAppearanceTemplateMethod ) ); -// IMP imp = method_getImplementation( m ); -// const char* typeEncoding = method_getTypeEncoding( m ); -// class_replaceMethod( [browserView class], @selector(keyboardAppearance), imp, typeEncoding ); -// } -// } -// */ -// -// @end -// diff --git a/www/ios/keyboard.js b/www/ios/keyboard.js index 156db6a..888a18a 100644 --- a/www/ios/keyboard.js +++ b/www/ios/keyboard.js @@ -8,8 +8,7 @@ var Keyboard = function() { }; Keyboard.hideKeyboardAccessoryBar = function(hide) { - // exec(null, null, "Keyboard", "hideKeyboardAccessoryBar", [hide]); - console.warn('hideKeyboardAccessoryBar has been removed until a method is found that doesn\'t get rejected from the App Store.') + exec(null, null, "Keyboard", "hideKeyboardAccessoryBar", [hide]); }; Keyboard.close = function() { From 55293c86a7f49c20a21fb9d119d810a50c82e1b0 Mon Sep 17 00:00:00 2001 From: Tony Homer Date: Tue, 26 Apr 2016 17:24:01 -0400 Subject: [PATCH 02/10] remove swizzle tracking, add class prefix checking --- src/ios/IonicKeyboard.h | 1 - src/ios/IonicKeyboard.m | 21 +++++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/ios/IonicKeyboard.h b/src/ios/IonicKeyboard.h index 16206d4..8d7470a 100644 --- a/src/ios/IonicKeyboard.h +++ b/src/ios/IonicKeyboard.h @@ -3,7 +3,6 @@ @interface IonicKeyboard : CDVPlugin { @protected id _keyboardShowObserver, _keyboardHideObserver; - NSMapTable* _swizzledViewToOriginalClass; NSMutableDictionary* _swizzledClassNameToClass; } diff --git a/src/ios/IonicKeyboard.m b/src/ios/IonicKeyboard.m index 2d855fe..47da66f 100644 --- a/src/ios/IonicKeyboard.m +++ b/src/ios/IonicKeyboard.m @@ -3,6 +3,8 @@ #import #import +NSString* const swizzled = @"swizzled_"; + @implementation IonicKeyboard @synthesize hideKeyboardAccessoryBar = _hideKeyboardAccessoryBar; @@ -15,7 +17,6 @@ - (void)pluginInitialize { __weak IonicKeyboard* weakSelf = self; //set defaults - _swizzledViewToOriginalClass = [[NSMapTable alloc] init]; _swizzledClassNameToClass = [[NSMutableDictionary alloc] init]; self.hideKeyboardAccessoryBar = YES; self.disableScroll = NO; @@ -71,15 +72,19 @@ -(id)nil_inputAccessoryView { } - (void)unswizzleInputAccessoryView { - UIView* view; - while (view = [_swizzledViewToOriginalClass.keyEnumerator nextObject]) { - object_setClass(view, [_swizzledViewToOriginalClass objectForKey:view]); + for (UIView* view in self.webView.scrollView.subviews) { + NSString* originalString = NSStringFromClass(view.class); + NSString *newString = [originalString copy]; + if ([originalString hasPrefix:swizzled]) { + newString = [originalString substringFromIndex:[swizzled length]]; + Class originalClass = NSClassFromString(newString); + object_setClass(view, originalClass); + } } - [_swizzledViewToOriginalClass removeAllObjects]; } - (Class)getSwizzledSubclassOfView:(Class)viewClass { - NSString* swizzledClassName = [NSString stringWithFormat:@"swizzled_%@", NSStringFromClass(viewClass)]; + NSString* swizzledClassName = [NSString stringWithFormat:@"%@%@", swizzled, NSStringFromClass(viewClass)]; Class newClass = [_swizzledClassNameToClass objectForKey:swizzledClassName]; if(newClass == nil) { newClass = objc_allocateClassPair(viewClass, [swizzledClassName UTF8String], 0); @@ -93,8 +98,8 @@ - (Class)getSwizzledSubclassOfView:(Class)viewClass { - (void)swizzleInputAccessoryView { for (UIView* view in self.webView.scrollView.subviews) { - if(![_swizzledViewToOriginalClass.keyEnumerator.allObjects containsObject:view]) { - [_swizzledViewToOriginalClass setObject:view.class forKey:[NSValue valueWithNonretainedObject:view]]; + //only swizzle unswizzled instances whose class starts with UIWeb + if(![NSStringFromClass(view.class) hasPrefix:swizzled] && [NSStringFromClass(view.class) hasPrefix:@"UIWeb"]) { Class swizzledClass = [self getSwizzledSubclassOfView:view.class]; object_setClass(view, swizzledClass); } From b583d0a104253d992829776a8edf46badeb44418 Mon Sep 17 00:00:00 2001 From: Tony Homer Date: Tue, 26 Apr 2016 17:31:17 -0400 Subject: [PATCH 03/10] reduce unnecessary string allocation in unswizzle --- src/ios/IonicKeyboard.m | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ios/IonicKeyboard.m b/src/ios/IonicKeyboard.m index 47da66f..5aa43fb 100644 --- a/src/ios/IonicKeyboard.m +++ b/src/ios/IonicKeyboard.m @@ -73,11 +73,10 @@ -(id)nil_inputAccessoryView { - (void)unswizzleInputAccessoryView { for (UIView* view in self.webView.scrollView.subviews) { - NSString* originalString = NSStringFromClass(view.class); - NSString *newString = [originalString copy]; - if ([originalString hasPrefix:swizzled]) { - newString = [originalString substringFromIndex:[swizzled length]]; - Class originalClass = NSClassFromString(newString); + NSString* currentClassName = NSStringFromClass(view.class); + if ([currentClassName hasPrefix:swizzled]) { + NSString *originalClassName = [currentClassName substringFromIndex:[swizzled length]]; + Class originalClass = NSClassFromString(originalClassName); object_setClass(view, originalClass); } } From bee3317a5f4de4d9970e44d9fbe9b1dbda1548ca Mon Sep 17 00:00:00 2001 From: Tony Homer Date: Tue, 26 Apr 2016 17:34:38 -0400 Subject: [PATCH 04/10] revert README.md to reenable cordova.plugins.Keyboard.hideKeyboardAccessoryBar --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6a4a654..61441ed 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The `cordova.plugins.Keyboard` object provides functions to make interacting wit Methods ------- -- ~~cordova.plugins.Keyboard.hideKeyboardAccessoryBar~~ (**removed in 2.0, see below**) +- cordova.plugins.Keyboard.hideKeyboardAccessoryBar - cordova.plugins.Keyboard.close - cordova.plugins.Keyboard.disableScroll - cordova.plugins.Keyboard.show @@ -30,11 +30,9 @@ These events are fired on the window. # API reference -~~Keyboard.hideKeyboardAccessoryBar~~ +Keyboard.hideKeyboardAccessoryBar ================= -**NOTE: This method started causing apps to be rejected from the App Store, so has been removed until a workaround is found.** - Hide the keyboard accessory bar with the next, previous and done buttons. cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); From 2081ad4cbba473540a73c02c3f9293f846cadc1b Mon Sep 17 00:00:00 2001 From: Tony Homer Date: Tue, 26 Apr 2016 17:53:07 -0400 Subject: [PATCH 05/10] added attributions for swizzling approach --- src/ios/IonicKeyboard.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ios/IonicKeyboard.m b/src/ios/IonicKeyboard.m index 5aa43fb..5755cef 100644 --- a/src/ios/IonicKeyboard.m +++ b/src/ios/IonicKeyboard.m @@ -82,6 +82,11 @@ - (void)unswizzleInputAccessoryView { } } +//keyboard swizzling inspired by: +//https://gist.github.com/bjhomer/2048571 +//http://stackoverflow.com/a/23398487/1091751 +//http://stackoverflow.com/a/19042279/273628 + - (Class)getSwizzledSubclassOfView:(Class)viewClass { NSString* swizzledClassName = [NSString stringWithFormat:@"%@%@", swizzled, NSStringFromClass(viewClass)]; Class newClass = [_swizzledClassNameToClass objectForKey:swizzledClassName]; From d12af2ecc6a5d211b0ce1b92e0ee4d5e85f5d65c Mon Sep 17 00:00:00 2001 From: Tony Homer Date: Tue, 26 Apr 2016 22:16:58 -0400 Subject: [PATCH 06/10] fixed indenting (tabs->spaces) --- src/ios/IonicKeyboard.m | 92 ++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/src/ios/IonicKeyboard.m b/src/ios/IonicKeyboard.m index 5755cef..80c0ed3 100644 --- a/src/ios/IonicKeyboard.m +++ b/src/ios/IonicKeyboard.m @@ -17,7 +17,7 @@ - (void)pluginInitialize { __weak IonicKeyboard* weakSelf = self; //set defaults - _swizzledClassNameToClass = [[NSMutableDictionary alloc] init]; + _swizzledClassNameToClass = [[NSMutableDictionary alloc] init]; self.hideKeyboardAccessoryBar = YES; self.disableScroll = NO; //self.styleDark = NO; @@ -68,18 +68,18 @@ - (void)setDisableScroll:(BOOL)disableScroll { } -(id)nil_inputAccessoryView { - return nil; + return nil; } - (void)unswizzleInputAccessoryView { - for (UIView* view in self.webView.scrollView.subviews) { - NSString* currentClassName = NSStringFromClass(view.class); - if ([currentClassName hasPrefix:swizzled]) { - NSString *originalClassName = [currentClassName substringFromIndex:[swizzled length]]; - Class originalClass = NSClassFromString(originalClassName); - object_setClass(view, originalClass); - } - } + for (UIView* view in self.webView.scrollView.subviews) { + NSString* currentClassName = NSStringFromClass(view.class); + if ([currentClassName hasPrefix:swizzled]) { + NSString *originalClassName = [currentClassName substringFromIndex:[swizzled length]]; + Class originalClass = NSClassFromString(originalClassName); + object_setClass(view, originalClass); + } + } } //keyboard swizzling inspired by: @@ -88,44 +88,44 @@ - (void)unswizzleInputAccessoryView { //http://stackoverflow.com/a/19042279/273628 - (Class)getSwizzledSubclassOfView:(Class)viewClass { - NSString* swizzledClassName = [NSString stringWithFormat:@"%@%@", swizzled, NSStringFromClass(viewClass)]; - Class newClass = [_swizzledClassNameToClass objectForKey:swizzledClassName]; - if(newClass == nil) { - newClass = objc_allocateClassPair(viewClass, [swizzledClassName UTF8String], 0); - [_swizzledClassNameToClass setObject:newClass forKey:swizzledClassName]; - IMP nilImp = [self methodForSelector:@selector(nil_inputAccessoryView)]; - class_addMethod(newClass, @selector(inputAccessoryView), nilImp, "@@:"); - objc_registerClassPair(newClass); - } - return newClass; + NSString* swizzledClassName = [NSString stringWithFormat:@"%@%@", swizzled, NSStringFromClass(viewClass)]; + Class newClass = [_swizzledClassNameToClass objectForKey:swizzledClassName]; + if(newClass == nil) { + newClass = objc_allocateClassPair(viewClass, [swizzledClassName UTF8String], 0); + [_swizzledClassNameToClass setObject:newClass forKey:swizzledClassName]; + IMP nilImp = [self methodForSelector:@selector(nil_inputAccessoryView)]; + class_addMethod(newClass, @selector(inputAccessoryView), nilImp, "@@:"); + objc_registerClassPair(newClass); + } + return newClass; } - (void)swizzleInputAccessoryView { - for (UIView* view in self.webView.scrollView.subviews) { - //only swizzle unswizzled instances whose class starts with UIWeb - if(![NSStringFromClass(view.class) hasPrefix:swizzled] && [NSStringFromClass(view.class) hasPrefix:@"UIWeb"]) { - Class swizzledClass = [self getSwizzledSubclassOfView:view.class]; - object_setClass(view, swizzledClass); - } - } + for (UIView* view in self.webView.scrollView.subviews) { + //only swizzle unswizzled instances whose class starts with UIWeb + if(![NSStringFromClass(view.class) hasPrefix:swizzled] && [NSStringFromClass(view.class) hasPrefix:@"UIWeb"]) { + Class swizzledClass = [self getSwizzledSubclassOfView:view.class]; + object_setClass(view, swizzledClass); + } + } } - (BOOL)hideKeyboardAccessoryBar { - return _hideKeyboardAccessoryBar; + return _hideKeyboardAccessoryBar; } - (void)setHideKeyboardAccessoryBar:(BOOL)hideKeyboardAccessoryBar { - if (hideKeyboardAccessoryBar == _hideKeyboardAccessoryBar || ![self.webView isKindOfClass:[UIWebView class]]) { - return; - } - if (hideKeyboardAccessoryBar) { - [self swizzleInputAccessoryView]; - } - else { - [self unswizzleInputAccessoryView]; - } - - _hideKeyboardAccessoryBar = hideKeyboardAccessoryBar; + if (hideKeyboardAccessoryBar == _hideKeyboardAccessoryBar || ![self.webView isKindOfClass:[UIWebView class]]) { + return; + } + if (hideKeyboardAccessoryBar) { + [self swizzleInputAccessoryView]; + } + else { + [self unswizzleInputAccessoryView]; + } + + _hideKeyboardAccessoryBar = hideKeyboardAccessoryBar; } /* @@ -177,13 +177,13 @@ - (void) disableScroll:(CDVInvokedUrlCommand*)command { } - (void) hideKeyboardAccessoryBar:(CDVInvokedUrlCommand*)command { - if (!command.arguments || ![command.arguments count]){ - return; - } - id value = [command.arguments objectAtIndex:0]; - if (value != [NSNull null]) { - self.hideKeyboardAccessoryBar = [value boolValue]; - } + if (!command.arguments || ![command.arguments count]){ + return; + } + id value = [command.arguments objectAtIndex:0]; + if (value != [NSNull null]) { + self.hideKeyboardAccessoryBar = [value boolValue]; + } } - (void) close:(CDVInvokedUrlCommand*)command { From c0241574d2530317b04b7315cd1b821efdecceba Mon Sep 17 00:00:00 2001 From: Tony Homer Date: Tue, 26 Apr 2016 22:18:50 -0400 Subject: [PATCH 07/10] fixed indenting (tabs->spaces) --- src/ios/IonicKeyboard.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ios/IonicKeyboard.h b/src/ios/IonicKeyboard.h index 8d7470a..cf7125f 100644 --- a/src/ios/IonicKeyboard.h +++ b/src/ios/IonicKeyboard.h @@ -3,7 +3,7 @@ @interface IonicKeyboard : CDVPlugin { @protected id _keyboardShowObserver, _keyboardHideObserver; - NSMutableDictionary* _swizzledClassNameToClass; + NSMutableDictionary* _swizzledClassNameToClass; } @property (readwrite, assign) BOOL hideKeyboardAccessoryBar; From 1b712264f2371a4ba41332c47ca1f6faea1c97f7 Mon Sep 17 00:00:00 2001 From: Tony Homer Date: Wed, 4 May 2016 15:47:41 -0400 Subject: [PATCH 08/10] change approach from class swizzling to method swizzling --- src/ios/IonicKeyboard.h | 4 ++- src/ios/IonicKeyboard.m | 70 ++++++++++++----------------------------- 2 files changed, 23 insertions(+), 51 deletions(-) diff --git a/src/ios/IonicKeyboard.h b/src/ios/IonicKeyboard.h index cf7125f..aa6e2e5 100644 --- a/src/ios/IonicKeyboard.h +++ b/src/ios/IonicKeyboard.h @@ -1,9 +1,11 @@ #import +#import @interface IonicKeyboard : CDVPlugin { @protected id _keyboardShowObserver, _keyboardHideObserver; - NSMutableDictionary* _swizzledClassNameToClass; + IMP wkOriginalImp, uiOriginalImp; + Method wkMethod, uiMethod; } @property (readwrite, assign) BOOL hideKeyboardAccessoryBar; diff --git a/src/ios/IonicKeyboard.m b/src/ios/IonicKeyboard.m index 80c0ed3..1b663c4 100644 --- a/src/ios/IonicKeyboard.m +++ b/src/ios/IonicKeyboard.m @@ -1,7 +1,6 @@ #import "IonicKeyboard.h" // #import "UIWebViewExtension.h" #import -#import NSString* const swizzled = @"swizzled_"; @@ -13,15 +12,20 @@ @implementation IonicKeyboard - (void)pluginInitialize { - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; - __weak IonicKeyboard* weakSelf = self; - + Class wkClass = NSClassFromString([@[@"UI", @"Web", @"Browser", @"View"] componentsJoinedByString:@""]); + wkMethod = class_getInstanceMethod(wkClass, @selector(inputAccessoryView)); + wkOriginalImp = method_getImplementation(wkMethod); + Class uiClass = NSClassFromString([@[@"WK", @"Content", @"View"] componentsJoinedByString:@""]); + uiMethod = class_getInstanceMethod(uiClass, @selector(inputAccessoryView)); + uiOriginalImp = method_getImplementation(uiMethod); + //set defaults - _swizzledClassNameToClass = [[NSMutableDictionary alloc] init]; self.hideKeyboardAccessoryBar = YES; self.disableScroll = NO; //self.styleDark = NO; - + + NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; + __weak IonicKeyboard* weakSelf = self; _keyboardShowObserver = [nc addObserverForName:UIKeyboardWillShowNotification object:nil queue:[NSOperationQueue mainQueue] @@ -67,47 +71,11 @@ - (void)setDisableScroll:(BOOL)disableScroll { _disableScroll = disableScroll; } --(id)nil_inputAccessoryView { - return nil; -} - -- (void)unswizzleInputAccessoryView { - for (UIView* view in self.webView.scrollView.subviews) { - NSString* currentClassName = NSStringFromClass(view.class); - if ([currentClassName hasPrefix:swizzled]) { - NSString *originalClassName = [currentClassName substringFromIndex:[swizzled length]]; - Class originalClass = NSClassFromString(originalClassName); - object_setClass(view, originalClass); - } - } -} - //keyboard swizzling inspired by: -//https://gist.github.com/bjhomer/2048571 -//http://stackoverflow.com/a/23398487/1091751 -//http://stackoverflow.com/a/19042279/273628 - -- (Class)getSwizzledSubclassOfView:(Class)viewClass { - NSString* swizzledClassName = [NSString stringWithFormat:@"%@%@", swizzled, NSStringFromClass(viewClass)]; - Class newClass = [_swizzledClassNameToClass objectForKey:swizzledClassName]; - if(newClass == nil) { - newClass = objc_allocateClassPair(viewClass, [swizzledClassName UTF8String], 0); - [_swizzledClassNameToClass setObject:newClass forKey:swizzledClassName]; - IMP nilImp = [self methodForSelector:@selector(nil_inputAccessoryView)]; - class_addMethod(newClass, @selector(inputAccessoryView), nilImp, "@@:"); - objc_registerClassPair(newClass); - } - return newClass; -} +//https://github.com/cjpearson/cordova-plugin-keyboard/ -- (void)swizzleInputAccessoryView { - for (UIView* view in self.webView.scrollView.subviews) { - //only swizzle unswizzled instances whose class starts with UIWeb - if(![NSStringFromClass(view.class) hasPrefix:swizzled] && [NSStringFromClass(view.class) hasPrefix:@"UIWeb"]) { - Class swizzledClass = [self getSwizzledSubclassOfView:view.class]; - object_setClass(view, swizzledClass); - } - } +id nil_inputAccessoryView() { + return nil; } - (BOOL)hideKeyboardAccessoryBar { @@ -115,14 +83,16 @@ - (BOOL)hideKeyboardAccessoryBar { } - (void)setHideKeyboardAccessoryBar:(BOOL)hideKeyboardAccessoryBar { - if (hideKeyboardAccessoryBar == _hideKeyboardAccessoryBar || ![self.webView isKindOfClass:[UIWebView class]]) { + if (hideKeyboardAccessoryBar == _hideKeyboardAccessoryBar) { return; } + if (hideKeyboardAccessoryBar) { - [self swizzleInputAccessoryView]; - } - else { - [self unswizzleInputAccessoryView]; + method_setImplementation(wkMethod, (IMP)nil_inputAccessoryView); + method_setImplementation(uiMethod, (IMP)nil_inputAccessoryView); + } else { + method_setImplementation(wkMethod, wkOriginalImp); + method_setImplementation(uiMethod, uiOriginalImp); } _hideKeyboardAccessoryBar = hideKeyboardAccessoryBar; From 27b288f6b7085ecdac42aa4ef270290d8fe7ce98 Mon Sep 17 00:00:00 2001 From: Tony Homer Date: Wed, 4 May 2016 16:13:34 -0400 Subject: [PATCH 09/10] replaced c function to IMP cast with block-based imp --- src/ios/IonicKeyboard.h | 2 +- src/ios/IonicKeyboard.m | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/ios/IonicKeyboard.h b/src/ios/IonicKeyboard.h index aa6e2e5..63935dc 100644 --- a/src/ios/IonicKeyboard.h +++ b/src/ios/IonicKeyboard.h @@ -4,7 +4,7 @@ @interface IonicKeyboard : CDVPlugin { @protected id _keyboardShowObserver, _keyboardHideObserver; - IMP wkOriginalImp, uiOriginalImp; + IMP wkOriginalImp, uiOriginalImp, nilImp; Method wkMethod, uiMethod; } diff --git a/src/ios/IonicKeyboard.m b/src/ios/IonicKeyboard.m index 1b663c4..501e3fd 100644 --- a/src/ios/IonicKeyboard.m +++ b/src/ios/IonicKeyboard.m @@ -18,6 +18,9 @@ - (void)pluginInitialize { Class uiClass = NSClassFromString([@[@"WK", @"Content", @"View"] componentsJoinedByString:@""]); uiMethod = class_getInstanceMethod(uiClass, @selector(inputAccessoryView)); uiOriginalImp = method_getImplementation(uiMethod); + nilImp = imp_implementationWithBlock(^(id _s) { + return nil; + }); //set defaults self.hideKeyboardAccessoryBar = YES; @@ -74,10 +77,6 @@ - (void)setDisableScroll:(BOOL)disableScroll { //keyboard swizzling inspired by: //https://github.com/cjpearson/cordova-plugin-keyboard/ -id nil_inputAccessoryView() { - return nil; -} - - (BOOL)hideKeyboardAccessoryBar { return _hideKeyboardAccessoryBar; } @@ -88,8 +87,8 @@ - (void)setHideKeyboardAccessoryBar:(BOOL)hideKeyboardAccessoryBar { } if (hideKeyboardAccessoryBar) { - method_setImplementation(wkMethod, (IMP)nil_inputAccessoryView); - method_setImplementation(uiMethod, (IMP)nil_inputAccessoryView); + method_setImplementation(wkMethod, nilImp); + method_setImplementation(uiMethod, nilImp); } else { method_setImplementation(wkMethod, wkOriginalImp); method_setImplementation(uiMethod, uiOriginalImp); From efb35400e17efc8eba7d5fef41250ca88d49cf48 Mon Sep 17 00:00:00 2001 From: Tony Homer Date: Tue, 10 May 2016 11:21:07 -0400 Subject: [PATCH 10/10] removed cruft --- plugin.xml | 5 ----- src/ios/IonicKeyboard.m | 2 -- 2 files changed, 7 deletions(-) diff --git a/plugin.xml b/plugin.xml index 57a1d4f..372d790 100644 --- a/plugin.xml +++ b/plugin.xml @@ -38,13 +38,8 @@ - - diff --git a/src/ios/IonicKeyboard.m b/src/ios/IonicKeyboard.m index 501e3fd..d072ca7 100644 --- a/src/ios/IonicKeyboard.m +++ b/src/ios/IonicKeyboard.m @@ -2,8 +2,6 @@ // #import "UIWebViewExtension.h" #import -NSString* const swizzled = @"swizzled_"; - @implementation IonicKeyboard @synthesize hideKeyboardAccessoryBar = _hideKeyboardAccessoryBar;