发新话题
打印

在Visual Studio中使用MonoTouch开发iOS应用程序(上):环境配置

在Visual Studio中使用MonoTouch开发iOS应用程序(上):环境配置



       

       
       

前段时间在工作机上装了Mac OS X,这主要是因为我最近需要开发iPhone应用程序。虽然Xcode,Objective C一定是开发iOS应用程序的主流,但是经过一番考虑,我还是决定尝试一下使用MonoTouch进行开发。MonoTouch是Novell公司基于开源的Mono
台构建的一套iOS开发环境,使用MonoDevelop作为代码编写工具。不过目前的MonoDevelop较之Visual
Studio可谓“萤火之光比皓月之明”,甚至还有无法输入中文的低级问题。因此,至今我所有在Mono上运行的代码其实都是用Visual
Studio写的,这次自然也不例外。不过,这似乎并不是件非常直接的事情……



什么是MonoTouch



Mono是由Novell提供的.NET跨平台执行环境,无论别人如何进行FUD,我使用下来对Mono的感觉很不错,自认为也有足够的理由来支持我的观点,如今无论是微软Mix大会还是社区类型的NDC 2010都有Mono的内容(尤其是后者)。在我看来,如果没有尝试过Mono就发表的猜忌就很难令人接受了。



Mono使用的授权方案允许第三方基于它上构建商业应用程序,MonoTouch便是其中的典型(还有哪些?自己看吧)。
MonoTouch是Novell公司的产品,可以让开发人员在.NET环境下开发iOS应用程序(包括iPhone 4和iPad),支持最新的iOS
SDK 4.1。这样.NET开发人员就可以利用现有的知识来开发iOS应用程序,如.NET 3.5中的绝大部分类库以及C#
3.0。例如,之前有同事抱怨Android里的API没法方便地使用SOAP协议(似乎iOS下也有不便),但是在MonoTouch中,一切的一切都是最常见的Add Web Services,或是用WCF的svcutil.exe便可直接生成代理。



除了.NET 3.5中的类库之外,MonoTouch也提供了访问iOS API(即Cocoa Touch
的.NET接口(尤其是在UI方面)。在这方面MonoTouch不是一味地直接暴露出Cocoa
Touch的功能,而是在一定程度上将它的API改写为更倾向于.NET程序员的形式。例如UIView的Frame属性为
System.Drawing.RectangleF类型,而不是Cocoa
Touch中原本使用的CGRect。当然,尤其是UI方面,MonoTouch还是使用了传统iOS应用程序的架构,包括它的MVC驱动方式。因此,即
使您使用MonoTouch,最好也要能够看懂简单的Objective C代码,因为SDK提供的文档和大量的示例都是用它来实现的。



众所周知,Mono使用JIT(Just-in-Time)编译来执行IL代码,JIT代表了在运行时动态生成原生代码,但是iOS不允许这么做。
因此,MonoTouch实际上是使用了AOT(Ahead-of-Time)编译方式,真正部署在机器上时已经是原生代码了。此外,MonoTouch
还提供了一个Linker,它只会将SDK及我们自己编写的代码中,真正使用到的部分静态链接至应用程序中,这削减了应用程序的体积。从中我们可以看出,
使用MonoTouch开发出来的应用程序,其实和普通使用iOS
SDK开发出的应用程序并没有什么区别,都是完全独立运行的。当然,这也是因为MonoTouch将一个Runtime塞入应用程序内部的关系,这会给应
用程序的体积带来大约5MB的增长,压缩后(也就是用户真正需要下载的体积)大约是3MB。



除了MonoTouch以外,用于Android开发的MonoDroid也已经进入了beta阶段,已经向一些开发人员提供试用版本了。这意味着,在不久的将来,C#及.NET类库将成为Windows Phone,iOS,Android三大移动平台上的跨平台开发工具。关于MonoTouch的更多消息,您可以关注NDC 2010上的相关演讲



在Windows和Mac OS X中共享文件



MonoTouch的开发工具是MonoDevelop和Interface Builder,后者用于编辑应用程序中的UI文件。不过编写C#代码的神器终归是Visual Studio,即便是最简单的Express版本在代码编写方面也胜出MonoDevelop很多,更别说是经过增强的高级版本了。因此,我打算使用Visual Studio编写C#代码,而使用Interface Builder开发UI界面。不过我们要做的第一件事情是在Windows和Mac OS X之间共享源文件。这里我继续基于之前Win7 + VirtualBox + Snow Leopard的环境进行配置,您也可以使用相同的方法连接两台独立的机器。



由于Mac OS X是在虚拟机上,我选择将源文件放在Windows里,并在Mac OS X上访问。首先,我们在Windows上共享一个目录,这里我将整个E盘共享给vbox账号,取名为host-e,并赋予完全控制权限:




然后在Mac OS X中打开Finder,在Go菜单中选择Connect to Server:




在弹出的对话框中输入Windows的IP:




点击Connect,并在下一个对话框中输入用户名的密码(注意这里需要包含机器名):




点击Connnet,此时对话框会列出这个账号的共享内容:




于是我们选择host-e,并点击OK。此时,您会在Finder的Shared栏目中访问到共享的内容,其中的projects目录是这里的关键:




我将所有的项目都存放在e:\projects目录中,接下来也不例外。为了方便起见,我在Mac OS X的home目录下建立一个软链接,指向共享中的projects目录



ln -s /Volumes/host-e/projects ~/Projects


此时我们就能在home目录下看到Projects文件夹了,而在各种应用程序中,我们可以使用~/Projects来访问其中的内容:




自然,其他方式也没有问题,您只要找到适合您自己的最合适的方式即可。例如,我现在提到的共享方式要求两台机器通过网络互连,如果您无法实现这点,也可以借助如Dropbox这样的同步工具,其实也非常方便。



安装MonoTouch



要安装MonoTouch,首先您必须安装Mono,MonoDevelop,iOS SDK。我的配置是:



  • Mono 2.6.7
  • MonoDevelop 2.4
  • iOS SDK 4.1


Mono和iOS SDK的安装过程十分普通,而MonoDevelop的安装方式对于Windows用户可能特殊。在加载了dmg文件以后,会弹出这样一个界面:




根据提示,此时您只需要将MonoDevelop的图标拖至右侧目录中就可以了。



随后,您便可以安装MonoTouch了。MonoTouch是商业产品,不过您可以免费下载它的试用版,无限期使用。不过试用版只能在模拟器上运行调试,如果需要在真机上运行测试、打包、甚至发布至AppStore,则需要购买授权。企业用户自不必说,MonoTouch针对个人用户的授权费用399美金,如果您真有制作应用程序的好点子,那这点钱实在不算什么了。




TOP

在Visual Studio中使用MonoTouch开发iOS应用程序(下)

对于熟悉.NET程序员来说,编写iOS应用程序的最佳选择自然是MonoTouch。在上一篇文章里,
我们已经在Mac OS X上安装了MonoTouch开发环境,并已经能够在Mac OS
X和Windows之间共享文件。现在我们就可以来简单体验一下,如何使用Visual Studio,Interface
Builder以及少量的MonoDevelop来开发一个最最简单的iOS应用程序。



新建项目



根据我的个人习惯,我会先创建一个空白的解决方案。首先在Mac OS X中打开MonoDevelop,然后在菜单中选择File - New - Solution,在弹出对话框的Other分类中选择Blank Solution模板,并填写合适的位置和名称:




然后便是创建iPhone应用程序项目。还是刚才的对话框,选择C# - iPhone and iPad分类下的iPhone
Window-based
Project模板。同样,在对话框下方填写合适的位置和名称,我的习惯是将所有的源代码统一放在src目录下(在解决方案中也会创建一个src目录与之
对应):




点击OK。下一步是额外的项目配置,可以直接点击OK。此时我们就会发现MonoDevelop里展示出的项目文件:




其中Main.cs里包含了项目的启动代码及一个AppDelegate类,MainWindow.xib是主窗口的界面文件,而
MainWindow.xib.designer.cs文件则是MonoDevelop根据xib文件中的标记所自动创建的C#代码,在绝大部分情况下我
们不会去修改它。



编辑界面



双击MainWindow.xib文件,便会打开Interface
Builder。下图左为Library窗口(近似于VS中的Toolbox);中间上方是可视化的UI编辑器,下方则是对象管理器,显示了界面中定义的
对象;右侧便是用来修改属性的Inspector窗口(近似于VS中的Properties窗口):




首先,在Library窗口上方选择Objects,并将一个Round Rect Button拖动至UI编辑器,双击,输入Hello World:




然后,在Library窗口上方选择Classes,在上方列表中选择AppDelegate,并在下方下拉框中选取Outlets,并使用下方加号添加一个id,叫做ButtonCounter:




接着便是个比较有趣的操作。在对象管理器里选中App Delegate对象,并在Inspector上方选择Connections,再将ButtonCounter右侧的小圆点拖动至按钮,这会将ButtonCounter这个id与按钮关联起来,如下图:




在Interface Builder中保存,回到MonoDevelop,打开MainWindow.xib.designer.cs文件,便可以看到其中在AppDelegate中生成的ButtonCounter属性:



private MonoTouch.UIKit.UIButton __mt_ButtonCounter;

[MonoTouch.Foundation.Connect("ButtonCounter")]
private MonoTouch.UIKit.UIButton ButtonCounter {
    get {
        this.__mt_ButtonCounter = ((MonoTouch.UIKit.UIButton)(this.GetNativeField("ButtonCounter")));
        return this.__mt_ButtonCounter;
    }
    set {
        this.__mt_ButtonCounter = value;
        this.SetNativeField("ButtonCounter", value);
    }
}


可见,MonoDevelop根据xib的内容,自动生成了一些C#代码。AppDelegate是个Partial Class,它的另一部分在Main.cs文件中,一会儿我们便会使用这里的ButtonCounter定义。



配置Visual Studio



虽然MonoDevelop的sln和csproj文件的格式与Visual
Studio兼容(包括2005、2008、2010三个版本的VS),但是VS无法识别iPhone应用程序的项目模板,因此如果您直接打开
iOS101.sln则会加载失败。因此,我们需要并行地创建一些sln和csproj,其中大部分内容与MonoDevelop创建的内容保持同步。



例如,我创建了iOS101.VS.sln及iPhoneApp.UI.VS.csproj(一个.NET 2.0的Class
Library)两个文件,它们分别与iOS101.sln和iPhoneApp.UI.csproj放在同样的目录下。值得注意的是
iPhoneApp.UI.VS.csproj文件,如果您直接在VS里创建这个项目文件,它的默认命名空间里也会包含“VS”,您可能需要手动修改一
下。由于要和MonoDevelop中的项目保持一致的“可编译通过性”,我们还需要引用MonoTouch
SDK里提供的dll。于是我在iOS101目录中创建了lib/monotouch目录,并使用如下命令复制所有的MonoTouch提供的dll文
件:



cp /Developer/MonoTouch/usr/lib/mono/2.1/*.dll ~/Projects/iOS101/lib/monotouch


然后,编辑iPhoneApp.UI.VS.csproj的程序集引用和项目文件,最终结果差不多是这样的。请注意MonoTouch中xib文件的类型为Page,而VS中则需要设为None:



<?xml version="1.0" encoding="utf-8"?>
<
Project ...>
  ...
  <ItemGroup>
    <
Reference Include="monotouch">
      <
HintPath>..\..\lib\monotouch\monotouch.dll</HintPath>
    </
Reference>
    <
Reference Include="System">
      <
HintPath>..\..\lib\monotouch\System.dll</HintPath>
    </
Reference>
    <
Reference Include="System.Core">
      <
HintPath>..\..\lib\monotouch\System.Core.dll</HintPath>
    </
Reference>
  </
ItemGroup>
  <ItemGroup>
    <
None Include="Info.plist" />
    <
Compile Include="Main.cs" />
    <
None Include="MainWindow.xib" />
    <
Compile Include="MainWindow.xib.designer.cs">
      <
DependentUpon>MainWindow.xib</DependentUpon>
    </
Compile>
  </
ItemGroup>
  ...
</Project>


在VS的结果则类似于:




试着编译一下,通过则表示配置成功。



编写代码



这里您是否有些疑惑,为什么上面创建的是一个.NET 2.0项目呢?这样我们还能够使用C#
3.0中的高级特性吗?答案是肯定的,只要我们使用的是Visual Studio 2008或是2010,则即使是针对.NET
2.0所编写的代码,VS也会使用C# 3.0的编译器,因为我们都知道其实C# 3.0只需要一点点框架和类库的支持(扩展方法)。您甚至可以使用C#
4.0的部分特性,例如参数的默认值,命名参数等等。可惜您无法使用C#
4.0的动态性,因为它需要DLR和Microsoft.CSharp.dll,又涉及到大量的动态代码生成,我对此没什么信心和意愿。当然您感兴趣的话
也可以尝试一下。我在这里使用.NET
2.0的原因,是希望可以尽可能减少对系统程序集的依赖,而尽量使用MonoTouch所提供的dll。例如现在,除了mscorlib以外,所有的程序
集都与Windows上所安装的.NET Framework无关,这保证了我们编写的代码可以在MonoTouch兼容。



现在就来开始编写代码吧,您可以在VS里打开Main.cs,在AppDelegate的FinishedLaunching方法中添加如下代码,使之成为:



public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    int i = 0;
    this.ButtonCounter.TouchDown += delegate
   
{
        this.ButtonCounter.SetTitle((++i).ToString(), UIControlState.Normal);
    };

    window.MakeKeyAndVisible();

    return true;
}


FinishedLaunching方法在程序启动时调用,此时我们为ButtonCounter添加一个TouchDown事件(类似于
Click)添加一个处理函数。这里用到了C#中的匿名函数特性,并捕获外部的变量i,每次点击按钮都将i加一,并显示在按钮上。在这里我们使用.NET
中比较常用方式添加事件处理,事实上您也可以在Interface
Builder中定义一个Action,并把它与Button的TouchDown事件关联起来。这个Action会表现为一个Partial
Method,您可以在代码里补全其实现。



保存代码后您便可以回到MonoDevelop中,为了能够在iPhone模拟器里运行,您还要修改一个参数。对iPhoneApp.UI点击右
键,打开Options对话框,在左侧选中Build - iPhone Build类别,并将右侧的SDK version设为4.0,如下:




点击OK保存并关闭对话框。此时可以选择菜单Run - Run,或直接使用快捷键Command(即Win键) + Alt +
Enter便会编译项目,并打开模拟器执行程序。在默认情况可能打开的iPad模拟器,您可以在Hardware -
Device中选择iPhone或iPhone 4。运行效果如下:




试着点击按钮查看效果吧。



单元测试及其他



如果您想调试代码,只需要在MonoDevelop中设置端点,并选择菜单Run - Debug,或直接使用快捷键Command +
Enter便可以对模拟器进行调试。但是如果是要单元测试呢?这问题也不大,MonoDevelop自带NUnit项目,您可以创建这样一个单元测试项
目,删除其默认引用,换之为MonoTouch SDK里所提供的程序集,同样您可以在Visual
Studio中开发单元测试代码,但是调试执行必须在MonoDevelop里进行,因为MonoTouch提供的程序集都是Mac下的Mono实现,它
们在Windows下的作用只是为Visual
Studio提供必要的元数据,使我们能够享受到智能提示之类的便利,想要在Windows里运行则是不行的。



但是,事实上我们也可以将Visual Studio里面的项目定义为.NET Framework
3.5项目,并直接使用.NET提供的程序集,对于MonoTouch里额外的程序集,例如System.Json.dll,则面向.NET
3.5自己重新构建一遍即可(源代码可以使用.NET
Reflector获得或是利用Mono上的开源代码)。这么做的优势在于,对于那些与MonoTouch无关的代码,我们都可以在Visual
Studio里进行调试与测试了。于是乎,我们可以在代码开发阶段尽可能留在熟悉而强大的环境中,对开发效率有很大帮助。



这种做法也有缺点,例如,虽然MonoTouch提供的类库与.NET 3.5兼容,但事实上我并不能百分之百保证这点,因此在.NET
3.5里可以编译通过的代码,也有可能无法在MonoTouch里编译执行。此外,这种方法也会让您无法使用Mono程序集中对.NET的扩展(主要是
Mono命名空间下的类库)。不过这两个理论上问题到目前为止还没有给我造成什么困扰,我也只有在需要在查看模拟器运行效果时才回到Mac及
MonoDevelop中。



有些朋友看到System.Json可能会有些熟悉,因为它在Silverlight开发中也有出现。您说的没错,事实上MonoTouch里的程
序集版本号与Silverlight一样,都是2.0.5.0,甚至连强签名都是一致的。只可惜Silverlight里的类库是.NET
3.5的子集,例如所有同步的IO操作都被去除了,因此我们很难使用Silverlight来开发MonoTouch程序。当然,有了
Silverlight,对我们开发MonoTouch也是有所帮助的,这点以后再谈。



最后,您应该已经意识到,我们需要在VS的项目文件与MonoDevelop的项目文件直接做同步,这个同步包括程序集引用与代码文件两方面。如果您觉得手动编辑比较麻烦的话,就写一个自动同步的小程序咯——不会?那么还是先别搞MonoTouch了,从编程基础学起吧。




TOP

发新话题
最近访问的版块