Reutilizar páginas de Xamarin.Forms en una extensión de iOS

Las extensiones de iOS permiten personalizar el comportamiento del sistema existente agregando una funcionalidad adicional a puntos de extensión predefinidos de iOS y macOS, como acciones de contexto personalizadas, autorrellenado de contraseñas, filtros de llamadas entrantes, modificadores de contenido de notificación, etc. Xamarin.iOS admite extensiones y esta guía le guiará a través de la creación de una extensión de iOS mediante herramientas de Xamarin.

Las extensiones se distribuyen como parte de una aplicación contenedora y se activan desde un punto de extensión específico en una aplicación host. La aplicación Contenedor suele ser una aplicación de iOS sencilla, que proporciona a un usuario información sobre la extensión, cómo activarla y usarla. Hay tres enfoques principales para compartir código entre una extensión y una aplicación contenedora:

  1. Proyecto de iOS común.

    Puede colocar todo el código compartido entre el contenedor y la extensión en una biblioteca compartida de iOS y hacer referencia a la biblioteca de ambos proyectos. Normalmente, la biblioteca compartida contiene uiViewControllers nativos y tiene que ser una biblioteca de Xamarin.iOS.

  2. Vínculos de archivo.

    En algunos casos, la aplicación Contenedor proporciona la mayor parte de la funcionalidad, mientras que la extensión debe representar un solo UIViewController. Con pocos archivos para compartir, es habitual agregar un vínculo de archivo a la aplicación de extensión desde el archivo ubicado en la aplicación contenedora.

  3. Proyecto común de Xamarin.Forms.

    Si las páginas de la aplicación ya se comparten con otra plataforma, como Android, mediante el marco de Xamarin.Forms, el enfoque común es volver a implementar las páginas necesarias de forma nativa en el proyecto de extensión, ya que la extensión de iOS funciona con uiViewControllers nativos y no con páginas de Xamarin.Forms. Tiene que realizar pasos adicionales para usar Xamarin.Forms en la extensión de iOS, que se explica a continuación.

Xamarin.Forms en un proyecto de extensión de iOS

La capacidad de usar Xamarin.Forms en un proyecto nativo se proporciona a través de Native Forms. Permite agregar páginas derivadas de ContentPage directamente a proyectos nativos de Xamarin.iOS. El método de extensión CreateViewController convierte una instancia de una página de Xamarin.Forms en un UIViewController nativo, que se podría usar o modificar como controlador normal. Dado que una extensión de iOS es un tipo especial de un proyecto nativo de iOS, también puede usar formularios nativos aquí.

Importante

Hay muchas limitaciones conocidas para las extensiones de iOS. Aunque puede usar Xamarin.Forms en una extensión de iOS, debe hacerlo con cuidado, supervisar el uso de memoria y el tiempo de inicio. De lo contrario, iOS podría terminar la extensión sin ninguna manera de controlar esto correctamente.

Tutorial

En este tutorial, va a crear una aplicación de Xamarin.Forms, una extensión de Xamarin.iOS y reutilizar código compartido en el proyecto de extensión:

  1. Abra Visual Studio para Mac, cree un proyecto de Xamarin.Forms con la plantilla Aplicación de formularios en blanco y asígnele el nombre FormsShareExtension:

    Crear proyecto

  2. En FormsShareExtension/MainPage.xaml, reemplace el contenido por el siguiente diseño:

    <?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. Agregue una nueva clase denominada MainPageViewMode al proyecto FormsShareExtension y reemplace el contenido de la clase por el código siguiente:

    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!";
            }
        }
    }
    

    El código se comparte en todas las plataformas y también lo usará una extensión de iOS.

  4. En el panel de solución, haga clic con el botón derecho en la solución, seleccione, seleccione Agregar > Nuevo proyecto > iOS > Extensión > Extensión de acción, asígnele el nombre MyAction y presione Crear:

    Captura de pantalla que muestra la opción Elegir una plantilla con la extensión de acción seleccionada.

  5. Para usar Xamarin.Forms en la extensión de iOS y el código compartido, debe agregar referencias necesarias:

    • Haga clic con el botón derecho en la extensión de iOS, seleccione Referencias > Agregar referencias > Proyectos > FormsShareExtension y presione Aceptar.

    • Haga clic con el botón derecho en la extensión de iOS, seleccione Paquetes > Administrar paquetes NuGet... > Xamarin.Forms y presione Agregar paquete.

  6. Expanda el proyecto de extensión y modifique un punto de entrada para inicializar Xamarin.Forms y crear páginas. Según los requisitos de iOS, una extensión debe definir el punto de entrada de Info.plist como NSExtensionMainStoryboard o NSExtensionPrincipalClass. Una vez activado el punto de entrada, en este caso es el método ActionViewController.ViewDidLoad, puede crear una instancia de una página de Xamarin.Forms y mostrarla a un usuario. Por lo tanto, abra el punto de entrada y reemplace el método ViewDidLoad por la siguiente implementación:

    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);
    }
    

    Se crea una instancia de MainPage mediante un constructor estándar y antes de poder usarlo en la extensión, conviértalo en un UIViewController nativo mediante el método de extensión CreateViewController.

    Compile y ejecute la aplicación:

    Captura de pantalla que muestra un mensaje Hello from Xamarin dot Forms en un dispositivo móvil.

    Para activar la extensión, vaya al explorador Safari, escriba cualquier dirección web, por ejemplo, microsoft.com, presione navegar y, a continuación, presione el icono Compartir en la parte inferior de la página para ver las extensiones de acción disponibles. En la lista de extensiones disponibles, seleccione la extensión MyAction pulsando en ella:

    Captura de pantalla que muestra una página más información de Microsoft Teams con el icono Compartir resaltado en un dispositivo móvil. Captura de pantalla que muestra una página principal oficial con MyAction resaltada en un dispositivo móvil. Captura de pantalla que muestra una página de bienvenida a X F creada a partir de un mensaje de extensión de I O S en un dispositivo móvil.

    La extensión se activa y la página de Xamarin.Forms se muestra al usuario. Todos los enlaces y comandos funcionan como en la aplicación Contenedor.

  7. El controlador de vista del punto de entrada original es visible porque iOS lo crea y activa. Para corregirlo, cambie el estilo de presentación modal a UIModalPresentationStyle.FullScreen para el nuevo controlador agregando el código siguiente justo antes de la llamada PresentModalViewController:

    newController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
    

    Compile y ejecute en el simulador de iOS o en un dispositivo:

    Xamarin.Forms en la extensión de iOS

    Importante

    Para la compilación del dispositivo, asegúrese de usar la configuración de compilación adecuada y la configuración Versión, como se describe aquí.