Xamarin演练:绑定一个Objective-C类库
本文提供一个手把手的练习,通过Xamarin.iOS绑定(Binding)到一个现有的Obj-C类库:InfColorPicker。这将涉及诸如编译一个静态的Obj-C类库,绑定这个类库,Xamarin.iOS应用程序使用这个绑定等问题。
概括
●首先,我们用xcode创建一个Obj-C静态库。●之后我们用Xamarin.iOS绑定这个静态库。●接着使用工具 Objective Sharpie自动生成一些(是的,不是全部)必要的API定义,这能减少自己定义的工作量。●最后,我们建立一个Xamarin.iOS项目来使用这个绑定。
这个示例将演示我们的c#代码使用强委托(strong delegate 译注1)调用InfColorPicker API。之后我们通过弱委托(weak delegate)来实现同样的功能。
要求
本文假设读者对Xcode和Obj-C有一定了解,并且已经读过 Binding Objective-C这篇文档。此外,下列的这些是必须的:
●Xcode 6 和 iOS --在苹果机上已经安装Xcode 6和最近的iOS API。●Xcode Command Line Tools --在苹果机上已经安装当前Xcode版本匹配的Xcode命令行工具。(参阅下文的安装细节)●Xamarin Studio 或 Visual Studio --在开发机已安装最新版的Xamarin Studio 或VisualStudio。Xamarin Studio (或Xamarin Build Host) 和一台苹果mac机是开发Xamarin应用必须的。( 译注2)●Objective Sharpie--当前版本的Objective Sharpie可以在 这里下载。
安装Xcode命令行工具Xcode Command Line Tools
如上所述,我们会使用到Xcode命令行工具(特别是make和lipo命令)。make命令是一个非常普遍的Unix命令,能执行makefile中的命令对项目程序和库进行编译。( 译注3)lipo是一个OS X的命令工具,能把适用于不同硬件架构的多个静态库文件(.a文件)打包到一个文件中。
按照苹果文档 Building from the Command Line with Xcode FAQ,在OS X10.9版本和更新的版本中,Xcode的首选项(默认)不再支持command-line tools的下载。
●安装Xcode6 或新版本--在安装X6时,一些命令行工具已捆绑安装。 在OS X 10.9及之后,可以使用xcrun命令。
●使用终端(Terminal Application)-- 可以在终端中使用xcode-select --install命令安装:
打开终端
输入xcode-select --install 并回车
会有安装向导,点击“安装”(Install)
![]()
安装包会从苹果服务器下载并安装:
![]()
●从Apple Developers下载--Downloads for Apple Developers:
![]()
安装完命令行工具后,我们已经准备好继续进行这个演练。
演练
在这个演练里,我们会进行下列步骤:●新建一个静态库--这步包括创建一个 Obj-C格式的静态库项目InfColorPicker ,输出一个.a扩展名的 静态库文件,该文件最终将被嵌入到.Net的类库中。
●新建一个Xamarin绑定项目-- 当完成一个静态库后,我们需要创建一个Xamarin的绑定项目(译注4)。这个绑定项目由之前我们创建的静态库及C#形式的元数据(meta-data)组成,C#的元数据描述了这些Obj-C API能被怎么使用。 这些元数据通常称为API 定义(API definitions)。我们将使用工具Objective Sharpie来帮助我们自动生成这些API定义。
●规范API定义--Objective Sharpie帮助我们做了很多工作,但在API能被使用前我们需要处理些变化--对自动生成的某些API做些调整。
●使用绑定的类库--最后,我们创建一个Xamarin应用来展示怎么使用之前创建好的绑定库。
现在我们已经知道了会涉及哪些步骤,让我们继续前进完成这些步骤。
创建一个静态类库
• InfColorPicker - 这个文件夹包含项目的Objective-C 代码• PickerSamplePad - 这个包含一个iPad的示例。• PickerSamplePhone - 这个包含一个iPhone的示例。
1.启动Xcode
2.在文件菜单(File)下选择新建一个项目(New>Project) ...
因为InfColorPicker.h文件已经默认生成,Xcode不允许我们覆盖它(不一定),我们打开Finder,定位到之前从github下载解压的项目中,拷贝InfColorPicker 下的所有文件并黏贴到我们新建的静态库项目中:
11.在Xcode方案选择(Scheme Selector)中,选择 InfColorPicker > iOS Device (确认下载的代码能在本机编译):
14.在Xcode菜单Product 下,选择 Build For > Running:
创建一个完全版的类库
如上所述,刚建立的库文件只能适用于真正的iOS设备。为了也能在iOS模拟器上适用,我们需要创建一个完全版的类库。这有如下3个步骤的工作:•创建一个ARM 7版本的静态库•创建一个x86 版本的静态库•使用lipo命令将2个库打包到一起
有很多工具可以自动化这样的任务--一个shell脚本、rake、build、和make。当我们安装命令行工具时已经自动安装了make,所以在这个练习里我们会使用make。这里给出一段makefile命令,它可以生成适用于iOS设备与模拟器的InfColorPicker库并打包成一个:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15XBUILD=/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild PROJECT_ROOT=./InfColorPicker PROJECT=$(PROJECT_ROOT)/InfColorPicker.xcodeproj TARGET=InfColorPicker all: libInfColorPickerSDK.a libInfColorPicker-i386.a: $(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphonesimulator -configuration Release clean build -mv $(PROJECT_ROOT)/build/Release-iphonesimulator/lib$(TARGET).a $@ libInfColorPicker-armv7.a: $(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphoneos -arch armv7 -configuration Release clean build -mv $(PROJECT_ROOT)/build/Release-iphoneos/lib$(TARGET).a $@ libInfColorPickerSDK.a: libInfColorPicker-i386.a libInfColorPicker-armv7.a xcrun -sdk iphoneos lipo -create -output $@ $^ clean: -rm -f *.a *.dll
(译注:命令注意用tab键分隔)
在mac机上打开终端,并定位到 InfColorPicker Xcode 静态库项目( Static Library)所在文件夹
输入make命令并回车,Makefile 将被执行:
libInfColorPicker-armv7.a,libInfColorPicker-i386.a , libInfColorPickerSDK.a
创建Xamarin.iOS绑定项目
在我们可以使用Objective-Sharpie自动处理前,我们需要先创建一个Xamarin.iOS绑定项目来容纳这些API定义(Objective-Sharpie会为我们自动生成定义)及C#的连接描述。让我们做以下:
1.启动Xamarin Studio2.在“File”菜单下选择新建一个方案(New > Solution...):
3.在新建方案对话框,选择新建一个绑定项目(Library > iOS Binding Project):![]()
4.点击下一步"Next"
5.输入InfColorPickerBinging作为绑定项目的名称,点击"Create"按钮创建方案:
![]()
方案被创建并默认已经包含2个文件:
![]()
• ApiDefinition.cs -- 这个文件是Obj-C API怎样被包装成C#的约定。
• StructsAndEnums.cs -- 这个文件里列出必要的结构和枚举声明。
在绑定项目中添加库
1.在刚创建的方案里右击InfColorPicker项目,在弹出菜单选择添加文件Add > Add Files...:
2.定位到 libInfColorPickerSDK.a文件,选中它并点击"Open"按钮
3.选择拷贝文件到文件夹(Copy the file to the directory),点击"OK"按钮
4.文件会被添加到项目里
当这个.a文件被添加到绑定项目,Xamarin.iOS会自动识别出这个Obj-C库,生成一个特定名称的文件libInfColorPickerSDK.linkwith.cs:
这个文件中的LinkWith属性告诉Xamarin该怎么处理这个刚添加的静态库。文件中内容是如下的一段代码:复制代码1
2
3using ObjCRuntime; [assembly: LinkWith ("libInfColorPickerSDK.a", SmartLink = true, ForceLoad = true)]
使用Objective Sharpie
开始,让我们下载Objective Sharpie的安装包,运行安装程序,按照屏幕上的向导完成安装。
安装成功后,运行终端,输入下列命令可以查看这个工具提供的功能。
复制代码1sharpie -help
复制代码1Europa:Resources kmullins$sharpie -help复制代码1usage: sharpie [OPTIONS] TOOL [TOOL_OPTIONS]复制代码1复制代码1Options:复制代码1-h, --helpShow detailed help复制代码1-v, --versionShow version information复制代码1复制代码1Available Tools:复制代码1复制代码1xcode Get information about Xcode installations and available SDKs.复制代码1复制代码1bind Create a Xamarin C#binding to Objective-C APIs复制代码1Europa:Resources kmullins$
我们会用到 ObjectiveSharpie的如下命令:
要获取 Objective Sharpie具体工具的帮助信息,可以输入工具的名称和 -help命令。 例如输入sharpie xcode -help会得到下列的信息:xcode --这个命令提供一些当前的Xcode、及iOS和MacAPIs的版本信息。当之后我们进行绑定工作时会用到这些信息。bind --我们将使用这个命令来解析InfColorPicker 项目的头文件(.h文件)来初始化ApiDefinition.cs 和StructsAndEnums.cs 文件。
复制代码1Europa:Resources kmullins$sharpie xcode -help复制代码1usage: sharpie xcode [OPTIONS]+复制代码1复制代码1Options:复制代码1-h, --help Show detailed help复制代码1-v, --verbose Be verbose with output复制代码1--sdks List all available Xcode SDKs. Pass -verbose for复制代码1more details.复制代码1Europa:Resources kmullins$
在我们处理绑定前,需要确认当前安装的一些SDK的信息。在终端输入以下命令sharpie xcode -sdks:
查看上面,可以看到机器上已经安装有 iphoneos8.1 SDK 。根据这个,我们已经准备好解析 InfColorPicker 项目的头文件,并初始生成 ApiDefinition.cs 和 StructsAndEnums.cs文件了。复制代码1
2
3
4
5
6
7Europa:Resources kmullins$ sharpie xcode -sdks macosx10.10 macosx10.9 iphoneos8.1 iphonesimulator8.1 iphonesimulator7.1 Europa:Resources kmullins$
查看上面,可以看到机器上已经安装有 iphoneos8.1 SDK 。根据这个,我们已经准备好解析 InfColorPicker 项目的头文件,并初始生成 ApiDefinition.cs 和 StructsAndEnums.cs文件了。
在终端输入下面的命令:
1sharpie bind --output=InfColorPicker --namespace=InfColorPicker --sdk=iphoneos8.1 [full-path-to-project]/InfColorPicker/InfColorPicker/*.h
[full-path-to-project]是你机器上 InfColorPicker 项目的Xcode 项目文件(.xcodepro)所在的路径。这个例子中,我们使用了*.h的通配符来解析文件夹下的所有头文件。通常你可以不用这样处理,你可以使用一个顶级的头文件,并在里面正确引用所有相关的头文件,然后只要把这个顶级头文件指定给Objective Sharpie就可以。
终端上会有如下输出:
复制代码1Europa:Resources kmullins$sharpie bind -output InfColorPicker -namespace InfColorPicker -sdk iphoneos8.1 /Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPicker.h -unified复制代码1Compiler configuration:复制代码1-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk -miphoneos-version-min=8.1 -resource-dir /Library/Frameworks/ObjectiveSharpie.framework/Versions/1.1.1/clang-resources -arch armv7 -ObjC复制代码1复制代码1[ 0%] parsing /Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPicker.h复制代码1In file included from /Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPicker.h:60:复制代码1/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:28:1: warning: no 'assign',复制代码1'retain', or 'copy' attribute is specified - 'assign' is assumed [-Wobjc-property-no-attribute]复制代码1@property (nonatomic) UIColor* sourceColor;复制代码1^复制代码1/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:28:1: warning: default property复制代码1attribute 'assign' not appropriate for non-GC object [-Wobjc-property-no-attribute]复制代码1/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:29:1: warning: no 'assign',复制代码1'retain', or 'copy' attribute is specified - 'assign' is assumed [-Wobjc-property-no-attribute]复制代码1@property (nonatomic) UIColor* resultColor;复制代码1^复制代码1/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:29:1: warning: default property复制代码1attribute 'assign' not appropriate for non-GC object [-Wobjc-property-no-attribute]复制代码14 warnings generated.复制代码1[100%] parsing complete复制代码1[bind] InfColorPicker.cs复制代码1Europa:Resources kmullins$
同时,在我们的文件夹下,InfColorPicker.enums.cs 和InfColorPicker.cs文件已被创建 :
在Xamarin中打开这2个文件。复制InfColorPicker.cs 中的内容到ApiDefinition.cs ,即用InfColorPicker.cs中namespace开始的代码段替换掉现有的。(using引用声明不用替换)。
目前版本的 Objective Sharpie有时候会创建重复的接口定义,所以我们要找到第一个InfColorPickerControllerDelegate定义删除它。
InfColorPicker 会用到些CoreGraphics的类,需要添加CoreGraphics 的引用:
1using CoreGraphics;
这个版本的Objective Sharpie翻译委托定义(Delegate)时有时会有问题,所以要用下面的的代码替换掉InfColorPickerControllerDelegate接口定义部分的[Protocol, Model] 行。
1
2
3[BaseType(typeof(NSObject))] [Model]
替换后的定义如下:
类似的,我们操作InfColorPicker.enums.cs文件。 除了using引用部分,复制所有内容到StructsAndEnums.cs:
这个版本的Objective Sharpie 还不能创建一个枚举类型的名称(醉了)。我们需要替换掉 <unamed-C-enum>,比如这里使用InfComponentIndex:
到这步,我们的绑定项目已经完成了。让我们编译一下看看有无错误。
使用绑定
1.创建Xamarin.iOS项目,新建一个叫InfColorPickerSample的Xamarin.iOS项目,如下截图:
2.添加对绑定项目的引用-使InfColorPickerSample 项目引用InfColorPickerBinding项目。
3.创建iPhone的UI-双击InfColorPickerSample项目的MainStoryboard.storyboard,在iOS设计界面添加一个叫 ChangeColorButton的按钮控件(Button),如下图:
4.添加 InfColorPickerView.xib --在InfColorPicker 的Obj-C库中包含(include)一个.xib文件,但Xamarin并未把它包含进绑定项目,这会导致我们运行示例程序时错误。解决办法是把这个.xib添加到我们的Xamarin项目。 右击我们的Xamarin项目,选择Add > Add Files,并定位到这个.xib文件。如下图:
5.在对话框中选择拷贝这个文件到项目
接下来,让我们快速浏览下Obj-C中的协议(Protocols 译注7) 是怎么被C#代码解析绑定的。
Protocols 和 Xamarin.iOS
1
2
3
4
5
6
7@protocol InfColorPickerControllerDelegate @optional - (void) colorPickerControllerDidFinish: (InfColorPickerController*) controller; // This is only called when the color picker is presented modally. - (void) colorPickerControllerDidChangeColor: (InfColorPickerController*) controller; @end
1
2
3
4
5
6
7
8
9[BaseType(typeof(NSObject))] [Model] public partial interface InfColorPickerControllerDelegate { [Export ("colorPickerControllerDidFinish:")] void ColorPickerControllerDidFinish (InfColorPickerController controller); [Export ("colorPickerControllerDidChangeColor:")] void ColorPickerControllerDidChangeColor (InfColorPickerController controller); }
当绑定库(binding library)编译时,Xamarin会创建一个叫InfColorPickerControllerDelegate的抽象基类,该基类中用虚方法实现了这个接口。
• 强委托(Strong Delegate)-- 使用强委托是指创建一个继承了InfColorPickerControllerDelegate的子类,并且实现(override)相应的方法。InfColorPickerController 将使用这个类的一个实例来与它的客户沟通。强委托是可感知(可推断),类型安全,及封装良好的。出于这些原因,我们应该尽可能的使用强委托来代替弱委托。
•弱委托(Weak Delegate) -- 一个弱委托是种稍微不同技术方法,它是指在某个类中(比如InfColorPickerSampleViewController)创建一个公共方法并通过添加Export属性把该方法指定(exposing)给InfColorPickerDelegate协议。
在这个演练中,2种方法我们都会讨论到。 让我们从实现一个强委托开始,再完成一个弱委托。
实现一个强委托
用强委托来响应colorPickerControllerDidFinish的信息以完成我们的Xamarin应用。InfColorPickerControllerDelegate的子类--在这个步骤中我们为项目新添加一个类:ColorSelectedDelegate,编辑这个类如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19using InfColorPickerBinding; using UIKit; namespace InfColorPickerSample { public class ColorSelectedDelegate:InfColorPickerControllerDelegate { readonly UIViewController parent; public ColorSelectedDelegate (UIViewController parent) { this.parent = parent; } public override void ColorPickerControllerDidFinish (InfColorPickerController controller) { parent.View.BackgroundColor = controller.ResultColor; parent.DismissViewController (false, null); } } }
新建ColorSelectedDelegate的实例-- 我们的事件处理程序需要一个实例,类型是之前我们创建的ColorSelectedDelegate。编辑类InfColorPickerSampleViewController ,添加一个如下的实例变量:
1ColorSelectedDelegate selector;
初始化这个ColorSelectedDelegate变量--根据下面的代码,更新ViewController中的方法ViewDidLoad,以确保实例selector可用。
1
2
3
4
5
6
7public override void ViewDidLoad () { base.ViewDidLoad (); ChangeColorButton.TouchUpInside += HandleTouchUpInsideWithStrongDelegate; selector = new ColorSelectedDelegate (this); }
实现HandleTouchUpInsideWithStrongDelegate方法--接下来我们需要实现事件处理--当用户点击ColorChangeButton按钮时。编辑ViewController,添加下来的方法:
1
2
3
4
5
6
7
8
9using InfColorPicker; ... private void HandleTouchUpInsideWithStrongDelegate (object sender, EventArgs e) { InfColorPickerController picker = InfColorPickerController.ColorPickerViewController(); picker.Delegate = selector; picker.PresentModallyOverViewController (this); }
我们首先通过静态方法得到 InfColorPickerController的实例, 再把我们定义的强委托赋给InfColorPickerController.Delegate,这个属性是Objective Sharpie为我们自动生成的。
最后我们调用PresentModallyOverViewController方法展示界面InfColorPickerSampleViewController.xib,用户得以选择颜色。
运行程序
到这里我们已经完成了所有功能代码,如果你运行程序,你可以设置背景色如下:
恭喜!你已经实现了在一个Xamarin应用中调用一个Obj-C类库。 接着,我们可以学习下弱委托的使用。
实现弱委托
作为子类继承及使用特定的委托以实现Obj-C协议方式的替代,Xamarin同样提供给你使用任何继承自NSObject的类的方法来实现Obj-C协议的方式--用Export属性装饰你的方法,并提供相应的选择(selectors)。当使用这种方式,你可以将你的类的一个实例赋给WeakDelegate属性来替换使用Delegate属性。弱委托为你提供了灵活性,将委托处理下降到不同的继承层次。让我们看看怎么在Xamarin应用中使用弱委托。
为TouchUpInside创建事件处理
让我们给设置背景色的按钮的TouchUpInside 事件添加事件处理。这个处理和之前章节创建的HandleTouchUpInsideWithStrongDelegate 有相同的职能,不过我们将使用弱委托来替换强委托。
编辑 ViewController类并添加如下的方法:
1
2
3
4
5
6
7
8private void HandleTouchUpInsideWithWeakDelegate (object sender, EventArgs e) { InfColorPickerController picker = InfColorPickerController.ColorPickerViewController(); picker.WeakDelegate = this; picker.SourceColor = this.View.BackgroundColor; picker.PresentModallyOverViewController (this); }
更新ViewDidLoad--我们必须修改ViewDidLoad来使用我们新建的事件处理,修改ViewDidLoad如下的代码段:
1
2
3
4
5
6public override void ViewDidLoad () { base.ViewDidLoad (); ChangeColorButton.TouchUpInside += HandleTouchUpInsideWithWeakDelegate; }
处理 colorPickerControllerDidFinish: Message--当ViewController处理完成,iOS会发送消息colorPickerControllerDidFinish:给弱委托。我们需要建一个C#方法来处理这个消息。为了完成这个,我们创建一个C#方法并用 Export属性修饰。编辑ViewController类并添加如下的方法:
1
2
3
4
5
6
7[Export("colorPickerControllerDidFinish:")] public void ColorPickerControllerDidFinish (InfColorPickerController controller) { View.BackgroundColor = controller.ResultColor; DismissViewController (false, null); }
运行这个程序,它和之前的功能是一样的,但使用弱委托替换了强委托。
到这里,你已经全部完成了整个演练。现在,你应该对怎么创建和使用一个Xamarin绑定项目有了一个了解。
摘要
本文演示了创建和使用一个Xamarin绑定项目的各个过程。首先我们讨论了怎样编译一个现有的Obj-C库到一个静态库。接着我们涉足了怎么创建一个Xamarin绑定项目,及怎么使用Objective Sharpie 生成Obj-C静态库的API定义。我们讨论了怎样更新和调整生成的API定义使它们能恰当的给外部调用。在Xamarin绑定项目完成后,我们转到在Xamarin应用项目中使用这个绑定,特别的,我们还讨论了强委托与弱委托的使用。
译注1:strong delegate在这里使用了C#中更熟悉的"委托"的叫法,但在iOS更强调的是引用的意思。weak delegate类似。
译注2:本文中的Xamarin.iOS是指在苹果机上的Xamarin环境,其实在 windows环境--Xamarin Studio或VS Xamarin中,你可以直接做类似的操作,如在VS里新建一个Xamarin binding project。
译注3:.Net程序员可能对makefile不熟悉,可以理解为一段脚本命令或一个批处理文件,其中会通过命令的方式调用IDE的编译器。在苹果机上可以通过文本软件创建,也有很多插件工具,或者,在终端直接输入命令:touch Makefile。更多信息请搜索makefil相关。
译注4:你同样可以在Windows环境创建绑定项目。
译注5:Obj-C中.h是头文件,.m文件是具体的实现内容。
译注6:可以直接指定具体的路径,也可以使用cd定位到文件夹,使用相对路径。
译注7:Obj-C中的Interface关键字是对类的声明,Protocols关键字 才更接近C#中的interface。
最后
以上就是简单小蝴蝶最近收集整理的关于Xamarin演练:绑定一个Objective-C类库Xamarin演练:绑定一个Objective-C类库的全部内容,更多相关Xamarin演练内容请搜索靠谱客的其他文章。
发表评论 取消回复