Cocoapods: como trabalhar com dependências device-only
Essa semana tive que enfrentar um problema que eu já vinha postergando faz muito tempo.
Desde que a Apple lançou o seus primeiros MacBook com processadores M1 nós desenvolvedores tivemos que começar a pensar em frameworks para simulador com arquitetura arm64.
Isso foi praticamente a sentença de morte dos fat binaries uma vez que um binário não pode conter duas arquitetura iguais: uma arm64 para devices e uma arm64 pra simuladores.
Com isso começamos a trabalhar com Xcframeworks: um pacote contendo duas ou mais plataformas dentro de si.
Foi então que um novo problema surgiu: como linkar bibliotecas que são devices-only e contém arquitetura arm64 com simuladores usando cocoapods.
Antes da arquitetura arm64 pra simuladores, quando tentávamos linkar uma biblioteca device-only em um build para simulador, o Linker simplesmente ignorava a biblioteca, por ela não conter nenhuma arquitetura válida; gerava um warning e a vida seguia normalmente. Mas agora que a arquitetura arm64 passou a ser uma arquitetura válida para simulador, o linker, ao tentar linkar o build com a biblioteca device-only passou a exibir o seguinte erro:
Chegamos então a um problema: como informar ao cocoapods que a biblioteca que eu estou tentando importar deve ser utilizada apenas para Devices e não pra simuladores? Nós podemos especificar configurações para um Pod, mas não uma plataforma para uma configuração.
A solução: um podspec customizado
Criar um podspec customizado não é uma tarefa difícil, mas encontrar os parâmetros certos para a solução que você deseja pode ser um desafio.
Nesse caso, precisamos remover a biblioteca do vendored_frameworks:
Quando é especificada como um vendored framework, o Cocoapods já inclui a biblioteca em todo lugar onde ela se faz necessária, desde frameworks search paths até o próprio Linker.
Nesse caso, iremos fazer o processo na mão, uma vez que queremos uma configuração bastante específica.
Para que o Cocoapods baixe e mantenha nossa biblioteca como dependência, precisamos especificar um path que será preservado durante a instalação do Pod (nesse caso, nosso framework):
s.preserve_paths = "MyDeviceOnlyFramework.framework/*"
Em seguida, precisamos informar ao Cocoapods toda a configuração adicional que a biblioteca precisa para ser usada pelo nosso projeto principal. Para isso, incluímos a propriedade xcconfig, passando as informações necessárias para o arquivo de configuração que será gerado.
s.xcconfig = {
'FRAMEWORK_SEARCH_PATH[sdk=iphoneos*]' => '$(inherited) "$(PODS_ROOT)/MyDeviceOnlyFramework"',
'OTHERCFLAGS[sdk=iphoneos*]' => '$(inherited) -iframework "$(PODS_ROOT)/MyDeviceOnlyFramework"',
'OTHER_LDFLAGS[sdk=iphoneos*]' => '$(inherited) -framework MyDeviceOnlyFramework'
}
Note que usamos a variante de iphoneos* para nossas configurações. É essa variante que vai nos permitir setar os valores apenas para devices, e não mais para simuladores.
Feito isso, é só subir o seu podspec customizado para seu repositório de specs ou armazená-lo em um local que o cocoapods tenha acesso, e dar um pod install no seu projeto (não esqueça do —repo-update para atualizar suas dependências, se necessário).
A solução final
Após o pod install, sua dependência exibirá suas configurações da seguinte forma no Xcode:
No final, seu podspec será parecido com o abaixo:
Pod::Spec.new do |s|
s.name = "MyDeviceOnlyFramework"
s.version = "1.0.0"
s.summary = "This is a Device Only Framework"
s.description = <<-DESC
Device Only Framework Podspec Example.
DESC
s.homepage = "http://mywebpage.xpto/MyDeviceOnlyFramework"
s.license = { :type => "Copyright", :file => "LICENSE" }
s.author = { "Andre Salla" => "contato@andresalla.com" }
s.platform = :ios, "10.0"
s.source = { :git => "http://mygitrepo.xpto/MyDeviceOnlyFramework.git", :tag => "1.0.0"}
s.preserve_paths = "MyDeviceOnlyFramework.framework/*"
s.xcconfig = {
'FRAMEWORK_SEARCH_PATH[sdk=iphoneos*]' => '$(inherited) "$(PODS_ROOT)/MyDeviceOnlyFramework"',
'OTHERCFLAGS[sdk=iphoneos*]' => '$(inherited) -iframework "$(PODS_ROOT)/MyDeviceOnlyFramework"',
'OTHER_LDFLAGS[sdk=iphoneos*]' => '$(inherited) -framework MyDeviceOnlyFramework'
}
end
Agradecimento
Quero agradecer o August Jaenicke, que com o seu post conseguiu me tirar dessa situação complicada e me mostrou a luz no fim do túnel.
Link para o post: https://blog.carbonfive.com/cocoapods-for-device-only-ios-libraries/