Compartilhar via


Referenciando bibliotecas nativas no Xamarin.iOS

O Xamarin.iOS dá suporte à vinculação com bibliotecas e Objective-C bibliotecas C nativas. Este documento discute como vincular suas bibliotecas C nativas ao seu projeto Xamarin.iOS. Para obter informações sobre como fazer o mesmo para Objective-C bibliotecas, consulte nosso documento Tipos de AssociaçãoObjective-C.

Criando bibliotecas nativas universais (i386, ARMv7 e ARM64)

Geralmente, é desejável criar suas bibliotecas nativas para cada uma das plataformas com suporte para desenvolvimento do iOS (i386 para o Simulador e ARMv7/ARM64 para os próprios dispositivos). Se você já tem um projeto Xcode para sua biblioteca, isso é realmente trivial de se fazer.

Para criar a versão i386 da biblioteca nativa, execute o seguinte comando em um terminal:

/Developer/usr/bin/xcodebuild -project MyProject.xcodeproj -target MyLibrary -sdk iphonesimulator -arch i386 -configuration Release clean build

Isso resultará em uma biblioteca MyProject.xcodeproj/build/Release-iphonesimulator/estática nativa em . Copie (ou mova) o arquivo de arquivo de biblioteca (libMyLibrary.a) para um lugar seguro para uso posterior, dando a ele um nome exclusivo (como libMyLibrary-i386.a) para que ele não entre em conflito com as versões arm64 e armv7 da mesma biblioteca que você criará em seguida.

Para criar a versão ARM64 da biblioteca nativa, execute o seguinte comando:

/Developer/usr/bin/xcodebuild -project MyProject.xcodeproj -target MyLibrary -sdk iphoneos -arch arm64 -configuration Release clean build

Desta vez, a biblioteca nativa criada estará localizada em MyProject.xcodeproj/build/Release-iphoneos/. Mais uma vez, copie (ou mova) esse arquivo para um local seguro, renomeando-o para algo como libMyLibrary-arm64.a para que ele não entre em conflito.

Agora, crie a versão ARMv7 da biblioteca:

/Developer/usr/bin/xcodebuild -project MyProject.xcodeproj -target MyLibrary -sdk iphoneos -arch armv7 -configuration Release clean build

Copie (ou mova) o arquivo de biblioteca resultante para o mesmo local em que você moveu as outras duas versões da biblioteca, renomeando-o para algo como libMyLibrary-armv7.a.

Para tornar um binário universal, você pode usar a lipo ferramenta da seguinte maneira:

lipo -create -output libMyLibrary.a libMyLibrary-i386.a libMyLibrary-arm64.a libMyLibrary-armv7.a

Isso cria libMyLibrary.a uma biblioteca universal (fat) que será adequada para uso para todos os destinos de desenvolvimento do iOS.

Arquitetura necessária ausente i386

Se você estiver recebendo uma does not implement methodSignatureForSelector mensagem ou does not implement doesNotRecognizeSelector na saída do runtime ao tentar consumir uma Objective-C biblioteca no Simulador do iOS, sua biblioteca provavelmente não foi compilada para a arquitetura i386 (consulte a seção Criando bibliotecas nativas universais acima).

Para marcar as arquiteturas compatíveis com uma determinada biblioteca, use o seguinte comando no Terminal:

lipo -info /full/path/to/libraryname.a

Onde /full/path/to/ é o caminho completo para a biblioteca que está sendo consumida e libraryname.a é o nome da biblioteca em questão.

Se você tiver a origem na biblioteca, precisará compilá-la e emcompocioná-la para a arquitetura i386 também, se quiser testar seu aplicativo no simulador do iOS.

Vinculando sua biblioteca

Qualquer biblioteca de terceiros que você consome precisa estar vinculada estaticamente ao seu aplicativo.

Se você quisesse vincular estaticamente a biblioteca "libMyLibrary.a" que você obteve da Internet ou compilar com o Xcode, precisaria fazer algumas coisas:

  • Colocar a Biblioteca em seu projeto
  • Configurar o Xamarin.iOS para vincular a biblioteca
  • Acesse os métodos da biblioteca.

Para colocar a biblioteca em seu projeto, selecione o projeto no gerenciador de soluções e pressione Command+Option+a. Navegue até o libMyLibrary.a e adicione-o ao projeto. Quando solicitado, diga ao Visual Studio para Mac ou ao Visual Studio para copiá-lo para o projeto. Depois de adicioná-lo, localize o libFoo.a no projeto, clique com o botão direito do mouse nele e defina a Ação de Build como nenhuma.

Para configurar o Xamarin.iOS para vincular a biblioteca, nas opções de projeto para o executável final (não a biblioteca em si, mas o programa final), você precisa adicionar no argumento Extra do Build do iOS (eles fazem parte das opções de projeto) a opção "-gcc_flags" seguida por uma cadeia de caracteres entre aspas que contém todas as bibliotecas extras necessárias para o programa, por exemplo:

-gcc_flags "-L$(MSBuildProjectDirectory) -lMylibrary -force_load $(MSBuildProjectDirectory)/libMyLibrary.a"

O exemplo acima vinculará libMyLibrary.a

Você pode usar -gcc_flags para especificar qualquer conjunto de argumentos de linha de comando para passar para o compilador GCC usado para fazer o link final do executável. Por exemplo, essa linha de comando também faz referência à estrutura CFNetwork:

-gcc_flags "-L$(MSBuildProjectDirectory) -lMylibrary -lSystemLibrary -framework CFNetwork -force_load $(MSBuildProjectDirectory)/libMyLibrary.a"

Se sua biblioteca nativa contiver código C++, você também deverá passar o sinalizador -cxx em seus "Argumentos Extras" para que o Xamarin.iOS saiba usar o compilador correto. Para C++, as opções anteriores seriam semelhantes a:

-cxx -gcc_flags "-L$(MSBuildProjectDirectory) -lMylibrary -lSystemLibrary -framework CFNetwork -force_load $(MSBuildProjectDirectory)/libMyLibrary.a"

Acessando métodos C a partir de C#

Há dois tipos de bibliotecas nativas disponíveis no iOS:

  • Bibliotecas compartilhadas que fazem parte do sistema operacional.

  • Bibliotecas estáticas que você envia com seu aplicativo.

Para acessar métodos definidos em qualquer um deles, use a funcionalidade P/Invoke do Mono , que é a mesma tecnologia que você usaria no .NET, que é aproximadamente:

  • Determinar qual função C você deseja invocar
  • Determinar sua assinatura
  • Determinar em qual biblioteca ela reside
  • Gravar a declaração P/Invoke apropriada

Ao usar P/Invoke, você precisa especificar o caminho da biblioteca com a qual você está vinculando. Ao usar bibliotecas compartilhadas do iOS, você pode codificar o caminho ou usar as constantes de conveniência que definimos em nosso Constants, essas constantes devem abranger as bibliotecas compartilhadas do iOS.

Por exemplo, se você quiser invocar o método UIRectFrameUsingBlendMode da biblioteca UIKit da Apple, que tem essa assinatura em C:

void UIRectFrameUsingBlendMode (CGRect rect, CGBlendMode mode);

Sua declaração P/Invoke teria esta aparência:

[DllImport (Constants.UIKitLibrary,EntryPoint="UIRectFrameUsingBlendMode")]
public extern static void RectFrameUsingBlendMode (RectangleF rect, CGBlendMode blendMode);

Constants.UIKitLibrary é apenas uma constante definida como "/System/Library/Frameworks/UIKit.framework/UIKit", o EntryPoint permite especificar opcionalmente o nome externo (UIRectFramUsingBlendMode) ao expor um nome diferente em C#, o rectFrameUsingBlendMode mais curto.

Acessando C Dylibs

Se você tiver a necessidade de consumir um Dylib C em seu aplicativo Xamarin.iOS, haverá uma configuração extra necessária antes de chamar o DllImport atributo.

Por exemplo, se tivermos um Animal.dylib com um Animal_Version método que chamaremos em nosso aplicativo, precisaremos informar o Xamarin.iOS sobre a localização da biblioteca antes de tentar consumi-la.

Para fazer isso, edite o Main.CS arquivo e faça com que ele se pareça com o seguinte:

static void Main (string[] args)
{
    // Load Dylib
    MonoTouch.ObjCRuntime.Dlfcn.dlopen ("/full/path/to/Animal.dylib", 0);

    // Start application
    UIApplication.Main (args, null, "AppDelegate");
}

Onde /full/path/to/ é o caminho completo para o Dylib que está sendo consumido. Com esse código em vigor, podemos vincular ao método da Animal_Version seguinte maneira:

[DllImport("Animal.dylib", EntryPoint="Animal_Version")]
public static extern double AnimalLibraryVersion();

Bibliotecas estáticas

Como você só pode usar bibliotecas estáticas no iOS, não há biblioteca compartilhada externa para vincular, portanto, o parâmetro path no atributo DllImport precisa usar o nome __Internal especial (observe os caracteres de sublinhado duplo no início do nome) em vez do nome do caminho.

Isso força dllImport a pesquisar o símbolo do método que você está referenciando no programa atual, em vez de tentar carregá-lo de uma biblioteca compartilhada.