Hello Xamarin.iOS developers !!!
Apple is not allowing a setfocus () operation on an html element in their WKWebview.
We have ported a solution based on objective-c to c #, attached code
Objective-C Code
- (void) keyboardDisplayDoesNotRequireUserAction {
SEL sel = sel_getUid "_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:");
Class WKContentView = NSClassFromString(@"WKContentView");
Method method = class_getInstanceMethod(WKContentView, sel);
IMP originalImp = method_getImplementation(method);
IMP imp = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, id arg3) {
((void (*)(id, SEL, void*, BOOL, BOOL, id))originalImp)(me, sel, arg0, TRUE, arg2, arg3);
});
method_setImplementation(method, imp);
}
c# code
using System;
using System.Runtime.InteropServices;
using CoreGraphics;
using Foundation;
using ObjCRuntime;
using WebKit;
namespace JBCWebManager.iOS.ViewControllers
{
public class WKWebViewEx : WKWebView
{
[DllImport("/usr/lib/libobjc.dylib")] static extern IntPtr class_getInstanceMethod(IntPtr classHandle, IntPtr Selector);
[DllImport("/usr/lib/libobjc.dylib")] static extern IntPtr method_getImplementation(IntPtr method);
[DllImport("/usr/lib/libobjc.dylib")] static extern IntPtr imp_implementationWithBlock(ref BlockLiteral block);
[DllImport("/usr/lib/libobjc.dylib")] static extern void method_setImplementation(IntPtr method, IntPtr imp);
private static IntPtr _original;
public WKWebViewEx(NSCoder coder) : base(coder)
{
AllowDisplayingKeyboardWithoutUserAction();
}
protected WKWebViewEx(NSObjectFlag t) : base(t)
{
AllowDisplayingKeyboardWithoutUserAction();
}
protected internal WKWebViewEx(IntPtr handle) : base(handle)
{
AllowDisplayingKeyboardWithoutUserAction();
}
public WKWebViewEx(CGRect frame, WKWebViewConfiguration configuration) : base(frame, configuration)
{
AllowDisplayingKeyboardWithoutUserAction();
}
static Selector selector1;
private void AllowDisplayingKeyboardWithoutUserAction()
{
IntPtr @class = Class.GetHandle("WKContentView");
NSOperatingSystemVersion iOS_11_3_0 = new NSOperatingSystemVersion(11, 3, 0);
NSProcessInfo processInfo = NSProcessInfo.ProcessInfo;
bool isIOS1130 = processInfo.IsOperatingSystemAtLeastVersion(iOS_11_3_0);
if (isIOS1130)
{
Selector selector = new Selector("_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:");
IntPtr method = class_getInstanceMethod(@class, selector.Handle);
_original = method_getImplementation(method);
BlockLiteral block = new BlockLiteral();
CaptureDelegate d = MyCapture;
block.SetupBlock(d, null);
IntPtr @override = imp_implementationWithBlock(ref block);
method_setImplementation(method, @override);
//IMP override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, BOOL arg3, id arg4)
//{
// ((void(*)(id, SEL, void *, BOOL, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3, arg4);
//});
}
else
{
selector1 = new Selector("_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:");
IntPtr method = class_getInstanceMethod(@class, selector1.Handle);
_original = method_getImplementation(method);
BlockLiteral block = new BlockLiteral();
CaptureDelegate d = MyCapture;
block.SetupBlock(d, null);
IntPtr @override = imp_implementationWithBlock(ref block);
method_setImplementation(method, @override);
//IMP override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, id arg3)
//{
// ((void(*)(id, SEL, void *, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3);
//});
}
}
[MonoNativeFunctionWrapper]
public delegate void OriginalDelegate(NSObject me, Selector sel, IntPtr arg0, bool arg1, bool arg2, NSObject arg3);
delegate void CaptureDelegate(NSObject me, IntPtr arg0, bool arg1, bool arg2, NSObject arg3);
[MonoPInvokeCallback(typeof(CaptureDelegate))]
static void MyCapture(NSObject me, IntPtr arg0, bool arg1, bool arg2, NSObject arg3)
{
OriginalDelegate del = (OriginalDelegate)Marshal.GetDelegateForFunctionPointer(_original, typeof(OriginalDelegate));
del(me, selector1, arg0, true, arg2, arg3);
}
}
}
The code compiles correctly. The problem is very localized in the call of (me, selector1, arg0, true, arg2, arg3), and specifically in the selector1 parameter. This call executes the delegate OriginalDelegate.
The error that occurs at runtime is:
Type ObjCRuntime.Selector which is passed to unmanaged code must have a StructLayout attribute.
and it tells me that the Selector object must have the StructAttribute attribute defined. ????
Thank you so much and sorry for my bad English !!