在 iOS 扩展中重复使用 Xamarin 页
借助 iOS 扩展,可以通过向预定义的 iOS 和 macOS 扩展点添加额外功能来自定义现有系统行为,例如自定义上下文操作、密码自动填充、来电筛选器、通知内容修饰符等。 Xamarin.iOS 支持扩展,此指南将指导你使用 Xamarin 工具创建 iOS 扩展。
扩展将作为容器应用的一部分进行分发,并从主机应用中的特定扩展点激活。 容器应用通常是一个简单的 iOS 应用程序,它为用户提供有关扩展以及如何激活和使用它的信息。 在扩展与容器应用之间共享代码有三种主要方法:
常见的 iOS 项目。
可以将容器与扩展之间的所有共享代码放入共享 iOS 库,然后从这两个项目引用该库。 通常,共享库包含本机 UIViewController,并且必须是 Xamarin.iOS 库。
文件链接。
在某些情况下,容器应用提供大部分功能,而扩展需要呈现单个
UIViewController
。 由于要共享的文件很少,通常会从容器应用中的相应文件向扩展应用添加文件链接。常见的 Xamarin.Forms 项目。
如果已经使用 Xamarin.Forms 框架与其他平台(如 Android)共享应用页面,则常见方法是在扩展项目中在本机重新实现所需的页面,因为 iOS 扩展适用于本机 UIViewController(而不是 Xamarin.Forms 页面)。 必须执行其他步骤才能在 iOS 扩展中使用 Xamarin.Forms,如下所述。
iOS 扩展项目中的 Xamarin.Forms
在本机项目中使用 Xamarin.Forms 的功能通过 Native Forms 提供。 它允许将 ContentPage
派生页面直接添加到本机 Xamarin.iOS 项目。 CreateViewController
扩展方法可将 Xamarin.Forms 页面的实例转换为本机 UIViewController
,后者可用作或修改为常规控制器。 由于 iOS 扩展是一种特殊的本机 iOS 项目,因此也可在此处使用 Native Forms。
重要
iOS 扩展存在许多已知限制。 虽然可以在 iOS 扩展中使用 Xamarin.Forms,但应非常谨慎并监视内存使用情况和启动时间。 否则,扩展可能会被 iOS 终止,而无法以任何方式正常处理此扩展。
演练
在本演练中,你将创建 Xamarin.Forms 应用程序、Xamarin.iOS 扩展并在扩展项目中重复使用共享代码:
打开 Visual Studio for Mac,使用“空白窗体应用”模板创建新的 Xamarin.Forms 项目,并将其命名为“FormsShareExtension”:
在 FormsShareExtension/MainPage.xaml 中,将内容替换为以下布局:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage x:Class="FormsShareExtension.MainPage" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://xamarin.com/schemas/2014/forms/design" xmlns:local="clr-namespace:FormsShareExtension" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:DataType="local:MainPageViewModel" BackgroundColor="Orange" mc:Ignorable="d"> <ContentPage.BindingContext> <local:MainPageViewModel Message="Hello from Xamarin.Forms!" /> </ContentPage.BindingContext> <StackLayout HorizontalOptions="Center" VerticalOptions="Center"> <Label Margin="20" Text="{Binding Message}" VerticalOptions="CenterAndExpand" /> <Button Command="{Binding DoCommand}" Text="Do the job!" /> </StackLayout> </ContentPage>
将名为“MainPageViewMode”的新类添加到“FormsShareExtension”项目中,并将该类的内容替换为以下代码:
using System; using System.ComponentModel; using System.Windows.Input; using Xamarin.Forms; namespace FormsShareExtension { public class MainPageViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string _message; public string Message { get { return _message; } set { if (_message != value) { _message = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Message))); } } } private ICommand _doCommand; public ICommand DoCommand { get { return _doCommand; } set { if(_doCommand != value) { _doCommand = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(DoCommand))); } } } public MainPageViewModel() { DoCommand = new Command(OnDoCommandExecuted); } private void OnDoCommandExecuted(object state) { Message = $"Job {Environment.TickCount} has been completed!"; } } }
这段代码跨所有平台共享,并且还可供 iOS 扩展使用。
在 Solution Pad 中,右键单击相应解决方案,选择“添加”>“新项目”>“iOS”>“扩展”>“操作扩展”, 将其命名为“MyAction”,然后按“创建”:
若要在该 iOS 扩展中使用 Xamarin.Forms 和共享代码,需要添加所需的引用:
右键单击 iOS 扩展,选择“引用”>“添加引用”>“项目”>“FormsShareExtension”,然后按“确定”。
右键单击 iOS 扩展,选择“包”>“管理 NuGet 包...”>“Xamarin.Forms”,然后按“添加包”。
展开扩展项目并修改入口点以初始化 Xamarin.Forms 并创建页面。 根据 iOS 要求,扩展必须在 Info.plist 中将入口点定义为
NSExtensionMainStoryboard
或NSExtensionPrincipalClass
。 激活入口点后(在本例中使用的是ActionViewController.ViewDidLoad
方法),可以创建 Xamarin.Forms 页面的实例并将其向用户显示。 因此,打开入口点并将ViewDidLoad
方法替换为以下实现:public override void ViewDidLoad() { base.ViewDidLoad(); // Initialize Xamarin.Forms framework global::Xamarin.Forms.Forms.Init(); // Create an instance of XF page with associated View Model var xfPage = new MainPage(); var viewModel = (MainPageViewModel)xfPage.BindingContext; viewModel.Message = "Welcome to XF Page created from an iOS Extension"; // Override the behavior to complete the execution of the Extension when a user press the button viewModel.DoCommand = new Command(() => DoneClicked(this)); // Convert XF page to a native UIViewController which can be consumed by the iOS Extension var newController = xfPage.CreateViewController(); // Present new view controller as a regular view controller this.PresentModalViewController(newController, false); }
MainPage
使用标准构造函数实现实例化,在扩展中使用它之前,请使用CreateViewController
扩展方法将其转换为本机UIViewController
。生成并运行应用程序:
若要激活扩展,请导航到 Safari 浏览器,键入任何 Web 地址,例如 microsoft.com,按键导航,然后按页面底部的“共享”图标以查看可用的操作扩展。 从可用扩展列表中选择“MyAction”扩展(只需点击该扩展即可):
该扩展已激活,系统将会向用户显示 Xamarin.Forms 页面。 所有绑定和命令的工作方式均与在容器应用中相同。
原始入口点视图控制器可见,因为它由 iOS 创建和激活。 若要解决此问题,请将新控制器的模式演示样式更改为
UIModalPresentationStyle.FullScreen
,方法是在PresentModalViewController
调用的前面添加以下代码:newController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
在 iOS 模拟器或设备中生成并运行:
重要
对于设备生成,请确保使用正确的生成设置和“发布”配置,如此处所述。