Partilhar 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 dependencyResolutionManagementrepositories 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.
  2. Use o sharpie objetivo para gerar as associações C# para suas atualizações de API Swift:
    1. Navegue até template/macios/NewBinding.MaciOS.Binding/bin/Debug/net9.0-ios/NewBinding.MaciOS.Binding.resources/NewBindingiOS.xcframework/ios-arm64/NewBinding.framework na pasta de saída de projetos de associação MaciOS.
    2. Execute sharpie xcode -sdks para obter uma lista de valores válidos do SDK de destino para o comando bind. Selecione o valor que se alinha à plataforma e à versão que você pretende usar com o próximo comando, por exemplo, iphoneos18.0.
    3. Execute sharpie bind nos arquivos de cabeçalho no xcframework criado pelo projeto de vinculação:
      sharpie bind --output=sharpie-out --namespace=NewBindingMaciOS --sdk=iphoneos18.0 --scope=Headers Headers/NewBinding-Swift.h
      
    4. Atualize o conteúdo de template/macios/NewBinding.MaciOS.Binding/ApiDefinition.cs, substituindo pelo conteúdo 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 e faça ajustes conforme desejado (por exemplo, nomenclatura).
    5. Execute dotnet build de template/macios/NewBinding.MaciOS.Binding novamente.

Consulte também a documentação objective-sharpie para aprender mais sobre essa ferramenta.

Definição da API: Android

Na parte nativa, faça atualizações em template/android/native/newbinding/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 um @(AndroidMavenLibrary) item ao template/sample/MauiSample.csproj para cada dependência maven que está sendo vinculada ao seu projeto Android nativo. Isso habilitará a verificação de dependência do Java para seu projeto e fará com que os builds subsequentes produzam avisos de build ou erros para dependências ausentes. Você pode resolver esses avisos/erros adicionando elementos @(AndroidMavenLibrary) ou @(PackageReference) conforme sugerido para atender à cadeia de dependência do Java para a biblioteca nativa à qual você está vinculando. (Observação: as dependências de gradle/maven geralmente precisam ser referenciadas explicitamente, pois elas não são agrupadas automaticamente em sua biblioteca.)
<ItemGroup Condition="$(TargetFramework.Contains('android'))">
    <AndroidMavenLibrary Include="{DependencyGroupId}:{DependencyName}" Version="{DependencyVersion}" Bind="false" />
</ItemGroup>

Consulte também a referência do AndroidMavenLibrary e a documentação de verificação de dependência Java para obter mais informações sobre esse processo.

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. Depois de criar o projeto de associação, você pode usar a ferramenta Objective Sharpie para gerar um arquivo ApiDefinitions.cs. 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.