Xamarin演练:绑定一个Objective-C类库
来源:互联网 发布:嗅探器改变了网络 编辑:程序博客网 时间:2024/06/05 11:00
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库并打包成一个:
XBUILD=/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuildPROJECT_ROOT=./InfColorPickerPROJECT=$(PROJECT_ROOT)/InfColorPicker.xcodeprojTARGET=InfColorPickerall: libInfColorPickerSDK.alibInfColorPicker-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该怎么处理这个刚添加的静态库。文件中内容是如下的一段代码:using ObjCRuntime;[assembly: LinkWith ("libInfColorPickerSDK.a", SmartLink = true, ForceLoad = true)]
使用Objective Sharpie
开始,让我们下载Objective Sharpie的安装包,运行安装程序,按照屏幕上的向导完成安装。
安装成功后,运行终端,输入下列命令可以查看这个工具提供的功能。
sharpie -help
Europa:Resources kmullins$sharpie -helpusage: sharpie [OPTIONS] TOOL [TOOL_OPTIONS]
Options:
-h, --helpShow detailed help
-v, --versionShow version information
Available Tools:
xcode Get information about Xcode installations and available SDKs.
bind Create a Xamarin C#binding to Objective-C APIsEuropa:Resources kmullins$
我们会用到 ObjectiveSharpie的如下命令:
要获取 Objective Sharpie具体工具的帮助信息,可以输入工具的名称和 -help命令。 例如输入sharpie xcode -help会得到下列的信息:xcode --这个命令提供一些当前的Xcode、及iOS和MacAPIs的版本信息。当之后我们进行绑定工作时会用到这些信息。bind --我们将使用这个命令来解析InfColorPicker 项目的头文件(.h文件)来初始化ApiDefinition.cs 和StructsAndEnums.cs 文件。
Europa:Resources kmullins$sharpie xcode -helpusage: sharpie xcode [OPTIONS]+
Options:
-h, --help Show detailed help
-v, --verbose Be verbose with output
--sdks List all available Xcode SDKs. Pass -verbose for
more details.
Europa:Resources kmullins$
在我们处理绑定前,需要确认当前安装的一些SDK的信息。在终端输入以下命令sharpie xcode -sdks:
查看上面,可以看到机器上已经安装有 iphoneos8.1 SDK 。根据这个,我们已经准备好解析 InfColorPicker 项目的头文件,并初始生成 ApiDefinition.cs 和 StructsAndEnums.cs文件了。Europa:Resources kmullins$ sharpie xcode -sdksmacosx10.10macosx10.9iphoneos8.1iphonesimulator8.1iphonesimulator7.1Europa:Resources kmullins$
查看上面,可以看到机器上已经安装有 iphoneos8.1 SDK 。根据这个,我们已经准备好解析 InfColorPicker 项目的头文件,并初始生成 ApiDefinition.cs 和 StructsAndEnums.cs文件了。
在终端输入下面的命令:
sharpie 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就可以。
终端上会有如下输出:
Europa:Resources kmullins$sharpie bind -output InfColorPicker -namespace InfColorPicker -sdk iphoneos8.1 /Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPicker.h -unifiedCompiler configuration:
-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
[ 0%] parsing /Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPicker.h
In file included from /Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPicker.h:60:
/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:28:1: warning: no 'assign','retain', or 'copy' attribute is specified - 'assign' is assumed [-Wobjc-property-no-attribute]@property (nonatomic) UIColor* sourceColor;
^
/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:28:1: warning: default property
attribute 'assign' not appropriate for non-GC object [-Wobjc-property-no-attribute]/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:29:1: warning: no 'assign','retain', or 'copy' attribute is specified - 'assign' is assumed [-Wobjc-property-no-attribute]@property (nonatomic) UIColor* resultColor;
^
/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:29:1: warning: default property
attribute 'assign' not appropriate for non-GC object [-Wobjc-property-no-attribute]4 warnings generated.
[100%] parsing complete
[bind] InfColorPicker.cs
Europa:Resources kmullins$
同时,在我们的文件夹下,InfColorPicker.enums.cs 和InfColorPicker.cs文件已被创建 :
在Xamarin中打开这2个文件。复制InfColorPicker.cs 中的内容到ApiDefinition.cs ,即用InfColorPicker.cs中namespace开始的代码段替换掉现有的。(using引用声明不用替换)。
目前版本的 Objective Sharpie有时候会创建重复的接口定义,所以我们要找到第一个InfColorPickerControllerDelegate定义删除它。
InfColorPicker 会用到些CoreGraphics的类,需要添加CoreGraphics 的引用:
using CoreGraphics;
这个版本的Objective Sharpie翻译委托定义(Delegate)时有时会有问题,所以要用下面的的代码替换掉InfColorPickerControllerDelegate接口定义部分的[Protocol, Model] 行。
[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
@protocol InfColorPickerControllerDelegate@optional- (void) colorPickerControllerDidFinish: (InfColorPickerController*) controller;// This is only called when the color picker is presented modally.- (void) colorPickerControllerDidChangeColor: (InfColorPickerController*) controller;@end
[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,编辑这个类如下:
using 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 ,添加一个如下的实例变量:
ColorSelectedDelegate selector;
初始化这个ColorSelectedDelegate变量--根据下面的代码,更新ViewController中的方法ViewDidLoad,以确保实例selector可用。
public override void ViewDidLoad (){ base.ViewDidLoad (); ChangeColorButton.TouchUpInside += HandleTouchUpInsideWithStrongDelegate; selector = new ColorSelectedDelegate (this);}
实现HandleTouchUpInsideWithStrongDelegate方法--接下来我们需要实现事件处理--当用户点击ColorChangeButton按钮时。编辑ViewController,添加下来的方法:
using 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类并添加如下的方法:
private void HandleTouchUpInsideWithWeakDelegate (object sender, EventArgs e){ InfColorPickerController picker = InfColorPickerController.ColorPickerViewController(); picker.WeakDelegate = this; picker.SourceColor = this.View.BackgroundColor; picker.PresentModallyOverViewController (this);}
更新ViewDidLoad--我们必须修改ViewDidLoad来使用我们新建的事件处理,修改ViewDidLoad如下的代码段:
public override void ViewDidLoad (){ base.ViewDidLoad (); ChangeColorButton.TouchUpInside += HandleTouchUpInsideWithWeakDelegate;}
处理 colorPickerControllerDidFinish: Message--当ViewController处理完成,iOS会发送消息colorPickerControllerDidFinish:给弱委托。我们需要建一个C#方法来处理这个消息。为了完成这个,我们创建一个C#方法并用 Export属性修饰。编辑ViewController类并添加如下的方法:
[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.ios 绑定Objective-C libraries中容易出现的问题
- Xamarin(3)---引用Objective-C class library
- objective-c之动态绑定
- Xamarin 和 Objective-C 开发移动应用的代码区别
- xamarin listview绑定数据
- Xamarin.Forms 数据绑定
- objective-c多态和绑定
- Objective-C动态绑定和多态
- Objective-C 动态绑定 学习笔记
- Xamarin.IOS Binding Objective Sharpie
- 【C#开发iOS】Objective-C与C# with Xamarin的开发代码对比
- Xamarin.iOS使用Objective-C静态类库.a(Linking Native Libraries)
- Xamarin.iOS使用Objective-C静态类库.a(Linking Native Libraries)
- xamarin.ios 绑定 oc libray
- Xamarin 绑定iOS 静态库
- Xamarin的坑-绑定(三)
- C#,URLRewriter 演练
- Eigen介绍及简单使用
- 我承认,我很笨。
- IOS生产实习知识
- Android序列化:Serializable和Parcelable详解
- 浅谈 PHP 中的多种加密技术及代码示例
- Xamarin演练:绑定一个Objective-C类库
- nyoj 6
- OC学习 第十三章 NSDate、NSData常用方法
- Elasticsearch - 集群管理工具Head插件
- 安卓学习教程总结:芯灵思开发板安卓底层开发
- <学习笔记>安卓模拟器错误:INSTALL_FAILED_CPU_ABI_INCOMPATIBLE
- 一个父亲对新婚女儿的自白
- Django1.6 用Form实现注册登录注销修改密码(含代码!)
- 打印中文控制台出现乱码