Compartilhar via


Introdução à Native Library Interop

Este artigo aborda como começar a usar a Native Library Interop usando Maui.NativeLibraryInterop para simplificar a configuração.

Essas instruções descrevem as etapas básicas, os principais pontos de decisão e os exemplos orientadores para a criação de associações por meio da Native Library Interop. Para obter mais diretrizes sobre detalhes específicos de API e implementação, consulte a documentação para os SDKs nativos e bibliotecas de interesse.

Pré-requisitos

Pré-requisitos de instalação:

Observação

É possível instalar o SDK do Android e/ou as ferramentas de linha de comando do Xcode de maneira autônoma. No entanto, a instalação das Ferramentas de Linha de Comando do Xcode normalmente é tratada por meio de Xcode. Da mesma forma, a instalação do SDK do Android também normalmente é tratada por meio do Android Studio e/ou da Extensão do VS Code do .NET MAUI, de acordo com a documentação de Introdução ao .NET MAUI.

Criar uma nova associação

A maneira mais fácil de começar a criar uma nova associação é clonando o modelo no repositório de Maui.NativeLibraryInterop e fazendo modificações nele. Para entender melhor o escopo completo de como Maui.NativeLibraryInterop está configurado no momento, leia mais na documentação de visão geral.

Configurar as bibliotecas de associação do .NET

O modelo inclui o .NET inicial para bibliotecas de associação para Android e .NET para iOS.

Atualize as bibliotecas de associação para refletir as plataformas de destino e a versão do .NET, conforme necessário em seu aplicativo .NET.

Observação

Por exemplo: se você pretende criar apenas uma associação do iOS usando o .NET 9, poderá:

  1. Excluir a biblioteca de associação do Android em template/android/NewBinding.Android.Binding e
  2. Atualizar a estrutura de destino em template/macios/NewBinding.MaciOS.Binding/NewBinding.MaciOS.Binding.csproj a ser definido como net9.0-ios.

Configure os projetos e as bibliotecas nativas do wrapper

O template também inclui projetos do Android Studio e projetos do Xcode.

Atualize os projetos nativos para refletir as plataformas e versões de destino, conforme necessário em seu aplicativo .NET, e inclua as bibliotecas nativas de interesse com as etapas a seguir.

Instalação: iOS e Mac Catalyst

O projeto Xcode está localizado em template/macios/native/NewBinding.

Atualize o projeto Xcode para refletir as plataformas de destino e as versões com suporte em seu aplicativo .NET. No projeto Xcode, clique na estrutura de nível superior e em Destinos > Geral:

  1. Adicione/remova todos os Destinos de Suporte conforme necessário.
  2. Ajuste a versão do iOS conforme necessário.

Traga a biblioteca nativa para iOS e/ou MacCatalyst em seu projeto Xcode, através de qualquer método que funcione melhor para a biblioteca e as necessidades (por exemplo, CocoaPods, Swift Package Manager).

Configuração: Android

O projeto do Android Studio está localizado em template/android/native.

Atualize o projeto do Android Studio para refletir as versões de destino com suporte em seu aplicativo .NET.

  1. Navegue até o arquivo build.gradle.kts (:app)
  2. Atualizar a versão do compileSdk conforme necessário

Traga a biblioteca nativa do Android por meio do gradle

  1. Adicione a dependência do pacote no bloco de dependências do arquivo build.gradle.kts (:app).
  2. Adicione o repositório ao bloco dependencyResolutionManagement repositories no arquivo settings.gradle.kts.
  3. Sincronizar projeto com arquivos de gradle (por meio do botão no canto superior direito do Android Studio).

Criar a interface de API

Crie a interface de API entre seus projetos nativos e seus projetos de associação do .NET com as etapas a seguir.

Definição de API: iOS e Mac Catalyst

No lado nativo, faça atualizações em template/macios/native/NewBinding/NewBinding/DotnetNewBinding.swift:

  1. Adicione uma instrução de importação para importar a biblioteca nativa que você acabou de adicionar.
  2. Escreva as definições de API para as APIs de interesse da biblioteca nativa.
  3. Verifique se o projeto do Xcode é compilado com êxito, e se você está satisfeito com as APIs.

De volta ao lado do .NET, agora estamos prontos para interoperabilidade com a biblioteca nativa:

  1. Execute dotnet build de template/macios/NewBinding.MaciOS.Binding para testar se tudo está conectado corretamente e pronto. Se for bem-sucedido, você deverá ver as associações C# geradas em template/macios/native/NewBinding/bin/Release/net8.0-ios/sharpie/NewBinding/ApiDefinitions.cs.
  2. Atualize o conteúdo de template/macios/NewBinding.MaciOS.Binding/ApiDefinition.cs substituindo-o pelo conteúdo de template/macios/native/NewBinding/bin/Release/net8.0-ios/sharpie/NewBinding/ApiDefinitions.cs.
  3. Execute dotnet build de template/macios/NewBinding.MaciOS.Binding novamente.

Definição da API: Android

No lado nativo, faça atualizações em template/android/native/app/src/main/java/com/example/newbinding/DotnetNewBinding.java:

  1. Adicione uma instrução de importação para importar a biblioteca nativa que você acabou de adicionar.
  2. Escreva as definições de API para as APIs de interesse da biblioteca nativa.
  3. Verifique se o projeto do Android Studio é compilado com êxito, e se você está satisfeito com as APIs.

De volta ao lado do .NET, agora estamos prontos para interoperabilidade com a biblioteca nativa:

  1. Execute dotnet build a partir de template/android/NewBinding.Android.Binding para testar se tudo está conectado corretamente e pronto para funcionar. (Observação: esta etapa exigirá que você tenha o JDK 17 instalado)
  2. Faça referência a quaisquer dependências de vinculação do Android adicionando o seguinte código a template/sample/MauiSample.csproj para cada dependência. Substitua {yourDependencyLibrary.aar} pelo arquivo .aar necessário para a dependência que você está vinculando. (Observação: as dependências do gradle/maven geralmente precisam ser referenciadas explicitamente, pois não são agrupadas automaticamente em sua biblioteca. O arquivo build.gradle.kts é configurado para copiar as dependências em uma pasta bin/outputs/deps para que você faça referência a elas em seu aplicativo)
<ItemGroup Condition="$(TargetFramework.Contains('android'))">
    <AndroidLibrary Include="..\android\native\newbinding\bin\Release\net8.0-android\outputs\deps\{yourDependencyLibrary.aar}">
        <Bind>false</Bind>
        <Visible>false</Visible>
    </AndroidLibrary>
</ItemGroup>

Observação

Você pode renomear a classe do espaço reservado DotnetNewBinding para refletir melhor a biblioteca nativa que está sendo encapsulada. Para obter mais exemplos e dicas para escrever as definições de API, leia mais na seção abaixo: Modificar uma associação existente.

Consumir as APIs em seu aplicativo .NET

O modelo inclui um aplicativo de exemplo .NET MAUI em template/sample/MauiSample, que faz referência aos projetos de associação do .NET e torna as bibliotecas nativas imediatamente prontas para uso!

Se você estiver interessado em usar seus próprios aplicativos .NET MAUI, .NET para Android, .NET para iOS e/ou .NET para Mac Catalyst, no entanto, você pode fazer isso modificando os arquivos de projeto do aplicativo .NET para fazer referência às bibliotecas de associação:

<!-- 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>

Modificar uma associação existente

Se a superfície de API existente não expor a funcionalidade necessária em seu próprio projeto, é hora de fazer suas próprias modificações!

iOS e Mac Catalyst

Dentro do projeto do Xcode, você encontrará um ou mais arquivos Swift que definem a superfície da API pública para a associação. Por exemplo, o método register para o Firebase Messaging é definido 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?)
        })
    }
    // ...
}

Observação

Os tipos de API de wrapper nativa que serão usados pela Associação .NET devem ser declarados como public e precisam ser anotados com @objc(NameOfType), e os métodos também precisam ser publice também podem se beneficiar de anotações @objc(methodName:parameter1:) semelhantes em que o nome e os parâmetros são especificados, o que ajuda a influenciar a associação que o objective sharpie gerará.

Você pode ver neste método que a superfície da API pública usa apenas tipos que o .NET para iOS já está ciente: NSData, String, NSError e um retorno de chamada.

No projeto Firebase.MaciOS.Binding, o arquivo ApiDefinitions.cs contém a definição de associação para esta API de wrapper nativa:

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

Digamos que você queira adicionar um método para cancelar o registro. O código Swift seria semelhante a isto:

@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?)
    })
}

A outra metade será atualizar o arquivo ApiDefinitions.cs no projeto de associação para expor esse novo método. Há duas formas de fazer isso:

  1. Você pode adicionar manualmente o código necessário
  2. Quando o projeto de associação é compilado, o sharpie objetivo é executado e um arquivo ApiDefinitions.cs é gerado dentro da pasta native/macios/bin/sharpie (esse caminho variará com base no projeto em que você está trabalhando). Você pode tentar encontrar as alterações relevantes desse arquivo e copiá-las manualmente ou tentar copiar todo o arquivo e examinar a diferença para encontrar a parte necessária.

Nesse caso, as alterações no ApiDefinitions.cs seriam:

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

Depois de fazer essas alterações, você poderá recompilar o projeto de associação, e a nova API estará pronta para uso do seu projeto .NET MAUI.

Observação

Os projetos de associação para Mac/iOS não estão usando geradores de origem e, portanto, o sistema de projetos e o intellisense podem não saber sobre as novas API até que você tenha recriado o projeto de associação e recarregado a solução para que a referência do projeto pegue o assembly mais recente. Seu projeto de aplicativo ainda deve ser compilado independentemente dos erros do intellisense.

Android

Dentro do projeto do Android Studio, você encontrará um diretório de módulo que contém um arquivo java definindo a superfície da API pública para a associação. Por exemplo, o método initialize para o Facebook é definido como:

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

    // ...
}

Você pode ver neste método que a superfície da API pública usa apenas tipos que o .NET para Android já está ciente: Activity e Boolean.

No projeto Facebook.Android.Binding, o arquivo Transforms/Metadata.xml contém apenas alguns xml para descrever como mapear o nome do pacote java (com.microsoft.mauifacebook) para um namespace mais amigável em C# (Facebook). Geralmente, as associações android são mais “automáticas” do que o Mac/iOS neste momento, e você raramente deve precisar fazer alterações nesses arquivos de transformação.

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

Digamos que você queira adicionar um método para registrar um evento em log. O código java seria semelhante a isto:

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

Com essa alteração simples, o projeto de associação não requer atualizações para o Transforms/Metadata.xml ou outros arquivos. Basta você recompilar o projeto de associação, e a nova API estará pronta para uso do seu projeto .NET MAUI.

Observação

Os projetos de associação para Android não estão usando geradores de origem e, portanto, o sistema de projetos e o intellisense podem não saber sobre as novas API até que você tenha recriado o projeto de associação e recarregado a solução para que a referência do projeto pegue o assembly mais recente. Seu projeto de aplicativo ainda deve ser compilado independentemente dos erros do intellisense.