Introducción a la interoperabilidad con bibliotecas nativas

En este artículo se explica cómo empezar a trabajar con la interoperabilidad de biblioteca nativa mediante Maui.NativeLibraryInterop para simplificar la configuración.

En estas instrucciones se describen los pasos básicos, los puntos de decisión clave y los ejemplos rectores para crear enlaces a través de la interoperabilidad de biblioteca nativa. Para obtener más instrucciones sobre los detalles específicos de la API y la implementación, consulte la documentación de los SDK nativos y las bibliotecas de interés.

Requisitos previos

Instale los requisitos previos:

Nota:

Es posible instalar el Android SDK o las Herramientas de línea de comandos de Xcode de forma independiente. Sin embargo, la instalación de las Herramientas de línea de comandos de Xcode se controla normalmente a través de Xcode . Del mismo modo, la instalación de Android SDK también se controla usualmente a través de Android Studio o de la Extensión de VS Code de .NET MAUI según la documentación de introducción a .NET MAUI.

Creación de un nuevo enlace

La manera más fácil de empezar a crear un nuevo enlace es clonar la plantilla en el repositorio Maui.NativeLibraryInterop y realizar las modificaciones desde allí. Para comprender mejor todo el alcance de la configuración actual de Maui.NativeLibraryInterop, lea más información en la documentación de información general.

Configuración de las bibliotecas de enlace de .NET

La plantilla incluye bibliotecas de enlaces .NET iniciales para Android y para iOS.

Actualice las bibliotecas de enlace para que reflejen las plataformas de destino y la versión de .NET según sea necesario en su aplicación .NET.

Nota:

Por ejemplo, si tiene como objetivo crear solo un enlace de iOS mediante .NET 9, puede hacer lo siguiente:

  1. Elimine la biblioteca de vinculaciones de Android en template/android/NewBinding.Android.Binding, y
  2. Actualice la plataforma de destino en template/macios/NewBinding.MaciOS.Binding/NewBinding.MaciOS.Binding.csproj para que se establezca en net9.0-ios.

Configura los proyectos y las bibliotecas del envoltorio nativo

La plantilla también incluye proyectos iniciales de Android Studio y proyectos de Xcode.

Actualice los proyectos nativos para que reflejen las plataformas y versiones de destino según sea necesario en su aplicación .NET e incluya las bibliotecas nativas de interés con los pasos siguientes.

Configuración: iOS y Mac Catalyst

El proyecto Xcode se encuentra en template/macios/native/NewBinding.

Actualice el proyecto Xcode para que refleje las plataformas y versiones de destino que se admiten en su aplicación .NET. En el proyecto Xcode, haga clic en el marco de nivel superior y en Destinos > General:

  1. Agregue o quite los destinos de soporte según sea necesario.
  2. Ajuste la versión de iOS según sea necesario.

Incorpore la biblioteca nativa para iOS o MacCatalyst en el proyecto Xcode, a través del método que mejor funcione para su biblioteca y sus necesidades (por ejemplo, CocoaPods, Swift Administrador de paquetes).

Configuración: Android

El proyecto de Android Studio se encuentra en template/android/native.

Actualice el proyecto de Android Studio para que refleje las versiones de destino admitidas en su aplicación .NET.

  1. Vaya al archivo build.gradle.kts (:app)
  2. Actualice la versión de compileSdk según sea necesario

Incorpore la biblioteca nativa de Android a través de Gradle

  1. Agregue la dependencia de paquete en el bloque de dependencias del archivo build.gradle.kts (:app).
  2. Agregue el repositorio al bloque dependencyResolutionManagementrepositories en el archivo settings.gradle.kts.
  3. Sincronice el proyecto con los archivos gradle (a través del botón de la esquina superior derecha de Android Studio).

Creación de la interfaz de API

Cree la interfaz de API entre los proyectos nativos y los proyectos de enlace de .NET con los pasos siguientes.

Definición de API: iOS y Mac Catalyst

En el lado nativo, realice actualizaciones en template/macios/native/NewBinding/NewBinding/DotnetNewBinding.swift:

  1. Agregue una instrucción import para importar la biblioteca nativa que acaba de agregar.
  2. Escriba las definiciones de API para las API de biblioteca nativas de interés.
  3. Asegúrese de que el proyecto Xcode se compila correctamente y que está satisfecho con las API.

De vuelta en el lado .NET, ahora estamos listos para la interoperabilidad con la biblioteca nativa:

  1. Ejecute dotnet build desde template/macios/NewBinding.MaciOS.Binding para probar que todo está conectado correctamente y listo para funcionar.
  2. Usa Objective Sharpie para generar las vinculaciones de C# para las actualizaciones de la API de Swift.
    1. Vaya a template/macios/NewBinding.MaciOS.Binding/bin/Debug/net9.0-ios/NewBinding.MaciOS.Binding.resources/NewBindingiOS.xcframework/ios-arm64/NewBinding.framework en el directorio de salida de los proyectos de enlace de MaciOS.
    2. Ejecute sharpie xcode -sdks para obtener una lista de valores SDK objetivo válidos para el comando bind. Seleccione el valor que se alinea con la plataforma y la versión que está apuntando a utilizar con el siguiente comando, por ejemplo iphoneos18.0.
    3. Ejecute sharpie bind para los archivos de encabezado del xcframework creado por el proyecto de enlace.
      sharpie bind --output=sharpie-out --namespace=NewBindingMaciOS --sdk=iphoneos18.0 --scope=Headers Headers/NewBinding-Swift.h
      
    4. Actualice el contenido de template/macios/NewBinding.MaciOS.Binding/ApiDefinition.cs reemplazándolo por el contenido de template/macios/NewBinding.MaciOS.Binding/bin/Debug/net9.0-ios/NewBinding.MaciOS.Binding.resources/NewBindingiOS.xcframework/ios-arm64/NewBinding.framework/sharpie-out/ApiDefinitions.cs y ajuste según sea necesario (por ejemplo, nomenclatura).
    5. Vuelva a ejecutar dotnet build desde template/macios/NewBinding.MaciOS.Binding.

Consulte también la documentación de objective-sharpie para obtener más información sobre esta herramienta.

Definición de API: Android

En el lado nativo, realice actualizaciones en template/android/native/newbinding/src/main/java/com/example/newbinding/DotnetNewBinding.java:

  1. Agregue una instrucción import para importar la biblioteca nativa que acaba de agregar.
  2. Escriba las definiciones de API para las API de biblioteca nativas de interés.
  3. Asegúrese de que el proyecto de Android Studio se compila correctamente y que está satisfecho con las API.

De vuelta en el lado .NET, ahora estamos listos para la interoperabilidad con la biblioteca nativa:

  1. Ejecute dotnet build desde template/android/NewBinding.Android.Binding para probar que todo está conectado correctamente y listo para funcionar. (Nota: Este paso requerirá que tenga JDK 17 instalado)
  2. Haga referencia a las dependencias de vinculación de Android agregando un elemento @(AndroidMavenLibrary) a template/sample/MauiSample.csproj para cada dependencia de maven vinculada en su proyecto Android nativo. Esto habilitará la verificación de dependencias de Java para su proyecto y hará que las compilaciones posteriores produzcan advertencias o errores de compilación para las dependencias faltantes. Puede hacer frente a estas advertencias/errores añadiendo elementos @(AndroidMavenLibrary) o @(PackageReference) como se sugiere para satisfacer la cadena de dependencia de java para la biblioteca nativa que está vinculando. (Nota: A menudo es necesario hacer referencia explícita a las dependencias de gradle/maven, ya que no se incluyen automáticamente en la biblioteca).
<ItemGroup Condition="$(TargetFramework.Contains('android'))">
    <AndroidMavenLibrary Include="{DependencyGroupId}:{DependencyName}" Version="{DependencyVersion}" Bind="false" />
</ItemGroup>

Consulte también la referencia de AndroidMavenLibrary y la documentación de verificación de dependencias de Java para más información sobre este proceso.

Nota:

Puede cambiar el nombre de la clase de marcador de posición DotnetNewBinding para que refleje mejor la biblioteca nativa que se está encapsulando. Para obtener más ejemplos y sugerencias para escribir las definiciones de API, lea más en la sección siguiente: Modificar un enlace existente.

Usa las API en tu aplicación .NET

La plantilla incluye una aplicación de ejemplo de .NET MAUI en template/sample/MauiSample, que hace referencia a los proyectos de enlaces de .NET y permite usar las bibliotecas nativas de inmediato.

Sin embargo, si está interesado en usar sus propias aplicaciones .NET MAUI, .NET para Android, .NET para iOS o .NET para Mac Catalyst, puede hacerlo modificando los archivos de proyecto de la aplicación .NET para hacer referencia a las bibliotecas de enlace:

<!-- Reference to MaciOS Binding project -->
<ItemGroup Condition="$(TargetFramework.Contains('ios')) Or $(TargetFramework.Contains('maccatalyst'))">
    <ProjectReference Include="..\..\macios\NewBinding.MaciOS.Binding\NewBinding.MaciOS.Binding.csproj" />
</ItemGroup>

<!-- Reference to Android Binding project -->
<ItemGroup Condition="$(TargetFramework.Contains('android'))">
    <ProjectReference Include="..\..\android\NewBinding.Android.Binding\NewBinding.Android.Binding.csproj" />
</ItemGroup>

Modificación de un enlace existente

Si la superficie de API existente no expone la funcionalidad que necesita en su propio proyecto, es el momento de realizar sus propias modificaciones.

iOS y Mac Catalyst

Dentro del proyecto Xcode, encontrará uno o varios archivos Swift que definen la superficie de API pública para el enlace. Por ejemplo, el método register para Firebase Messaging se define como:

@objc(MauiFIRMessaging)
public class MauiFIRMessaging : NSObject {

    @objc(register:completion:)
    public static func register(apnsToken: NSData, completion: @escaping (String?, NSError?) -> Void) {
        let data = Data(referencing: apnsToken);
        Messaging.messaging().apnsToken = data
        Messaging.messaging().token(completion: { fid, error in
            completion(fid, error as NSError?)
        })
    }
    // ...
}

Nota:

Los tipos de API de envoltorio nativo que utilizará el binding de .NET deben declararse como public y anotarse con @objc(NameOfType); los métodos también deben marcarse como public y también pueden beneficiarse de anotaciones similares @objc(methodName:parameter1:), en las que se especifican el nombre y los parámetros, lo que ayuda a determinar el binding que generará Objective Sharpie.

Puede observar en este método que la API pública solo usa tipos que .NET for iOS ya reconoce: NSData, String, NSError y una función de devolución de llamada.

En el proyecto Firebase.MaciOS.Binding, el archivo ApiDefinitions.cs contiene la definición de enlace para esta API de contenedor nativo:

using System;
using Foundation;

namespace Firebase
{
    // @interface MauiFIRMessaging : NSObject
    [BaseType (typeof(NSObject))]
    interface MauiFIRMessaging
    {
        [Static]
        [Export ("register:completion:")]
        [Async]
        void Register (NSData apnsToken, Action<string?, NSError?> completion);
        // ...
    }

Supongamos que quiere agregar un método para anular el registro. El código Swift debería tener un aspecto parecido al siguiente:

@objc(unregister:)
public static func unregister(completion: @escaping (NSError?) -> Void) {
    // need delegate to watch for fcmToken updates
    Messaging.messaging().deleteToken(completion: { error in
        completion(error as NSError?)
    })
}

La otra parte consistirá en actualizar el archivo ApiDefinitions.cs en el proyecto de enlace para exponer este nuevo método. Hay dos maneras de hacerlo:

  1. Puede agregar manualmente el código necesario
  2. Después de construir el proyecto de vinculación, puede ejecutar la herramienta objetivo sharpie para generar un archivo ApiDefinitions.cs. Puede intentar encontrar los cambios relevantes de este archivo y copiarlos manualmente, o intentar copiar todo el archivo y examinar la diferencia para encontrar la parte que necesita.

En este caso, los cambios en ApiDefinitions.cs serían:

[Static]
[Export("unregister:")]
[Async]
void UnRegister(Action completion);

Una vez que hayas realizado estos cambios, puedes recompilar el proyecto Binding y la nueva API estará lista para usarla desde tu proyecto de .NET MAUI.

Nota:

Los proyectos de enlace para Mac/iOS no usan generadores de origen, por lo que es posible que el sistema de proyectos e IntelliSense no conozcan las nuevas API hasta que haya vuelto a compilar el proyecto de enlace y vuelva a cargar la solución para que la referencia del proyecto recoja el ensamblado más reciente. Su proyecto de aplicación todavía debe compilarse independientemente de los errores de IntelliSense.

Android

Dentro del proyecto de Android Studio encontrará un directorio de módulos que contiene un archivo java que define la superficie de API pública para el enlace. Por ejemplo, el método initialize para Facebook se define como se indica a continuación:

package com.microsoft.mauifacebook;

import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;

import com.facebook.LoggingBehavior;
import com.facebook.appevents.AppEventsLogger;

public class FacebookSdk {

    static AppEventsLogger _logger;

    public static void initialize(Activity activity, Boolean isDebug) {
        Application application = activity.getApplication();

        if (isDebug) {
            com.facebook.FacebookSdk.setIsDebugEnabled(true);
        }

        com.facebook.FacebookSdk.addLoggingBehavior(LoggingBehavior.APP_EVENTS);

        AppEventsLogger.activateApp(application);

        _logger = AppEventsLogger.newLogger(activity);
    }

    // ...
}

Puede ver en este método que la superficie de API pública solo usa tipos que .NET para Android ya conoce: Activity y Boolean.

En el proyecto Facebook.Android.Binding, el archivo Transforms/Metadata.xml contiene solo algunos xml para describir cómo asignar el nombre del paquete java (com.microsoft.mauifacebook) a un espacio de nombres más amigable para C# (Facebook). Por lo general, los enlaces Android son más "automáticos" que Mac/iOS en este punto, y rara vez debería necesitar hacer cambios en estos archivos de transformación.

<metadata>
    <attr path="/api/package[@name='com.microsoft.mauifacebook']" name="managedName">Facebook</attr>
</metadata>

Supongamos que quiere agregar un método para registrar un evento. El código java debería tener un aspecto parecido al siguiente:

public static void logEvent(String eventName) {
    _logger.logEvent(eventName);
}

A partir de este simple cambio, el proyecto de enlace no requiere actualizaciones del archivo Transforms/Metadata.xml u otros. Simplemente puede recompilar el proyecto de enlace y la nueva API estará lista para usarse desde el proyecto .NET MAUI.

Nota:

Los proyectos de enlace para Android no usan generadores de origen, por lo que es posible que el sistema de proyectos e IntelliSense no conozcan las nuevas API hasta que haya vuelto a compilar el proyecto de enlace y vuelva a cargar la solución para que la referencia del proyecto recoja el ensamblado más reciente. Su proyecto de aplicación todavía debe compilarse independientemente de los errores de IntelliSense.