Forum General

Porting Objective-c code to C#

CarLoOSXCarLoOSX USMember ✭✭

Hello Everyone !

I'm trying to port this objective-c code to c# with no success...

Apple is not allowing a setfocus () operation on an html element in their WKWebview.

In need to get running this feature on Xamarin.iOS, the following code is a original answer from another forum. I've try the solution in Objective-c project and it works:

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); 
} 

The following code is our ported code:

using System;
using System.Runtime.InteropServices;
using CoreGraphics;
using Foundation;
using ObjCRuntime;
using WebKit;

        namespace XXXX.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:

(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. ????

Could anyone give us a hand ?

Thankyou so much!

Answers

Sign In or Register to comment.