Xamarin方法在调用原始方法时在设备上失败

时间:2018-09-03 16:50:10

标签: ios xamarin.ios arm64 method-swizzling

以下代码在模拟器中有效,但在调用_originalSetTextMethod(self, stringParam)时在设备上失败。

我怀疑问题与此相关,但无法在C#中确定适当的语法:https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaTouch64BitGuide/ConvertingYourAppto64-Bit/ConvertingYourAppto64-Bit.html#//apple_ref/doc/uid/TP40013501-CH3-SW22

任何人都可以提供有关如何使它在设备上运行的建议吗?谢谢。

public static class SetTextSwizzle
{
    [DllImport("/usr/lib/libobjc.dylib")]
    extern static IntPtr class_getInstanceMethod(IntPtr classHandle, IntPtr Selector);

    [DllImport("/usr/lib/libobjc.dylib")]
    extern static IntPtr imp_implementationWithBlock(ref BlockLiteral block);

    [DllImport("/usr/lib/libobjc.dylib")]
    extern static OriginalDelegate method_setImplementation(IntPtr method, IntPtr imp);

    static OriginalDelegate _originalSetTextMethod;

    [MonoNativeFunctionWrapper]
    public delegate void OriginalDelegate(IntPtr one, IntPtr two);
    delegate void CaptureDelegate(IntPtr block, IntPtr self, IntPtr paramOne);

    public static void Initialise() {
        OverrideSetText();
    }

    static void OverrideSetText()
    {
        var method = class_getInstanceMethod(new UILabel().ClassHandle, new Selector("setText:").Handle);
        var block_value = new BlockLiteral();
        CaptureDelegate d = SetTextAndFont;
        block_value.SetupBlock(d, null);
        var imp = imp_implementationWithBlock(ref block_value);
        _originalSetTextMethod = method_setImplementation(method, imp);
    }

    [MonoPInvokeCallback(typeof(CaptureDelegate))]
    static void SetTextAndFont(IntPtr block, IntPtr self, IntPtr stringParam)
    {
        var label = (UILabel)Runtime.GetNSObject(self);
        label?.SetFont();
        _originalSetTextMethod(self, stringParam);
    }
}

2 个答案:

答案 0 :(得分:1)

这是最终为我工作的代码。它有点复杂,因为它需要避免意外的循环调用。

using System;
using ObjCRuntime;
using UIKit;
using System.Runtime.InteropServices;
using Foundation;
using System.Diagnostics;

public static class SetTextSwizzle
    {
        [DllImport("/usr/lib/libobjc.dylib")]
        extern static IntPtr class_getInstanceMethod(IntPtr classHandle, IntPtr Selector);

        [DllImport("/usr/lib/libobjc.dylib")]
        extern static IntPtr method_getImplementation(IntPtr method);

        [DllImport("/usr/lib/libobjc.dylib")]
        extern static IntPtr class_addMethod(IntPtr classPointer, IntPtr selector, IntPtr implementation, char[] typeEncoding);

        [DllImport("/usr/lib/libobjc.dylib")]
        extern static IntPtr imp_implementationWithBlock(ref BlockLiteral block);

        [DllImport("/usr/lib/libobjc.dylib")]
        extern static IntPtr method_setImplementation(IntPtr method, IntPtr imp);

        [DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
        static extern void CallOriginalMethod(IntPtr receiver, IntPtr selector, IntPtr symbol);

        delegate void CaptureDelegate(IntPtr block, IntPtr self, IntPtr paramOne);

        static readonly char[] _objCVoidReturnEncoding = { 'v', '@', ':' };
        static readonly IntPtr _setTextHandle = new Selector("setText:").Handle;
        static readonly IntPtr _setAttributedTextHandle = new Selector("setAttributedText:").Handle;
        static readonly IntPtr _setTextOrigHandle = new Selector("setTextOrig:").Handle;
        static readonly IntPtr _setAttributedTextOrigHandle = new Selector("setAttributedTextOrig:").Handle;

        public static void Initialise() {
            OverrideSetText();
            OverrideSetAttributedText();
            OverrideTextFieldSetText();
            OverrideTextViewSetText();
            OverrideTextViewSetAttributedText();
        }

        static IntPtr GetNewImplementation(CaptureDelegate newMethod) {
            var block_value = new BlockLiteral();
            block_value.SetupBlock(newMethod, null);
            return imp_implementationWithBlock(ref block_value);
        }

        static void OverrideSetText()
        {
            var originalMethod = class_getInstanceMethod(new UILabel().ClassHandle, _setTextHandle);
            var originalImplementation = method_getImplementation(originalMethod);
            class_addMethod(new UILabel().ClassHandle, _setTextOrigHandle, originalImplementation, _objCVoidReturnEncoding);
            method_setImplementation(originalMethod, GetNewImplementation(SetTextAndFont));
        }

        [MonoPInvokeCallback(typeof(CaptureDelegate))]
        static void SetTextAndFont(IntPtr block, IntPtr self, IntPtr stringParam)
        {
            var label = (UILabel)Runtime.GetNSObject(self);
            if (label != null)
            {
                label.SetFont();
                CallOriginalMethod(label.Handle, _setTextOrigHandle, stringParam);
            }
        }


        static void OverrideSetAttributedText()
        {
            var originalMethod = class_getInstanceMethod(new UILabel().ClassHandle, _setAttributedTextHandle);
            var originalImplementation = method_getImplementation(originalMethod);
            class_addMethod(new UILabel().ClassHandle, _setAttributedTextOrigHandle, originalImplementation, _objCVoidReturnEncoding);
            method_setImplementation(originalMethod, GetNewImplementation(SetTextAttributedAndFont));
        }

        [MonoPInvokeCallback(typeof(CaptureDelegate))]
        static void SetTextAttributedAndFont(IntPtr block, IntPtr self, IntPtr attrStringParam)
        {
            var label = (UILabel)Runtime.GetNSObject(self);
            var attrSringObject = (NSAttributedString)Runtime.GetNSObject(attrStringParam);
            if (label != null && attrSringObject != null)
            {
                var customFontString = label.AttributedStringWithCustomFont(attrSringObject);
                CallOriginalMethod(label.Handle, _setAttributedTextOrigHandle, customFontString.Handle);
            }
        }


        static void OverrideTextFieldSetText()
        {
            var originalMethod = class_getInstanceMethod(new UITextField().ClassHandle, _setTextHandle);
            var originalImplementation = method_getImplementation(originalMethod);
            class_addMethod(new UITextField().ClassHandle, _setTextOrigHandle, originalImplementation, _objCVoidReturnEncoding);
            method_setImplementation(originalMethod, GetNewImplementation(SetTextFieldTextAndFont));
        }

        [MonoPInvokeCallback(typeof(CaptureDelegate))]
        static void SetTextFieldTextAndFont(IntPtr block, IntPtr self, IntPtr stringParam)
        {
            var field = (UITextField)Runtime.GetNSObject(self);
            if (field != null)
            {
                field.SetFont();
                CallOriginalMethod(field.Handle, _setTextOrigHandle, stringParam);
            }
        }


        static void OverrideTextViewSetText()
        {
            var originalMethod = class_getInstanceMethod(new UITextView().ClassHandle, _setTextHandle);
            var originalImplementation = method_getImplementation(originalMethod);
            class_addMethod(new UITextView().ClassHandle, _setTextOrigHandle, originalImplementation, _objCVoidReturnEncoding);
            method_setImplementation(originalMethod, GetNewImplementation(SetTextViewTextAndFont));
        }

        [MonoPInvokeCallback(typeof(CaptureDelegate))]
        static void SetTextViewTextAndFont(IntPtr block, IntPtr self, IntPtr stringParam)
        {
            var textView = (UITextView)Runtime.GetNSObject(self);
            if (textView != null)
            {
                textView.SetFont();
                CallOriginalMethod(textView.Handle, _setTextOrigHandle, stringParam);
            }
        }


        static void OverrideTextViewSetAttributedText()
        {
            var originalMethod = class_getInstanceMethod(new UITextView().ClassHandle, _setAttributedTextHandle);
            var originalImplementation = method_getImplementation(originalMethod);
            class_addMethod(new UITextView().ClassHandle, _setAttributedTextOrigHandle, originalImplementation, _objCVoidReturnEncoding);
            method_setImplementation(originalMethod, GetNewImplementation(TextViewSetTextAttributedAndFont));
        }

        [MonoPInvokeCallback(typeof(CaptureDelegate))]
        static void TextViewSetTextAttributedAndFont(IntPtr block, IntPtr self, IntPtr attrStringParam)
        {
            var textView = (UITextView)Runtime.GetNSObject(self);
            var attrSringObject = (NSAttributedString)Runtime.GetNSObject(attrStringParam);
            if (textView != null && attrSringObject != null)
            {
                var customFontString = textView.AttributedStringWithCustomFont(attrSringObject);
                CallOriginalMethod(textView.Handle, _setAttributedTextOrigHandle, customFontString.Handle);
            }
        }
    }```

答案 1 :(得分:0)

尝试将MonoNativeFunctionWrapper属性添加到CaptureDelegate。

[MonoNativeFunctionWrapper] 委托void CaptureDelegate(IntPtr块,IntPtr自身,IntPtr paramOne);