Xamarin 中的 Objective-c 绑定问题

本文关键字:问题 绑定 Objective-c 中的 Xamarin | 更新日期: 2023-09-27 17:56:56

我正在努力让我的第一个 Xamarin 绑定工作。我正在尝试创建FlatUIKit库的绑定:https://github.com/Grouper/FlatUIKit。

我设法创建了上述项目的胖静态库(通用 .a)。我使用Objective Sharpie为我生成ApiDefinition.cs。我使用该 ApiDefinition.cs 在 Xamarin 中创建了一个 BindingProject(稍作修改以使项目编译)。我拿了那个新.dll,并在一个新项目中尝试了它。从该.dll调用方法工作正常并可编译。但是,我在运行时遇到问题。对FlatUI_UIColor所做的所有静态调用都返回 null。这使得此 API 不可用。

以下是包含颜色的初始 .h:

@interface UIColor (FlatUI)

  • (UIColor *) colorFromHexCode:(NSString *)hexString;
  • (UIColor *) 绿松石色;
  • (UIColor *) 绿色海洋颜色;
  • (UIColor *) emerlandColor;
  • (UIColor *)肾炎颜色;
  • (UIColor *) peterRiverColor;
  • (UIColor *) 伯利兹洞颜色;
  • (UIColor *) 紫水晶颜色;
  • (UIColor *) 紫藤颜色;
  • (UIColor *) 湿沥青颜色;
  • (UIColor *) 午夜蓝色;
  • (UIColor *) 向日葵颜色;
  • (UIColor *) 橘色;
  • (UIColor *) 胡萝卜颜色;
  • (UIColor *) 南瓜颜色;
  • (UIColor *) 茜素颜色;
  • (UIColor *)石榴颜色;
  • (UIColor *) 云彩;
  • (UIColor *) 银色;
  • (UIColor *) 混凝土颜色;
  • (UIColor *) 石棉颜色;

  • (UIColor *) blendedColorWithForegroundColor:(UIColor *)foredeColor 背景颜色:(UIColor *)背景颜色 百分比混合:(CGFloat) 百分比混合;

@end

以下是Objective Sharpie制作的装订:

[Category, BaseType (typeof (UIColor))]
public partial interface FlatUI_UIColor {
    [Static, Export ("colorFromHexCode:")]
    UIColor ColorFromHexCode (string hexString);
    [Static, Export ("turquoiseColor"), Verify ("ObjC method massaged into getter property", "/Users/jhondel/Projects/iOS Libraries/FlatUIKit/Classes/ios/UIColor+FlatUI.h", Line = 14)]
    UIColor TurquoiseColor { get; }
    [Static, Export ("greenSeaColor"), Verify ("ObjC method massaged into getter property", "/Users/jhondel/Projects/iOS Libraries/FlatUIKit/Classes/ios/UIColor+FlatUI.h", Line = 15)]
    UIColor GreenSeaColor { get; }
    /// ...
    [Static, Export ("blendedColorWithForegroundColor:backgroundColor:percentBlend:")]
    UIColor BlendedColorWithForegroundColor (UIColor foregroundColor, UIColor backgroundColor, float percentBlend);
}

在ApiDefintion.cs中,我摆脱了验证。

如果有帮助,这是初始库的 .m:

@implementation UIColor (FlatUI)
// Thanks to http://stackoverflow.com/questions/3805177/how-to-convert-hex-rgb-color-codes-to-uicolor
+ (UIColor *) colorFromHexCode:(NSString *)hexString {
    NSString *cleanString = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""];
    if ([cleanString length] == 3) {
        cleanString = [NSString stringWithFormat:@"%@%@%@%@%@%@",
                       [cleanString substringWithRange:NSMakeRange(0, 1)],[cleanString substringWithRange:NSMakeRange(0, 1)],
                       [cleanString substringWithRange:NSMakeRange(1, 1)],[cleanString substringWithRange:NSMakeRange(1, 1)],
                       [cleanString substringWithRange:NSMakeRange(2, 1)],[cleanString substringWithRange:NSMakeRange(2, 1)]];
    }
    if([cleanString length] == 6) {
        cleanString = [cleanString stringByAppendingString:@"ff"];
    }
    unsigned int baseValue;
    [[NSScanner scannerWithString:cleanString] scanHexInt:&baseValue];
    float red = ((baseValue >> 24) & 0xFF)/255.0f;
    float green = ((baseValue >> 16) & 0xFF)/255.0f;
    float blue = ((baseValue >> 8) & 0xFF)/255.0f;
    float alpha = ((baseValue >> 0) & 0xFF)/255.0f;
    return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}
+ (UIColor *) turquoiseColor {
    static UIColor *turquoise = nil;
    static dispatch_once_t dispatchToken;
    dispatch_once(&dispatchToken, ^{
        turquoise = [UIColor colorFromHexCode:@"1ABC9C"];
    });
    return turquoise;
}

知道为什么FlatUI_UIColor.GreenSeaColor(和其他)返回null吗?

感谢您的帮助。

@jstedfast评论后更新:

感谢您的回复。

我已经使用 makefile 构建了胖库https://github.com/xamarin/monotouch-samples/blob/master/BindingSample/src/binding/Makefile。

它构建了一个通用库(收集 armv7 和 i386)。
当我在 Xamarin 的绑定项目中导入此 .a 时,它会自动生成 LinkWith。就我而言:

[assembly: LinkWith ("libXMBindingLibrarySampleUniversal.a", LinkTarget.ArmV7 | LinkTarget.Simulator, ForceLoad = true)]  

该库仅使用"UIKit"和"Foundation",根据文档,不需要在LinkWith中指定。

生成的.dll似乎很好。我可以在我的示例项目中访问它的方法。我设法创建了一个带有标题的 FlatUIButton,并在运行模拟器时看到标题。但是该按钮无法单击并且是黑色的,因为所有 FlatUI_UIColor.X 都返回 null。我真的不知道发生了什么。

Xamarin 中的 Objective-c 绑定问题

绑定

方法通常将返回 null 如果/当它们无法 P/Invoke 到本机库中时。所以问题可能是你要么在构建中根本没有与本机库链接(或者您在模拟器上运行,例如,本机库在 FAT 二进制文件中没有 i386 支持),要么你有错误的链接器标志。

有两种方法可以为 Xamarin.iOS 的本机库指定链接器标志,但我会引导你完成我认为最简单的方法:

如果您使用的是 Xamarin Studio 并且已使用 Objective-C Binding Project 模板创建了一个项目,则只需添加本机库(扩展名为 .a),Xamarin Studio 将创建一个新的源文件,该文件与本机库的基本名称相同,但扩展名为".linkwith.cs"。

您需要做的是编辑该文件并进行所需的任何调整。

初始 LinkWith 属性应如下所示(这是来自内存,因此可能不是 100% 准确):

[assembly: LinkWith ("libLibraryName.a", LinkTarget.ArmV7 | LinkTarget.ArmV7s | LinkTarget.Simulator, ForceLoad = true)]

如果库是 c++,则需要添加:

IsCxx = true

您还可以指定它所依赖的框架:

Frameworks = "UIKit"
如果本机库

需要与其他本机库链接,则可以使用 LinkerFlags 属性(字符串)指定它们。

(你只需要指定应用程序尚未链接的框架 - 所以你通常可以跳过Foundation和UIKit,但它也没有坏处)

还有其他属性可以设置,但我不记得它们在我的头顶上,所以你可能想检查文档以获取更多可用的属性(谷歌可能会提供其他资源)。

我遇到了同样的问题,解决方案非常简单:

  • .h 标头中的接口称为"iZettle"
  • Objective Sharpie将其翻译成"IZettle"

我有权访问静态属性,但它们为空。经过几天的不同尝试,最后我们将接口名称更改为"iZettle"(注意开头的小"i"),因此它将与头文件中的接口匹配,你猜怎么着,静态不再为空了!

此外,正如@Rolf Bjarne Kvinge指出的那样,当我们为模拟器构建时,没有错误,但是当它为设备构建时,它报告了一个错误,即缺少"iZettle"框架。

因此,也许您应该尝试将public partial interface名称更改为与 objective-c 中的 .h 头文件中相同的名称。