Share via


iOS 拡張機能で Xamarin.Forms ページを再利用する

iOS 拡張機能を使うと、カスタム コンテキスト アクション、パスワード オートフィル、着信通話フィルター、通知コンテンツ修飾子など、iOS と macOS の拡張ポイントによって事前に定義されている特別な機能を追加することで、既存のシステム動作をカスタマイズできます。 Xamarin.iOS では拡張機能がサポートされており、こちらのガイドでは Xamarin ツールを使って iOS 拡張機能を作成する手順が説明されています。

拡張機能はコンテナー アプリの一部として配布され、ホスト アプリの特定の拡張ポイントからアクティブ化されます。 通常、コンテナー アプリは簡単な iOS アプリケーションであり、拡張機能、そのアクティブ化方法、その使用方法に関する情報をユーザーに提供します。 拡張機能とコンテナー アプリの間でコードを共有するには、主に 3 つの方法があります。

  1. 共通 iOS プロジェクト。

    コンテナーと拡張機能の間のすべての共有コードを共有 iOS ライブラリに置いて、両方のプロジェクトからそのライブラリを参照できます。 通常、共有ライブラリにはネイティブ UIViewController が含まれており、それは Xamarin.iOS ライブラリである必要があります。

  2. ファイル リンク。

    コンテナー アプリがほとんどの機能を提供し、拡張機能では 1 つの UIViewController をレンダリングすることだけが必要な場合があります。 共有するファイルが少ない場合は、コンテナー アプリにあるファイルから拡張機能アプリへのファイル リンクを追加するのが一般的です。

  3. 共通 Xamarin.Forms プロジェクト。

    アプリ ページが Xamarin.Forms フレームワークを使って Android などの別のプラットフォームと既に共有されている場合、iOS 拡張機能は Xamarin.Forms ページではなくネイティブ UIViewControllers で動作するため、拡張機能プロジェクトで必要なページをネイティブに再実装するのが一般的な方法です。 iOS 拡張機能で Xamarin.Forms を使うには、追加の手順を実行する必要があります。これについては、以下で説明します。

iOS 拡張機能プロジェクトでの Xamarin.Forms

ネイティブ プロジェクトで Xamarin.Forms を使う機能は、ネイティブ フォームを介して提供されます。 これにより、ContentPage から派生したページを、ネイティブ Xamarin.iOS プロジェクトに直接追加できます。 CreateViewController 拡張メソッドは、Xamarin.Forms ページのインスタンスを、通常のコントローラーとして使用または変更できるネイティブ UIViewController に変換します。 iOS 拡張機能は特別な種類のネイティブ iOS プロジェクトであるため、ここでもネイティブ フォームを使用できます。

重要

iOS 拡張機能には、多くの既知の制限があります。 iOS 拡張機能で Xamarin.Forms を使うことはできますが、非常に慎重に行い、メモリ使用量と起動時間を監視する必要があります。 そうしないと、拡張機能が iOS によって終了される可能性があり、それを適切に処理する方法はありません。

チュートリアル

このチュートリアルでは、Xamarin.Forms アプリケーション (Xamarin.iOS 拡張機能) を作成し、拡張機能プロジェクトで共有コードを再利用します。

  1. Visual Studio for Mac を開き、[空白フォームのアプリ] テンプレートを使って新しい Xamarin.Forms プロジェクトを作成して、FormsShareExtension という名前を付けます。

    Create Project

  2. 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>
    
  3. 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 拡張機能でも使われます。

  4. ソリューション パッドで、ソリューションを右クリックして、[追加] > [新しいプロジェクト] > [iOS] > [Extension] > [Action Extension] を選び、それに MyAction という名前を指定して、[作成] を選びます。

    Screenshot shows the Choose a template with Action Extension selected.

  5. iOS 拡張機能と共有コードで Xamarin.Forms を使うには、必要な参照を追加する必要があります。

    • iOS 拡張機能を右クリックし、[参照] > [参照の追加] > [プロジェクト] > [FormsShareExtension] を選んで、[OK] を選びます。

    • iOS 拡張機能を右クリックし、[パッケージ] > [NuGet パッケージの管理] > [Xamarin.Forms] を選んで、[パッケージの追加] を選びます。

  6. 拡張機能プロジェクトを展開し、Xamarin.Forms を初期化してページを作成するようにエントリ ポイントを変更します。 iOS の要件に従い、拡張機能ではエントリ ポイントを Info.plistNSExtensionMainStoryboard または 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 に変換します。

    アプリケーションをビルドして実行します。

    Screenshot shows a Hello from Xamarin dot Forms message on a mobile device.

    拡張機能をアクティブにするには、Safari ブラウザーに移動し、任意の Web アドレス (例: microsoft.com) を入力し、ナビゲートを押してから、ページの下部にある [共有] アイコンを押して、使用可能なアクション拡張機能を表示します。 使用できる拡張機能の一覧から、MyAction 拡張機能をタップして選びます。

    Screenshot shows a Microsoft Teams Learn more page with the Share icon highlighted on a mobile device.Screenshot shows an Official Home Page with MyAction highlighted on a mobile device.Screenshot shows a Welcome to X F Page created from an i O S extension message on a mobile device.

    拡張機能がアクティブになり、Xamarin.Forms ページがユーザーに表示されます。 コンテナー アプリと同様に、すべてのバインドとコマンドが機能します。

  7. 元のエントリ ポイント ビュー コントローラーは、iOS によって作成およびアクティブ化されるため、表示されています。 これを修正するには、PresentModalViewController の呼び出しの直前に次のコードを追加して、新しいコントローラーのモーダル プレゼンテーション スタイルを UIModalPresentationStyle.FullScreen に変更します。

    newController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
    

    iOS シミュレーターまたはデバイスでビルドして実行します。

    Xamarin.Forms in iOS Extension

    重要

    デバイスでビルドする場合は、こちらで説明されているように、適切なビルド設定とリリース構成を使ってください。