Demonstra Passo a passo: Vincular uma biblioteca Swift do iOS
Importante
No momento, estamos investigando o uso de vinculação personalizada na plataforma Xamarin. Por favor, faça esta pesquisa para informar os futuros esforços de desenvolvimento.
O Xamarin permite que os desenvolvedores móveis criem experiências móveis nativas de plataforma cruzada usando Visual Studio e C#. Você pode usar os componentes do SDK da plataforma iOS prontos para uso. Mas, em muitos casos, você também deseja usar SDKs de terceiros desenvolvidos para essa plataforma, o que o Xamarin permite que você faça por meio de associações. Para incorporar uma estrutura de terceiros em seu aplicativo Xamarin.iOS, você precisa criar uma associação Xamarin.iOS para ele antes de poder usá-lo Objective-C em seus aplicativos.
A plataforma iOS, juntamente com suas linguagens e ferramentas nativas, estão em constante evolução e o Swift é uma das áreas mais dinâmicas no mundo do desenvolvimento iOS no momento. Há uma série de SDKs de terceiros, que já foram migrados do Objective-C Swift e isso nos apresenta novos desafios. Embora o processo de vinculação do Swift seja semelhante ao Objective-C, ele requer etapas adicionais e definições de configuração para criar e executar com êxito um aplicativo Xamarin.iOS que seja aceitável para a AppStore.
O objetivo deste documento é descrever uma abordagem de alto nível para lidar com esse cenário e fornecer um guia passo a passo detalhado com um exemplo simples.
Tela de fundo
O Swift foi inicialmente introduzido pela Apple em 2014 e agora está na versão 5.1, com a adoção por estruturas de terceiros crescendo rapidamente. Você tem algumas opções para vincular uma estrutura Swift e este documento descreve a abordagem usando Objective-C o cabeçalho de interface gerado. O cabeçalho é criado automaticamente pelas ferramentas Xcode quando uma estrutura é criada, e é usado como uma maneira de se comunicar do mundo gerenciado para o mundo Swift.
Pré-requisitos
Para concluir este passo a passo, você precisa:
- Xcode
- Visual Studio para Mac
- Objective Sharpie
- CLI do AppCenter (opcional)
Criar uma biblioteca nativa
A primeira etapa é criar um Swift Framework nativo com Objective-C cabeçalho habilitado. A estrutura geralmente é fornecida por um desenvolvedor de terceiros e tem o cabeçalho incorporado ao pacote no seguinte diretório: FrameworkName.framework/Headers/<FrameworkName-Swift.h>>.<
Esse cabeçalho expõe as interfaces públicas, que serão usadas para criar metadados de vinculação Xamarin.iOS e gerar classes C# expondo os membros da estrutura Swift. Se o cabeçalho não existir ou tiver uma interface pública incompleta (por exemplo, você não vê classes/membros), você tem duas opções:
- Atualize o código-fonte do Swift para gerar o cabeçalho e marcar os membros necessários com
@objc
o atributo - Crie uma estrutura de proxy onde você controla a interface pública e proxy todas as chamadas para a estrutura subjacente
Neste tutorial, a segunda abordagem é descrita, pois tem menos dependências do código-fonte de terceiros, que nem sempre está disponível. Outra razão para evitar a primeira abordagem é o esforço adicional necessário para apoiar futuras mudanças de estrutura. Depois de começar a adicionar alterações ao código-fonte de terceiros, você é responsável por dar suporte a essas alterações e, potencialmente, mesclá-las com cada atualização futura.
Como exemplo, neste tutorial é criada uma associação para o SDK do Gigya Swift:
Abra o Xcode e crie uma nova estrutura Swift, que será um proxy entre o código Xamarin.iOS e a estrutura Swift de terceiros. Clique em Arquivo > Novo > Projeto e siga as etapas do assistente:
Baixe o Gigya xcframework do site do desenvolvedor e descompacte-o. No momento em que este artigo foi escrito, a versão mais recente é Gigya Swift SDK 1.5.3
Selecione o SwiftFrameworkProxy no explorador de arquivos do projeto e, em seguida, selecione a guia Geral
Arraste e solte o pacote Gigya.xcframework na lista Frameworks e bibliotecas do Xcode na guia Geral, marque a opção Copiar itens, se necessário, ao adicionar a estrutura:
Verifique se a estrutura Swift foi adicionada ao projeto, caso contrário, as opções a seguir não estarão disponíveis.
Certifique-se de que a opção Não incorporar esteja selecionada, que será posteriormente controlada manualmente:
Certifique-se de que a opção Configurações de compilação Sempre incorporar bibliotecas padrão Swift, que inclui bibliotecas Swift com a estrutura, esteja definida como Não. Mais tarde, ele será controlado manualmente, que dylibs Swift são incluídos no pacote final:
Certifique-se de que a opção Ativar código de bits esteja definida como Não. A partir de agora, o Xamarin.iOS não inclui Bitcode, enquanto a Apple exige que todas as bibliotecas suportem as mesmas arquiteturas:
Você pode verificar se a estrutura resultante tem a opção Bitcode desabilitada executando o seguinte comando de terminal na estrutura:
otool -l SwiftFrameworkProxy.framework/SwiftFrameworkProxy | grep __LLVM
A saída deve estar vazia, caso contrário, você deseja revisar as configurações do projeto para sua configuração específica.
Verifique se a opção Nome do cabeçalho da interface gerada está habilitada Objective-C e especifica um nome de cabeçalho. O nome padrão é FrameworkName-Swift.h>:<
Dica
Se essa opção não estiver disponível, primeiro certifique-se de adicionar um
.swift
arquivo ao projeto conforme explicado abaixo, depois retorne aoBuild Settings
e a configuração deve ser detectável.Exponha os métodos desejados e marque-os com o
@objc
atributo e aplique regras adicionais definidas abaixo. Se você criar a estrutura sem essa etapa, o cabeçalho gerado Objective-C estará vazio e o Xamarin.iOS não poderá acessar os membros da estrutura Swift. Exponha a lógica de inicialização para o SDK Gigya Swift subjacente criando um novo arquivo Swift SwiftFrameworkProxy.swift e definindo o seguinte código:import Foundation import UIKit import Gigya @objc(SwiftFrameworkProxy) public class SwiftFrameworkProxy : NSObject { @objc public func initFor(apiKey: String) -> String { Gigya.sharedInstance().initFor(apiKey: apiKey) let gigyaDomain = Gigya.sharedInstance().config.apiDomain let result = "Gigya initialized with domain: \(gigyaDomain)" return result } }
Algumas observações importantes sobre o código acima:
- Importar o
Gigya
módulo aqui do SDK Gigya original de terceiros permite o acesso a qualquer membro da estrutura. - Marque a classe SwiftFrameworkProxy com o
@objc
atributo especificando um nome, caso contrário, um nome ilegível exclusivo será gerado, como_TtC19SwiftFrameworkProxy19SwiftFrameworkProxy
. O nome do tipo deve ser claramente definido porque será usado posteriormente por seu nome. - Herde a classe proxy do , caso contrário, ela não será gerada no Objective-C arquivo de
NSObject
cabeçalho. - Marque todos os membros a serem expostos como
public
.
- Importar o
Altere a configuração de compilação do esquema de Debug para Release. Para fazer isso, abra a caixa de diálogo Xcode > Target > Edit Scheme e defina a opção Build Configuration como Release:
Neste ponto, o Framework está pronto para ser criado. Crie a estrutura para as arquiteturas de simulador e dispositivo e, em seguida, combine as saídas como um único pacote de estrutura binária (
.xcframework
). Execute a compilação com os seguintes comandos:xcodebuild -project "Swift/SwiftFrameworkProxy/SwiftFrameworkProxy.xcodeproj" archive \ -scheme "SwiftFrameworkProxy" \ -configuration Release \ -archivePath "build/SwiftFrameworkProxy-simulator.xcarchive" \ -destination "generic/platform=iOS Simulator" \ -derivedDataPath "build" \ -IDECustomBuildProductsPath="" -IDECustomBuildIntermediatesPath="" \ ENABLE_BITCODE=NO \ SKIP_INSTALL=NO \ BUILD_LIBRARY_FOR_DISTRIBUTION=YES
xcodebuild -project "Swift/SwiftFrameworkProxy/SwiftFrameworkProxy.xcodeproj" archive \ -scheme "SwiftFrameworkProxy" \ -configuration Release \ -archivePath "build/SwiftFrameworkProxy-ios.xcarchive" \ -destination "generic/platform=iOS" \ -derivedDataPath "build" \ -IDECustomBuildProductsPath="" -IDECustomBuildIntermediatesPath="" \ ENABLE_BITCODE=NO \ SKIP_INSTALL=NO \ BUILD_LIBRARY_FOR_DISTRIBUTION=YES
Dica
Se você tiver um espaço de trabalho em vez de projeto, crie o espaço de trabalho e especifique o destino como um parâmetro necessário. Você também deseja especificar um diretório de saída porque para espaços de trabalho esse diretório será diferente do que para compilações de projeto.
Dica
Você também pode usar o script auxiliar para criar a estrutura para todas as arquiteturas aplicáveis ou apenas compilá-la a partir do Simulador de comutação Xcode e do dispositivo no seletor de destino.
Há dois arquivos com as estruturas geradas, um para cada plataforma, combiná-los como um único pacote de estrutura binária para ser incorporado em um projeto de vinculação Xamarin.iOS mais tarde. Para criar um pacote de estrutura binário, que combina ambas as arquiteturas, você precisa fazer as seguintes etapas. O pacote .xcarchive é apenas uma pasta para que você possa fazer todos os tipos de operações, como adicionar, remover e substituir arquivos:
Crie um
xcframework
com as estruturas criadas anteriormente nos arquivos:xcodebuild -create-xcframework \ -framework "build/SwiftFrameworkProxy-simulator.xcarchive/Products/Library/Frameworks/SwiftFrameworkProxy.framework" \ -framework "build/SwiftFrameworkProxy-ios.xcarchive/Products/Library/Frameworks/SwiftFrameworkProxy.framework" \ -output "build/SwiftFrameworkProxy.xcframework"
Dica
Se você quiser oferecer suporte a apenas uma única plataforma (por exemplo, você está criando um aplicativo, que pode ser executado apenas em um dispositivo), você pode ignorar a etapa para criar a biblioteca .xcframework e usar a estrutura de saída da compilação do dispositivo anteriormente.
Dica
Você também pode usar o script auxiliar para criar o .xcframework, que automatiza todas as etapas acima.
Preparar metadados
Neste momento, você deve ter o .xcframework com o cabeçalho de interface gerado pronto para ser consumido Objective-C por uma associação Xamarin.iOS. A próxima etapa é preparar as interfaces de definição de API, que são usadas por um projeto de vinculação para gerar classes C#. Essas definições podem ser criadas manualmente ou automaticamente pela ferramenta Objective Sharpie e pelo arquivo de cabeçalho gerado. Use Sharpie para gerar os metadados:
Baixe a ferramenta Objective Sharpie mais recente do site oficial de downloads e instale-a seguindo o assistente. Depois que a instalação for concluída, você poderá verificá-la executando o comando sharpie:
sharpie -v
Gere metadados usando sharpie e o arquivo de cabeçalho gerado Objective-C automaticamente:
sharpie bind --sdk=iphoneos16.4 --output="XamarinApiDef" --namespace="Binding" --scope="build/SwiftFrameworkProxy.xcframework/ios-arm64/SwiftFrameworkProxy.framework/Headers/" "build/SwiftFrameworkProxy.xcframework/ios-arm64/SwiftFrameworkProxy.framework/Headers/SwiftFrameworkProxy-Swift.h"
A saída reflete o arquivo de metadados que está sendo gerado: ApiDefinitions.cs. Salve este arquivo na próxima etapa para incluí-lo em um projeto de vinculação Xamarin.iOS junto com as referências nativas:
Parsing 1 header files... Binding... [write] ApiDefinitions.cs
A ferramenta gerará metadados C# para cada membro exposto, que serão semelhantes ao código a Objective-C seguir. Como você pode ver, ele pode ser definido manualmente porque tem um formato legível por humanos e mapeamento de membros direto:
[Export ("initForApiKey:")] string InitForApiKey (string apiKey);
Dica
O nome do arquivo de cabeçalho pode ser diferente se você alterou as configurações padrão do Xcode para o nome do cabeçalho. Por padrão, ele tem o nome de um projeto com o sufixo -Swift . Você sempre pode verificar o arquivo e seu nome navegando até a pasta de cabeçalhos do pacote de estrutura.
Dica
Como parte do processo de automação, você pode usar o script auxiliar para gerar metadados automaticamente depois que o .xcframework for criado.
Criar uma biblioteca de vinculação
A próxima etapa é criar um projeto de vinculação Xamarin.iOS usando o modelo de associação do Visual Studio, adicionar metadados necessários, referências nativas e, em seguida, compilar o projeto para produzir uma biblioteca consumível:
Abra o Visual Studio para Mac e crie um novo projeto de biblioteca de vinculação Xamarin.iOS, dê um nome, neste caso SwiftFrameworkProxy.Binding e conclua o assistente. O modelo de vinculação Xamarin.iOS está localizado pelo seguinte caminho: Biblioteca de vinculação da biblioteca > do iOS>:
Exclua o arquivo de metadados existente ApiDefinition.cs pois ele será substituído completamente pelos metadados gerados pela ferramenta Objective Sharpie.
Copie os metadados gerados pelo Sharpie em uma das etapas anteriores, selecione a seguinte Ação de compilação na janela de propriedades: ObjBindingApiDefinition para o arquivo ApiDefinitions.cs e ObjBindingCoreSource para o arquivo StructsAndEnums.cs:
Os metadados em si descrevem cada classe exposta Objective-C e membro usando a linguagem C#. Você pode ver a definição de cabeçalho original Objective-C junto com a declaração C#:
// @interface SwiftFrameworkProxy : NSObject [BaseType (typeof(NSObject))] interface SwiftFrameworkProxy { // -(NSString * _Nonnull)initForApiKey:(NSString * _Nonnull)apiKey __attribute__((objc_method_family("none"))) __attribute__((warn_unused_result)); [Export ("initForApiKey:")] string InitForApiKey (string apiKey); }
Mesmo que seja um código C# válido, ele não é usado como está, mas é usado pelas ferramentas Xamarin.iOS para gerar classes C# com base nessa definição de metadados. Como resultado, em vez da interface SwiftFrameworkProxy, você obtém uma classe C# com o mesmo nome, que pode ser instanciada pelo seu código Xamarin.iOS. Essa classe obtém métodos, propriedades e outros membros definidos por seus metadados, que você chamará de maneira C#.
Adicione uma referência nativa ao pacote de estrutura binário gerado anteriormente, bem como a cada dependência dessa estrutura. Nesse caso, adicione referências nativas do SwiftFrameworkProxy e do framework Gigya ao projeto de vinculação:
- Para adicionar referências de estrutura nativa, abra o localizador e navegue até a pasta com as estruturas. Arraste e solte as estruturas no local Referências Nativas no Gerenciador de Soluções. Como alternativa, você pode usar a opção de menu de contexto na pasta Referências Nativas e clicar em Adicionar Referência Nativa para procurar as estruturas e adicioná-las:
Atualize as propriedades de cada referência nativa e verifique três opções importantes:
- Definir Smart Link = true
- Definir Force Load = false
- Definir lista de Frameworks usados para criar os frameworks originais. Nesse caso, cada framework tem apenas duas dependências: Foundation e UIKit. Defina-o para o campo Estruturas:
Se você tiver sinalizadores de vinculador adicionais para especificar, defina-os no campo sinalizadores de vinculador. Neste caso, mantenha-o vazio.
Especifique sinalizadores de vinculador adicionais quando necessário. Se a biblioteca que você está vinculando expor apenas Objective-C APIs, mas internamente estiver usando o Swift, talvez você esteja vendo problemas como:
error MT5209 : Native linking error : warning: Auto-Linking library not found for -lswiftCore error MT5209 : Native linking error : warning: Auto-Linking library not found for -lswiftQuartzCore error MT5209 : Native linking error : warning: Auto-Linking library not found for -lswiftCoreImage
Nas propriedades do projeto de vinculação para a biblioteca nativa, os seguintes valores devem ser adicionados aos sinalizadores de vinculador:
L/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator/ -L/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos -Wl,-rpath -Wl,@executable_path/Frameworks
As duas primeiras opções (as únicas) dizem ao compilador nativo onde encontrar as
-L ...
bibliotecas swift. O compilador nativo ignorará bibliotecas que não têm a arquitetura correta, o que significa que é possível passar o local para bibliotecas de simuladores e bibliotecas de dispositivos ao mesmo tempo, para que funcione tanto para compilações de simuladores quanto de dispositivos (esses caminhos são corretos apenas para iOS; para tvOS e watchOS eles precisam ser atualizados). Uma desvantagem é que essa abordagem requer que o Xcode correto esteja em /Application/Xcode.app, se o consumidor da biblioteca de vinculação tiver o Xcode em um local diferente, ele não funcionará. A solução alternativa é adicionar essas opções nos argumentos mtouch adicionais nas opções de compilação do iOS do projeto executável (--gcc_flags -L... -L...
). A terceira opção faz com que o vinculador nativo armazene a localização das bibliotecas swift no executável, para que o sistema operacional possa encontrá-las.
A ação final é criar a biblioteca e garantir que você não tenha erros de compilação. Você geralmente descobrirá que os metadados de vinculação produzidos pelo Objective Sharpie serão anotados com o
[Verify]
atributo. Esses atributos indicam que você deve verificar se a Objective Sharpie fez a coisa correta, comparando a vinculação com a declaração original Objective-C (que será fornecida em um comentário acima da declaração vinculada). Você pode saber mais sobre os membros marcados com o atributo no link a seguir. Uma vez que o projeto é construído, ele pode ser consumido por um aplicativo Xamarin.iOS.
Consumir a biblioteca de vinculação
A etapa final é consumir a biblioteca de vinculação Xamarin.iOS em um aplicativo Xamarin.iOS. Crie um novo projeto Xamarin.iOS, adicione referência à biblioteca de vinculação e ative o SDK do Gigya Swift:
Crie o projeto Xamarin.iOS. Você pode usar o aplicativo > iOS > Single View App como ponto de partida:
Adicione uma referência de projeto de vinculação ao projeto de destino ou .dll criado anteriormente. Trate a biblioteca de vinculação como uma biblioteca Xamarin.iOS regular:
Atualize o código-fonte do aplicativo e adicione a lógica de inicialização ao ViewController primário, que ativa o SDK do Gigya
public override void ViewDidLoad() { base.ViewDidLoad(); var proxy = new SwiftFrameworkProxy(); var result = proxy.InitForApiKey("APIKey"); System.Diagnostics.Debug.WriteLine(result); }
Crie um botão com um nome btnLogin e adicione o seguinte manipulador de clique de botão para ativar um fluxo de autenticação:
private void btnLogin_Tap(object sender, EventArgs e) { _proxy.LoginWithProvider(GigyaSocialProvidersProxy.Instagram, this, (result, error) => { // process your login result here }); }
Execute o aplicativo, na saída de depuração você deve ver a seguinte linha:
Gigya initialized with domain: us1.gigya.com
. Clique no botão para ativar o fluxo de autenticação:
Parabéns! Você criou com êxito um aplicativo Xamarin.iOS e uma biblioteca de vinculação, que consome uma estrutura Swift. O aplicativo acima será executado com sucesso no iOS 12.2+ porque a partir desta versão do iOS a Apple introduziu a estabilidade ABI e todo iOS a partir do 12.2+ inclui bibliotecas de tempo de execução Swift, que podem ser usadas para executar seu aplicativo compilado com o Swift 5.1+. Se você precisar adicionar suporte para versões anteriores do iOS, há mais algumas etapas a serem realizadas:
Para adicionar suporte para iOS 12.1 e versões anteriores, você deseja enviar dylibs Swift específicos usados para compilar sua estrutura. Use o pacote NuGet Xamarin.iOS.SwiftRuntimeSupport para processar e copiar as bibliotecas necessárias com seu IPA. Adicione a referência NuGet ao seu projeto de destino e recrie o aplicativo. Nenhuma etapa adicional é necessária, o pacote NuGet instalará tarefas específicas, que são executadas com o processo de compilação, identificará dylibs Swift necessários e os empacotará com o IPA final.
Para enviar o aplicativo para a loja de aplicativos, você deseja usar o Xcode e distribuir opção, que irá atualizar o arquivo IPA e dylibs pasta SwiftSupport para que ele será aceito pela AppStore:
○ Arquive o aplicativo. No menu Visual Studio para Mac, selecione Build > Archive for Publishing:
Essa ação cria o projeto e o alcança para o Organizador, que é acessível pelo Xcode para distribuição.
○ Distribua via Xcode. Abra o Xcode e navegue até a opção de menu do Organizador de Janelas>:
Selecione o arquivo criado na etapa anterior e clique no botão Distribuir aplicativo. Siga o assistente para carregar o aplicativo na AppStore.
Esta etapa é opcional, mas é importante verificar se seu aplicativo pode ser executado no iOS 12.1 e versões anteriores, bem como no 12.2. Você pode fazer isso com a ajuda do Test Cloud e do framework UITest. Crie um projeto UITest e um teste básico de interface do usuário, que executa o aplicativo:
Crie um projeto UITest e configure-o para seu aplicativo Xamarin.iOS:
Dica
Você pode encontrar mais informações sobre como criar um projeto UITest e configurá-lo para seu aplicativo no link a seguir.
Crie um teste básico para executar o aplicativo e use alguns dos recursos do SDK do Swift. Este teste ativa o aplicativo, tenta fazer login e pressiona o botão cancelar:
[Test] public void HappyPath() { app.WaitForElement(StatusLabel); app.WaitForElement(LoginButton); app.Screenshot("App loaded."); Assert.AreEqual(app.Query(StatusLabel).FirstOrDefault().Text, "Gigya initialized with domain: us1.gigya.com"); app.Tap(LoginButton); app.WaitForElement(GigyaWebView); app.Screenshot("Login activated."); app.Tap(CancelButton); app.WaitForElement(LoginButton); app.Screenshot("Login cancelled."); }
Dica
Leia mais sobre a estrutura UITests e a Automação da Interface do Usuário no link a seguir.
Crie um aplicativo iOS no centro de aplicativos, crie uma nova execução de teste com um novo dispositivo definido para executar o teste:
Dica
Saiba mais sobre o AppCenter Test Cloud no link a seguir.
Instalar a CLI do appcenter
npm install -g appcenter-cli
Importante
Verifique se você tem o nó v6.3 ou posterior instalado
Execute o teste usando o seguinte comando. Verifique também se a linha de comando do appcenter está conectada no momento.
appcenter test run uitest --app "Mobile-Customer-Advisory-Team/SwiftBinding.iOS" --devices a7e7cb50 --app-path "Xamarin.SingleView.ipa" --test-series "master" --locale "en_US" --build-dir "Xamarin/Xamarin.SingleView.UITests/bin/Debug/"
Verifique o resultado. No portal do AppCenter, navegue até as execuções do Teste de Aplicativo > >:
E selecione a execução de teste desejada e verifique o resultado:
Você desenvolveu um aplicativo Xamarin.iOS básico que usa uma estrutura Swift nativa por meio de uma biblioteca de vinculação Xamarin.iOS. O exemplo fornece uma maneira simplista de usar a estrutura selecionada e, em aplicativos reais, você precisará expor mais APIs e preparar metadados para essas APIs. O script para gerar metadados simplificará as alterações futuras nas APIs da estrutura.
Links relacionados
- Xcode
- Visual Studio para Mac
- Objective Sharpie
- Verificação de metadados Sharpie
- Quadro de vinculação Objective-C
- Gigya iOS SDK (estrutura Swift)
- Estabilidade ABI Swift 5.1
- SwiftRuntimeSupport NuGet
- Automação do Xamarin UITest
- Configuração do Xamarin.iOS UITest
- Nuvem de teste do AppCenter
- Repositório de projeto de exemplo