The following code works in simulator but fails on device when calling _originalSetTextMethod(self, stringParam)
.
I suspect the issue is related to this, but can't determine the appropriate syntax in C#: https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaTouch64BitGuide/ConvertingYourAppto64-Bit/ConvertingYourAppto64-Bit.html#//apple_ref/doc/uid/TP40013501-CH3-SW22
Can anybody please offer suggestions as to how I can get this running on device? Thanks.
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);
}
}
This is the code that ended up working for me. It is slightly convoluted as it needs to avoid accidental cyclical calls.
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);
}
}
}```