Fim dos fat binaries: XCFrameworks
Em 2019, o Xcode 11 trouxe uma funcionalidade que todo desenvolvedor iOS sempre quis: gerar um framework que rodasse tanto no simulador quanto no device.
Antes, isso já era possível, usando o lipo para gerarmos um fat binary. Apesar de possível, a Apple há tempos desencoraja o seu uso, mas nunca ofereceu uma alternativa viável para isso.
Agora podemos utilizar o xcframework, que gera um pseudo framework, que contém dentro de si vários frameworks para plataformas distintas.
Supomos que seu framework dê suporte para devices iOS, simulador iOS e macOS. Dentro do xcframework, encontraremos os 3 frameworks buildados, e quando o projeto que irá usar o framework for buildado, o Xcode selecionará automaticamente qual dos frameworks contidos ele deve usar.
Vantagens de um xcframework
- Suporte à múltiplas plataformas dentro do mesmo framework.
- Suporte à Swift, Objective-C e C.
- Suporte à dynamic frameworks e static libraries.
- Suporte ao Swift Package Manager.
- Fim dos fat binaries.
Gerando um XCFramework
No seu projeto, crie um novo target (File -> New -> Target) da seção “Cross Platform” do tipo “Aggregate“.
No Build Phases do seu novo target, adicione um Run Script e cole o código abaixo:
#Gera o framework para devices
xcodebuild archive -scheme ${PROJECT_NAME} -archivePath "${PROJECT_DIR}/build/${PROJECT_NAME}-iphoneos.xcarchive" -sdk iphoneos SKIP_INSTALL=NO BUILD_LIBRARIES_FOR_DISTRIBUTION=YES
#Gera o framework para simuladores
xcodebuild archive -scheme ${PROJECT_NAME} -archivePath "${PROJECT_DIR}/build/${PROJECT_NAME}-iossimulator.xcarchive" -sdk iphonesimulator SKIP_INSTALL=NO BUILD_LIBRARIES_FOR_DISTRIBUTION=YES
#Gera o xcframework para as duas arquiteturas
xcodebuild -create-xcframework -framework "${PROJECT_DIR}/build/${PROJECT_NAME}-iphoneos.xcarchive/Products/Library/Frameworks/${PROJECT_NAME}.framework" -framework "${PROJECT_DIR}/build/${PROJECT_NAME}-iossimulator.xcarchive/Products/Library/Frameworks/${PROJECT_NAME}.framework" -output "${PROJECT_DIR}/build/${PROJECT_NAME}.xcframework"
#Abre a pasta onde o xcframework foi gerado
open "${PROJECT_DIR}/build"
Esse código basicamente faz o archive do seu projeto tanto para device quanto simulador, e em seguida cria o xcframework. Os artefator gerados ficarão em uma pasta build no seu projeto.
Nos archives você ainda poderá obter os DSYMS da suas compilações.
A dica de ouro
O xcodebuild “ignora” o parâmetro BUILD_LIBRARIES_FOR_DISTRIBUTION (muito provavelmente isso é um bug que será corrigido posteriormente). Dessa forma, ele não gera o arquivo swiftinterface, necessário para o create-xcframework funconar.
Para resolver o problema, a flag de build para distribuição deve ser YES também no build settings do seu projeto.
Para alterar a flag, vá em Build Settings, selecione All no nível de exibição, e na seção Build Settings, altere a chave Build libraries for distribution para Yes.
Agora execute novamente o target, e tudo vai funcionar como deveria ser. Basta agora arrastar o seu xcframework para dentro do projeto do seu app principal e o Xcode se encarregará de tudo daqui pra frente.