Xcode 6 e Embedded Frameworks suportados apenas no iOS8

Ao usar uma estrutura integrada (dyld) no Xcode 6.0.1 com um destino de implementação menor que o iOS 8, recebo:

  • Construir é bem sucedido
  • Erro de carregamento da biblioteca de tempo de execução

Erro:

dyld: Library not loaded: @rpath/ObjectiveLyricsTouch2.framework/ObjectiveLyricsTouch2 Referenced from: /private/var/mobile/Containers/Bundle/Application/DC65ACA9-98E5-46CD-95F8-829D3416F6C0/musiXmatch.app/musiXmatch Reason: image not found (lldb) 

Por algum tempo eu estava pensando que este é o meu problema também, mas para aplicativos normais ( non-iOS-8-extension ) você só precisa mudar uma configuração de build no seu alvo casual do Xcode 6 iOS Universal Framework ( definir Mach-O Type à biblioteca estática ):

Definir como biblioteca estática

Não deve haver nenhum problema com o iTunes Connect e iOS 7 depois disso 🙂

Então, depois de cavar por aí eu saí com a solução

Supostamente para ter o seu MyEmbeddedFramework.framework para adicionar ao aplicativo, faça isso

  1. Remova MyEmbeddedFramework.framework na guia General> Embedded Binaries
  2. Remova as fases de compilation> Copy Phase “Frameworks” se você tiver MyEmbeddedFramework.framework lá.
  3. Pasta de compilation limpa
  4. Mova o MyEmbeddedFramework.framework na seção void Embedded Frameworks.
  5. Você verá agora que uma nova Build Phase> Embedded Frameworks é criada pelo XCode6 (não você, isso é feito automaticamente)
  6. Agora, se você tem 5, ele deve rodar sem erros.

Então, para recapitular, para que funcione, você deve ver MyEmbeddedFramework.framework em

A) Geral> Binários Embutidos Geral/> Binários Embutidos”></p>
<p>  B) Fase de Construção> Frameworks Embutidos <img src=

A partir de agora, não há como usar uma estrutura incorporada para compartilhar código entre um aplicativo e um widget e executá-lo no iOS 8, bem como no iOS 7 e anterior.

Aqui está mais alguma leitura sobre http://atomicbird.com/blog/ios-app-extension-tips

Frameworks vs. iOS 7

Se você estiver compartilhando código entre um aplicativo e uma extensão, uma boa maneira de fazer isso é criar sua própria estrutura incorporada para manter o código. No iOS 8, ele será carregado dinamicamente para ambos os casos, então você está pronto.

Se você ainda suporta o iOS 7 (ou anterior), não é tão claro. Estruturas incorporadas não funcionam lá. O Guia de Programação de Extensão de App observa que você pode usar o dlopen para lidar com isso. Com essa abordagem, você escreve código para carregar a estrutura dinamicamente em tempo de execução, em vez de confiar no iOS para carregá-lo, se você verificou se o código está sendo executado em uma versão do iOS que suporta isso.

Mas como você usa esse código no iOS 7? Você não Se o seu código compartilhado estiver em uma estrutura incorporada, não há como executá-lo no iOS 7. Ele está indisponível.

A abordagem dlopen pode ser útil se você precisar apenas do código compartilhado no iOS 8. Se precisar no iOS 7, será necessário incluí-lo no destino do aplicativo. E uma vez que você faz isso, você não precisa da estrutura. Você ainda pode usar uma estrutura para a extensão de aplicativo, mas isso não é realmente útil. Você estaria fazendo o trabalho de criar a estrutura, mas não obtendo nenhum benefício dela. Apenas inclua o código compartilhado nos dois destinos.

E no guia de extensão da Apple, https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensibilityPG.pdf

Se você vincular a uma estrutura incorporada a partir do aplicativo que contém, ainda poderá implantá-la em versões do iOS anteriores à 8.0, mesmo que as estruturas incorporadas não estejam disponíveis nessas versões.

Corrigido o erro no xcode 6.1.1

usando vim ou vi, abra o arquivo project.pbxproj.

No final do arquivo (procure por 8.1), deve haver a seção Iniciar XCBuildConfiguration

Procure seu framework.

Em nosso caso, embora o destino de implementação tenha sido definido como 7.1 via Xcode -> general nas configurações de destino, a input no arquivo tinha 8.1 para debugging e liberação

Aqui está a seção de arquivos antigos se parece com:

 CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = ENFramework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; 

Nova seção se parece com:

 CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = ENFramework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 7.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; 

Agora, não recebemos um erro apenas um aviso (mas funciona no dispositivo iOS 7.1): ld: aviso: os dylibs / frameworks incorporados só são executados no iOS 8 ou posterior

Isso parece um bug xcode que define incorretamente alvos ios diferentes e, em seguida, causa erro.

Aprofundando na Documentação da Apple , descobri o comando dlopen , que é usado para fazer a vinculação das bibliotecas em algumas condições, dependendo das versões do sistema e das bibliotecas suportadas.

dlopen exemplo de uso: A function ‘dlopen ()’ private API?

Então, vamos dar uma olhada na solução fornecida pelo Apple Docs:

Implantando um aplicativo de contenção em versões antigas do iOS

Se você vincular a uma estrutura incorporada a partir do aplicativo que contém, ainda poderá implantá-la em versões do iOS anteriores à 8.0, mesmo que as estruturas incorporadas não estejam disponíveis nessas versões.

O mecanismo que permite fazer isso é o comando dlopen , que você usa para vincular e carregar condicionalmente um pacote configurável de estrutura. Você emprega esse comando como uma alternativa para o vínculo de tempo de construção que você pode especificar no Xcode General ou no editor de destino das Fases de Construção . A ideia principal é vincular estruturas incorporadas ao seu aplicativo contido somente quando estiver executando no iOS 8.0 ou mais recente .

Você deve usar o Objective-C, não o Swift , em suas instruções de código que carregam condicionalmente um pacote configurável de estrutura. O restante do seu aplicativo pode ser escrito em qualquer idioma e a própria estrutura incorporada também pode ser escrita em qualquer idioma.

Depois de chamar o dlopen , acesse as classs da estrutura incorporada usando o seguinte tipo de instrução:

 MyLoadedClass *loadedClass = [[NSClassFromString (@"MyClass") alloc] init]; 

IMPORTANTE

Se seus links de destino de aplicativo contidos para uma estrutura incorporada, ele deve include a arquitetura arm64 ou será rejeitado pela App Store.

Para configurar um projeto Xcode de extensão de aplicativo para aproveitar a vinculação condicional

  1. Para cada uma das suas extensões de aplicativo contidas, defina o destino de implantação como iOS 8.0 ou posterior, como de costume. Faça isso na seção “Informações de implantação” da guia Geral no editor de destino do Xcode.
  2. Para o seu aplicativo contido, defina o destino de implementação como a versão mais antiga do iOS que você deseja oferecer suporte.
  3. Em seu aplicativo contido, condicionalize as chamadas para o comando dlopen em uma verificação de tempo de execução para a versão do iOS usando o método systemVersion. Ligue para o comando dlopen apenas se o aplicativo que o contém estiver executando no iOS 8.0 ou posterior. Certifique-se de usar o Objective-C, não o Swift, ao fazer esta chamada.

Determinadas APIs do iOS usam estruturas incorporadas por meio do comando dlopen. Você deve condicionar o uso dessas APIs exatamente como faz ao chamar o dlopen diretamente. Essas APIs são do tipo opaco CFBundleRef :

CFBundleGetFunctionPointerForName
CFBundleGetFunctionPointersforNames

E da class NSBundle:

carga
loadAndReturnError:
classNamed:

Em um aplicativo que você está implantando em versões do iOS anteriores à 8.0, chame essas APIs apenas em uma verificação de tempo de execução que garanta que você esteja executando no iOS 8.0 ou mais recente e chame essas APIs usando o Objective-C.

Tentamos executar o código mais recente nas seguintes configurações:

iOS 8+ – iPhone 5s iOS 7.1.2 – iPhone 4 iOS 6.1.3 – iPad 4

O aplicativo está funcionando bem em todos os três dispositivos, mas o aviso está presente no Xcode durante a compilation. “dylibs / frameworks incorporados são executados somente no iOS 8 ou posterior”

Também tentei arquivar o aplicativo para enviá-lo para a loja de aplicativos que correu bem.

Além disso, descobri um link onde em um desenvolvedor de maçã afirmou que isso é um bug https://devforums.apple.com/message/999579#999579

Eu configurei o Mach-O Type como EXECUTABLE e funcionou para mim. Configurá-lo para Static, Dynamic ou Bundle criou outros erros quando o executei.

Destino> “Seu aplicativo”> ​​Configurações de construção> Vinculação> Tipo Mach-O> Executável

Eu resolvo esse problema da seguinte maneira: Use o mesmo destino de implantação no destino “Embedded Framework” e “principal aplicativo”.

Então, temporário, eu disse não para biblioteca dinâmica, enquanto muitos dispositivos no iOS 7. Como eu resolvi meu problema. Eu precisava de lib para transferir o modelo entre o aplicativo e a extensão. Então, eu coloquei meu modelo para string JSON no container compartilhado. E funciona como um encanto.

Apenas para o registro … Eu tive esse problema ao alterar um projeto do iOS8 para o tipo de implantação do iOS7.

O aplicativo usava cocoapods e nenhum framework incorporado personalizado.

Eu tive que mudar o projeto principal dois alvos
Aplicação
Teste de Aplicação

Alterar o Mach-O Type para static (da resposta acima).

Então, no projeto cocoapods. Em cada projeto de subpainho, alterar o tipo Mach-O para estático, deixando a configuração principal do Mach Mach do Project em branco.

Quando você usa a biblioteca dinâmica no ios, você deve codificar a biblioteca assinada. No Xcode 6, você deve selecionar o “Code Sign On Copy”. E com o Xcode5, você deve assinar a biblioteca por conta própria com o script de execução. gostar :

 LOCATION="${BUILT_PRODUCTS_DIR}"/"${FRAMEWORKS_FOLDER_PATH}" IDENTITY="iPhone Developer: xxxxx" codesign --verbose --force --sign "$IDENTITY" "$LOCATION/BeeFramework.framework/BeeFramework" 

Remova as estruturas de uso! do seu PodFile se você quiser que o Framework funcione no iOS 7.0. ou seja, execute o comando pod deintegrate, modifique seu PodFile e, em seguida, execute novamente o comando pod install

Além disso, depois disso, tive que adicionar todos os arquivos .h do Framework no arquivo Bridging, que resolveu o problema. Também remova a importação TestLibrary dos arquivos rápidos

Eu tive um erro ao atualizar para o xcode 7.3. E eu tive solução para mim. – Mude os alvos no projeto de pods -> 7.0 – Espero que seja útil! ataque

Eu estava me deparando com um problema em que eu precisava include algumas bibliotecas como estruturas incorporadas. Caso contrário, recebi o erro acima e, quando fiz isso, recebi erros ao enviar para a loja de aplicativos.

Minha solução foi usar o Pods e descomentar o “use_frameworks!” linha.