2016 年 9 月

第 31 卷,第 9 期

Xamarin - 使用 Xamarin 的跨平台生产力

作者 Kevin Ashley | 2016 年 9 月

如果你最近在硅谷,就会发现投资者和开发人员大多对他们所使用的技术持保守态度。大多数人会先聘请 iOS 开发人员,接下来(如果他们有足够的资金)再聘请 Android 和/或 Windows 开发人员。然而,这种做法是极其低效的,并且会导致多个代码重写:iOS 开发人员使用 Objective-C;Android 开发人员使用 Java;Windows 开发人员使用 C#。他们之间很少互相交流,更谈不上参与代码共享,而这导致应用在各个平台上不一致—通常要浪费数百万美元来支持完全独立的开发分支和技术。对于一种有效、一致的开发策略,使用跨平台技术(如 Xamarin)是获得生产力的关键。随着 Native 预先 (AOT) 编译技术(该技术可从 C# 等高级别语言本机转换为本机平台的静态代码)的兴起,单独的 Android、iOS 和 Windows 开发人员所需的编程模型正在成为历史。

这是传统应用的新方向,但这已经在其他领域取得了成功,如游戏领域。例如,超过一半的适用于 iOS、Android 和 Windows 的 3D 游戏都使用 Unity 进行开发。在 Unity 中生成游戏时,通常会在 Mono 子集上的 C# 中进行开发,这与通过 Xamarin 使用 C# 没有什么区别。Unity 游戏可在 20 多种平台上运行,包括 Windows、Android、iOS、OS X、Xbox、PlayStation 等。这是非游戏类应用可以效仿的一条好途径,Xamarin 为实现这一操作提供了一个极好的平台。

同样的方法是否能用于其他应用,而不仅仅用于游戏? 使用 Xamarin,可以实现以下操作: 我曾使用 Xamarin 创建 Active Fitness,一个基于云的健身平台和移动应用,在全世界拥有超过 200 万的用户 (activefitness.co)。我在开发周期的早期开始使用 Xamarin,从非常早期的版本开始,就能基于 Microsoft Azure 云创建适用于 Windows、iOS 和 Android 的跨平台解决方案。Active Fitness(如图 1 所示)在其本机 iOS、Windows 和 Android 应用中提供多达 90% 的代码共享。这本身就是生产力的提升。而且,大多数 Xamarin(包括 Xamarin.Forms (bit.ly/2a8Yo4g))都是开放源代码,平台可享受良好的社区支持,并且性能等同于本机代码,这要归功于嵌入式系统上的 AOT 支持。此外,Xamarin 包含在 Visual Studio 中,无需额外成本,还包括免费的社区版本。

运行中的 Active Fitness,演示 3D 地图和丰富的 UI
图 1 运行中的 Active Fitness,演示 3D 地图和丰富的 UI

使用 Xamarin 的跨平台应用的设计方面

几年前,每个平台上的移动应用设计截然不同。例如,iOS 应用在设计上真的与 Android 或 Windows 应用完全不一样。现在情况有所不同。现在,大多数适用于 Windows、Android 和 iOS 的新式应用使用相似的概念和设计模式。究竟发生了什么? Microsoft 创建了通用 Windows 平台 (UWP) 应用所使用的新式设计语言;Google 推出了 Material Design;Apple 引入了外观更加现代的 OS 设计。所有这些变化使得应用在 iOS、Android 和 Windows 中的外观和操作更为相似,简化了开发人员的工作(请参阅图 2)。开发人员甚至纷纷采用图标字体,如 Font Awesome,为跨多个平台的操作使用相似的图标概念。当然,平台仍然还存在视觉上的差异,例如,Windows 包含动态磁贴。也许会让人感到惊讶,不过,如果你生成一个跨平台应用,一旦构建好核心,就可以轻松地添加这些功能。

Windows 上的 Active Fitness(左)、Android 上的 Active Fitness(中)和 iOS 上的 Active Fitness(右)
图 2 Windows 上的 Active Fitness(左)、Android 上的 Active Fitness(中)和 iOS 上的 Active Fitness(右)

在使用 Xamarin 进行开发时,你可以直接在 Visual Studio 中为每个平台创建精美的 UI。这意味着使用 iOS 情节提要、Android XML 和 Windows XAML 均可以访问每个控件或小组件以及供应商提供的大量自定义控件。此外,Xamarin 为每个平台完整提供 C# 中的 100% API 访问。

借助为生成共享 UI 提供 API 抽象的 Xamarin.Forms 库,许多设计概念会通过 Xamarin 自定义呈现器自动转换为适用于每个平台的本机控件,从而使你可以将跨平台控件自定义为其在每个平台上的本机表示形式。这样,你获得了一个真正跨平台应用的生产力优势,以及无限制自定义的可能性!

使用 Xamarin.Forms 的一个巨大好处就是它只是一个附加内容,即你添加到项目中的一个库。从生产力和应用的生命周期管理方面来看,这是无价的,因为你可以创建不过多依赖于平台发布周期的代码,平台发布周期通常要慢得多。Xamarin 始终与 iOS、Android 和 Windows 的主要版本具有同步兼容性,现在这是开放源代码,如果你需要将控件添加到 Xamarin.Forms,你可以随时自行添加,方法是查看源代码或加入 Xamarin.Forms 的 GitHub 存储库。此外,Xamarin 通过自定义控件呈现器为本机平台提供几乎无限制的扩展性选项。如果你已经有一个 XAML 应用,那么你非常幸运,因为 Xamarin.Forms 现在已经成为 XAML 的另一种语言,如果你的应用已经使用 Silverlight、UWP 或 XAML,那么你可以轻松地在 iOS 或 Android 中添加跨平台插件。

使用 Xamarin 创建大纲细节导航

让我们通过关注开放源代码 Xamarin 示例存储库 (bit.ly/29Tk9VJ) 的一个示例来了解使用 Xamarin 的好处:iOS、Android 和 Windows 中包含大纲细节(或称为“汉堡”)导航模型的典型应用。如果你要像传统 iOS、Android 和 Windows 开发人员一样编写此应用,那么你最终会得到三个以 Objective-C、Java 和 C# 编写的独立项目,并且还要为每个项目使用不同的控件: Windows 中的 SplitView,以及 iOS 和 Android 中的类似模式。你可以转而使用单个 Xamarin.Forms 实例来为所有平台实现所有这些艰辛的工作,如图 3 所示。

以 Android、iOS 和 Windows 为目标的 Xamarin 大纲细节项目
图 3 以 Android、iOS 和 Windows 为目标的 Xamarin 大纲细节项目

在可移植项目的 App.cs 文件中,我实例化应用的根页面:

public App ()
{
  MainPage =
    new MasterDetailPageNavigation.
    MainPage ();
}

请注意,大部分项目代码位于可移植项目中,并在所有 OS 中共享,此外,在 Xamarin.Forms 中,你可以使用 XAML。如果你熟悉 UWP 本机 SplitView 控件,那么图 4 中的 XAML 可能看上去会非常简单。

图 4 使用 XAML 创建大纲细节页面

<?xml version="1.0" encoding="UTF-8"?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="https://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MasterDetailPageNavigation;assembly=MasterDetailPageNavigation"
x:Class="MasterDetailPageNavigation.MainPage">
  <MasterDetailPage.Master>
    <local:MasterPage x:Name="masterPage" />
  </MasterDetailPage.Master>
    <MasterDetailPage.Detail>
      <NavigationPage>
        <x:Arguments>
        <local:ContactsPage />
        </x:Arguments>
      </NavigationPage>
    </MasterDetailPage.Detail>
</MasterDetailPage>

在开发人员可以通过条件编译和平台选择执行哪些操作方面,Xamarin 具有很强的灵活性。如果平台是 Windows,以下代码将更改母版页的图标:

if (Device.OS == TargetPlatform.Windows)
{
  Master.Icon = "hamburger.png";
}

特定于设备的代码和 Xamarin

到目前为止,一切都很顺利,但是,我能否真正接近我的 Xamarin 代码中的物理平台? 换句话说,我能否区分为不同类型的设备创建的代码? 幸运的是,Xamarin 是为数不多的支持本机编码和 API 访问的跨平台技术之一。类似于可使你区分设备系列(手机、平板电脑或桌面)的 UWP 应用,Xamarin 包含非常有用的 Device.Idiom 选择器,如图 5 所示。

图 5 使用 Device.Idiom 选择平台

switch (Device.Idiom)
  {
  case TargetIdiom.Phone:
    heading.Text += " Phone ";
    break;
  case TargetIdiom.Tablet:
    heading.Text += " Tablet ";
    break;
  case TargetIdiom.Desktop:
    heading.Text += " Desktop ";
    break;
  default:
    heading.Text += " unknown ";
    break;
  }

图 6 显示了另一种非常有用的选择器 Device.OnPlatform,这种选择器可在代码隐藏和 XAML 中使用,以便根据目标 OS 执行不同的操作。

图 6 使用 Device.OnPlatform 来面向不同的平台

// Device.OnPlatform (Action)
//
var box = new BoxView {
  Color = Color.Green,
  WidthRequest = Device.OnPlatform (30, 40, 50),
  HorizontalOptions = LayoutOptions.Center
};
Device.OnPlatform(
  iOS: () =>{
    box.Color = box.Color.MultiplyAlpha(0.5);
    heading.TextColor = Color.Blue;
  },
  Android: () =>{
    box.Color = box.Color.AddLuminosity(0.3);
    heading.TextColor = Color.FromRgb(115, 129, 130);
  },
  WinPhone: () =>{
    box.Color = box.Color.AddLuminosity(0.3);
    heading.TextColor = Color.Accent;
  },
  Default: () =>{
    heading.Text = "what platform is this?!" + Device.OS;
  }
);

在 XAML 中,Xamarin 添加支持不同平台的 OnPlatform 标记,例如:

<Button Text="Start Timer"
  Clicked="TimerClicked"
  BackgroundColor="Gray"
  HorizontalOptions="Center">
  <Button.WidthRequest>
    <OnPlatform x:TypeArguments="x:Double"
      iOS="200"
      Android="300"
      WinPhone="100" />
  </Button.WidthRequest>
</Button>

但如果我想要在本机平台上自定义 Xamarin.Forms 提供的某个控件,该怎么办呢? 我在前面提到过名为“自定义呈现器”的 Xamarin 功能,该功能提供这种灵活性。自定义呈现器是你可以从内置对象派生出来并在特定于平台的实现中提供功能的类。假设我想要生成我自己的 CustomMap 控件:

public class CustomMap : Map
  {
    public List<CustomPin> CustomPins { get; set; }
  }

在本机平台上,我的对象的签名将包括以下内容:

[assembly:ExportRenderer (typeof(CustomMap), typeof(CustomMapRenderer))]

那么,在 Android、iOS 和 Windows 中,我可以不断地自定义我的地图控件的外观。有趣的是,Xamarin 地图控件的包装器在 Windows 上本机包装 Windows 地图控件,在 Android 上本机包装 Google 地图控件,并在 iOS 上本机包装本机 iOS 地图控件。你还可以使用自定义呈现器对哪些内容进行自定义? 基本上可以自定义任何控件! 地图控件是一个相当复杂的示例,但你也可以自定义按钮、标签、滑块或 Xamarin.Forms 中可用的任何控件。

借助 Xamarin.Forms 2.2,Xamarin 现在包含本机嵌入,这可以将任何本机控件添加到 Xamarin.Forms 应用 (bit.ly/29IEvxH)。

从 Xamarin 访问云

Azure 一直便于进行跨平台使用,而且为许多不同平台(包括 iOS 和 Android)提供各种 SDK 并为 Xamarin 提供专用的跨平台示例和支持。正因为如此,我的 Active Fitness 应用才能够扩展到拥有 2 百万用户。多亏了 Azure 的可靠性、支持和性能,用户每天能够在每分钟连接成千上万设备的情况下继续跑步、慢跑和进行各种体育活动。你可以在 Azure 网站上找到多个非常棒的 Xamarin 专用指南,这些指南能帮助你了解最适用于你的应用的 Microsoft 云服务 (bit.ly/2a5kciF)。同时,我也想谈谈云对移动应用非常有用的几个常见领域:

身份验证: 如果你需要对用户进行身份验证或识别用户,那么你很有可能会需要在你的 Xamarin 应用中使用云服务。访问 bit.ly/29HlDD3 了解如何操作。

将推送通知添加到你的应用: 推送通知不仅为应用提供通信机制,还帮助更新特定于平台的功能,如磁贴。在 bit.ly/29HlDD3 上查找更多信息。

脱机同步:在日常使用中,移动应用并不是始终处于联机状态,但即使在设备从后端断开连接的情况下,数据也需要进行无缝同步。请参阅我的有关偶尔断开连接的数据集的 MSDN 杂志文章(网址为 msdn.com/magazine/dn890372),以及 Xamarin 应用快速启动(网址为 bit.ly/29QkXqT)。

Azure 移动应用是集成多种云服务(包括存储、通知和身份验证)的良好起点。请查看位于 bit.ly/29K3IHi 的 Xamarin 应用专用教程。

扩展、组件和插件

通过组件、插件和扩展的大量支持,Xamarin 取得了成功并得到了改进。许多扩展在 GitHub 上可用或可通过 NuGet 获取。一些库—例如 Android 支持库、Google Play 服务客户端库、Facebook SDK,甚至 OxyPlot 等制作图表库—均受到 Xamarin 或其社区的支持。插件是能够让开发人员从共享代码访问本机功能的唯一产品。这意味着,如果你想要访问 GPS 功能,将无需再编写三次代码—只需下载 NuGet 包并直接在共享代码中访问 GPS。一些插件是开放源代码,并受到开发人员的支持。例如,James Montemagno 已经为 Xamarin 开发了大量插件,例如 Connectivity、Settings、Media 和其他等等 (bit.ly/2a2mM7J)。

图 7 显示了我推荐你在深入研究 Xamarin 开发时使用的几个有用扩展。

图 7 Xamarin 扩展

“名称” 说明 NuGet 链接 GitHub 上的文档和源
电池状态 收集电池剩余电量、充电状态和类型。 bit.ly/2a4gbZ6 bit.ly/2a5Ofqm
条形码扫描程序 使用 ZXing.NET.Mobile 扫描并创建条形码。 bit.ly/2a5Ofqm bit.ly/29QykY9
罗盘 访问设备罗盘方向。 bit.ly/2a32UAZ bit.ly/29KfcKV
连接性 获取网络连接性信息,如类型以及连接是否可用。 bit.ly/29QDplO bit.ly/2a33PBr
加密 PCL Crypto 提供一致的可移植加密 API 集。 bit.ly/29Qz5AE bit.ly/29PzwAb
设备信息 获取设备的相关属性,例如 OS、型号、版本和 ID。 bit.ly/29PzPeg bit.ly/29QzSBq
设备运动 提供对加速计、陀螺仪、磁力计和罗盘的访问。 bit.ly/2a6SzTk bit.ly/2a35maG
嵌入的资源 解压缩嵌入资源以供跨平台使用。 bit.ly/29J6Wf3 bit.ly/29J6z46
外部地图 从纬度/经度或地址启动外部地图。 bit.ly/29KgNR0 bit.ly/2abuJbI
文件系统 PCL 存储提供跨平台存储 API。 bit.ly/29LEOru bit.ly/28Ju1AB
地理定位器 检测设备的 GPS 位置。 bit.ly/2a70ekG bit.ly/29Tpuvd
本地通知 显示本地通知。 bit.ly/2arOGYf bit.ly/29TpSd7
媒体 拍摄或选取照片和视频。 bit.ly/2a6rpxi bit.ly/29TqlMm
消息传递 拨打电话、发送短信以及发送电子邮件。 bit.ly/2a8Uie5 bit.ly/29SEdDm
权限 查看并请求运行时权限。 bit.ly/29Tnvo8 bit.ly/29S6ZKv
Akavache 键值存储 异步、永久性(写入到磁盘)键值存储。 bit.ly/29Tou7I bit.ly/2arPSLf
推送通知 适用于 iOS、Android 的跨平台推送通知。 bit.ly/29ToDs5 bit.ly/2aex4CR
设置 简单一致的跨平台设置 API。 bit.ly/29ToTXT bit.ly/2a6tn0Q
共享 轻松共享文本、链接或打开浏览器。 bit.ly/2aa2R51 bit.ly/2aa3sUk
套接字 TCP 和 UDP 侦听器和客户端,以及 UDP 多播。 bit.ly/1rQIyyR bit.ly/1y1UHPb
文本到语音转换 从共享代码实现文本到语言转换。 bit.ly/29S7Yud bit.ly/29MMA3S
用户对话框 启用消息框风格的对话框。 bit.ly/2aa4dMV bit.ly/29Tqzkd
版本跟踪 跟踪用户已安装的应用的版本。 bit.ly/29S8YhH bit.ly/2a74lNW

例如,在跨平台解决方案中使用 Connectivity 插件检查连接性会变成单行式命令,而不是需要在 iOS、Android 和 Windows 中单独实现的特定于平台的代码:

public static bool IsOnline
  {
    get
    {
      return Plugin.Connectivity.CrossConnectivity.Current.IsConnected;
    }
  }

你甚至可以在 bit.ly/29XZ3VM 中找到更多的插件和扩展。

设备支持: Android Wear、WatchKit 和 Microsoft Band

Xamarin 一直对各种各样的设备和市场上的设备平台响应非常迅速。我很高兴能与 Microsoft Band 团队一起协作,在 2016 版中,我们联合发布了 Active Fitness 的一些非常激动人心的功能,增加了对超过 50 种健身活动的支持,包括滑雪、单板滑雪等。此外,Active Fitness 现在支持 Android Wear,如图 8 中精美的表盘所示。如果你在 Android 设备上安装了 Active Fitness,那么将完全支持表盘。

适用于 Active Fitness 应用的 Android Wear 表盘
图 8 适用于 Active Fitness 应用的 Android Wear 表盘

借助 Xamarin,你可以使用以下工具将应用添加到小工具和设备,并提供支持:

  • Android Wear: Xamarin 包含代码示例和支持,包括以 C# 创建表盘。
  • Apple WatchKit: 有关 Xamarin 支持,请查看 bit.ly/29XZ3VM 上的文档。
  • Microsoft Band: 除了 Microsoft Band SDK,GitHub (bit.ly/29WeDli) 和 NuGet (bit.ly/29SOoLA) 上提供一个绝佳的适用于跨平台 Xamarin 应用的 Microsoft Band 包装器。

性能和编译的 XAML

Xamarin.Forms 会结合使用 XAML 和代码隐藏逻辑。如果你愿意,可以只使用代码来实例化和管理你的 UI 对象。事实上,除了效率(XAML 的声明本质使其可以非常高效地进行编写和管理),没有什么能阻止你对 UI 进行最大程度地编码。但是,如果你真的想要这么做,则可以从 ContentPage 派生你的 Page,然后用代码编写所有逻辑,而不使用 XAML,如图 9 所示。

图 9 不使用 XAML 从 ContentPage 派生 Page

class ButtonCodePage : ContentPage
{
  int count = 0;
  public ButtonCodePage()
  {
    Button button = new Button
    {
      Text = String.Format("Tap for click count!")
    };
    button.Clicked += (sender, args) =>
    {
      count++;
      button.Text =
        String.Format("{0} click{1}!", count, count == 1 ? "" : "s");
    };
    this.Content = button;
  }
}

在这种情况下,你的所有 UI 代码都确实是编译的 C#。编译的 XAML 使用类似的原理: 你可以让 Xamarin 预编译你的所有 XAML,这可以使 XAML 文件中包含的 UI 代码更快地进行加载和执行。编译的 XAML 具有多个优点:即时编译时检查、删除加载和实例化时间、减少可执行文件的大小。可以在程序集启用 XAML 编译:

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace MyApp

或在类级别启用 XAML 编译:

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MyPage

总结

使用 Xamarin 进行开发,我学会了专注于生产力,并利用 Microsoft 开放源代码社区的强大功能。正如我介绍的那样,Xamarin 对开放源代码和设备趋势的响应非常迅速: Android Wear、Apple Watch、Microsoft Band 和最新版本的 Android、iOS 和 Windows。此处介绍了几个值得注意的新增功能,这些功能使 Xamarin 成为真正激动人心的平台:

  • Data Pages: 简化数据绑定,更易于生成复杂的多页应用 (bit.ly/29SRtLk)。
  • 本地化和多语言应用工具包: 完全支持 Xamarin 项目,将行业标准 XLIFF 支持添加到你的项目 (bit.ly/2a5Uzwx)。
  • 本机控件嵌入: 使得向 Xamarin 应用添加本机控件变得非常容易 (bit.ly/29IEvxH)。
  • 效果: 可将特定于平台的效果添加到 Xamarin 应用 (bit.ly/29RDrbD)。

Xamarin 提供一种强大且高效的方式来真正生成在 iOS、Android 和 Windows 中运行的具有任何复杂性的跨平台应用。你可以真正地专注于应用的功能和内容,生成将在任何 OS 中运行的功能强大的应用。在开始生成你的第一个 Xamarin 应用后,你很快就会发现一个充满活力的大规模跨平台开发人员社区。


Kevin Ashley  Microsoft 架构技术推广者。他是《Professional Windows 8 Programming》(Wrox, 2012) 一书的合著者,而且是最受欢迎的应用和游戏的开发人员之一,其中最著名的应用当属 Active Fitness (activefitness.co)。他经常参加不同活动、行业演出和网络广播,并进行技术方面的演讲。他的职责在于,与创业公司和合作伙伴密切合作,并在软件设计、业务和技术战略、体系结构和开发方面提供相关建议。你可以访问他的博客 (kevinashley.com),也可在 Twitter (@kashleytwit) 上关注他。

衷心感谢以下 Microsoft 技术专家对本文的审阅: James Montemagno