Is your obj-c good enough to explain what Ionic is actually doing in the file that triggers the problem? https://github.com/driftyco/ionic-plugin-keyboard/blob/maste... Are they really doing it in a 'bad' way?
Is your obj-c good enough to explain what Ionic is actually doing in the file that triggers the problem? https://github.com/driftyco/ionic-plugin-keyboard/blob/maste... Are they really doing it in a 'bad' way?
When you use a normal view that uses the keyboard (UITextView, etc.), you can set it to any custom view you want, but because UIWebView is supposed to be used to display websites and not full apps, that property is not accessible, so they access the internal hierarchy of the webView, find the actual view that triggers the keyboard and modify it's property.
An internal undocumented subview which is part of a private framework, aka they're digging into UIWebView's private implementation details[0] in order to do whatever they want to. Which may or may not be possible without that, but sadly that's besides the point.
It's interesting to see that below the now-offending bits are even hackier bits which are currently commented "until [they] know it's app store safe"
[0] which can't be formally private due to the architecture of Cocoa and objective-c I guess
So removing this code would mean that all Ionic apps would display this thing here on all keyboards: https://raw.githubusercontent.com/clrung/PrevNextInputAccess... Did I get this right?
- (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;
}
This iterates through the view hierarchy until it finds a view with class name starting with "UIWebBrowserView". - (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;
}
}
This creates a new class at runtime that is a subclass of UIWebBrowserView (not accessible at compile time), but with the getter method for the inputAccessoryView overridden to return nil instead of the accessory view. - (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];
}
This takes the UIWebBrowserView object and overrides it's class at runtime with the aforementioned subclass with the nil accessory view getter.(Side note, this could also maybe have been done by swizzling out the method on the internal class instead of subclassing at runtime)
I wonder if they can go around the Apple issue by using something like https://github.com/UrbanApps/UAObfuscatedString to generate the "UIWebBrowserView" string.
static NSString browserViewClassName = Obfuscate.U.I.W.e.b.B.r.o.w.s.e.r.V.i.e.w;
- (UIView *)hackishlyFoundBrowserView {
UIScrollView *scrollView = self.scrollView;
UIView *browserView = nil;
for (UIView *subview in scrollView.subviews) {
if ([NSStringFromClass([subview class]) hasPrefix:browserViewClassName]) {
browserView = subview;
break;
}
}
return browserView;
}
This generates the "UIWebBrowserView" string at runtime which may get around Apple's checks.That said, clearly it's not good for Apple to have large numbers of apps relying on private implementation details. It hamstrings them when it comes time to improve the OS. That translates to a harm for users. I'm not advocating for this hack.
I wonder if this could be avoided by switching to WKWebView?
Nope, the keyboard UI is pretty much the same and the API does not provide any more support for disabling the accessory bar.