Xcode 6 iOS Criando um Cocoa Touch Framework – Arquiteturas

Estou tentando criar uma estrutura dinâmica para um aplicativo iOS. Graças à nova versão do Xcode (6), podemos selecionar um Cocoa Touch Framework quando criamos um novo projeto e não há mais necessidade de adicionar um alvo agregado, executar o script e, assim, criar um. Eu não tenho nenhum problema quando eu construo o framework. Mas quando estou tentando usá-lo dentro de um aplicativo iOS, recebo alguns problemas de arquitetura.

ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (arm64): /Library/Frameworks/MyFramework.framework/MyFramework Undefined symbols for architecture arm64: "_OBJC_CLASS_$_MyFrameworkWebService", referenced from: objc-class-ref in AppDelegate.o ld: symbol(s) not found for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation) ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (armv7): /Library/Frameworks/MyFramework.framework/MyFramework Undefined symbols for architecture armv7: "_OBJC_CLASS_$_MyFrameworkWebService", referenced from: objc-class-ref in AppDelegate.o ld: symbol(s) not found for architecture armv7 clang: error: linker command failed with exit code 1 (use -v to see invocation) 

Bem, tentei alterar as configurações do projeto e do destino da estrutura (Arquiteturas e Construir apenas arquiteturas válidas e Arquiteturas válidas). Eu fiz a mesma coisa para o projeto do aplicativo iOS, mas nada funciona. Eu acho que há algo que eu não entendi.

Por exemplo, quando eu construo uma estrutura para apenas i386 (iOS Simulator), verifique com a linha de comando “xcrun lipo -info MyFramework”, eu tenho um problema que

ld: aviso: ignorando o arquivo /Library/Frameworks/MyFramework.framework/MyFramework, o arquivo foi criado para x86_64, que não é a arquitetura que está sendo vinculada (i386) …

Se alguém puder me ajudar a obter uma estrutura que funcione para todas as arquiteturas iOS, incluindo simuladores.

Com base em todas as respostas, o post sobre raywenderlich.com e a essência criada por Chris Conway I surgiu com isso .

Executando as etapas a seguir, consegui criar uma estrutura do Cocoa Touch (incluindo arquivos Swift e Objective-C) que contém todas as arquiteturas para simulador e dispositivo:

  1. Criar um novo alvo (Agregado) no projeto do seu framework
  2. Em “Build Phases”, selecione “Add Run Script” e copie o conteúdo deste arquivo
  3. Selecione o alvo Agregar na lista suspensa Seleção de Esquema
  4. Construa o alvo para o esquema agregado

Espero que ajude 🙂

ATUALIZAÇÃO: Corrigido um erro na essência em que os caminhos na etapa 3 estavam incorretos. Graças a Tokuriku !!

UPDATE No Xcode 7 e 8, clique em File> New> Target … e selecione o grupo “Other” para selecionar Aggregate target

Tente as etapas a seguir para criar um espaço de trabalho que contenha um projeto de estrutura e um projeto de aplicativo.

Área de trabalho:

  • Crie um espaço de trabalho.

Projeto de estrutura:

  • Crie um projeto do iOS Cocoa touch Framework dentro do Workspace.
  • Adicione uma class simples do Objective C MyClass (header .h e arquivo de implementação .m) e crie um método – (void) greetings .
  • Vá para o projeto Fases de Construção > Cabeçalhos > Mover MyClass.h de Projeto para Público .
  • Altere o esquema para o projeto de estrutura e escolha o simulador do iOS e , em seguida, crie. (Escolha o dispositivo iOS se o aplicativo que integra esta estrutura for executado no dispositivo. Continuaremos usando o simulador neste exemplo)
  • Você não deve ter nenhum problema de construção, a construção do framework é encontrada em seu diretório Derived Data , que você pode encontrar no Organizer .

Projeto App:

  • Crie um aplicativo Swift Single View dentro do Workspace.
  • Arraste acima da estrutura do simulador do iOS (encontrado em Debug-iphonesimulator ou Release-iphonesimulator ) para o seu projeto.
  • Crie um header de bridging para expor os methods da class Objective C ao Swift.
  • Importe MyClass.h no arquivo de header de ponte.
  • Observe que, se a definição do MyClass não for encontrada, adicione o caminho Headers da estrutura aos caminhos de pesquisa de header de configurações de compilation.
  • Crie uma instância de MyClass em viewDidLoad de ViewController.swift e chame greetings .
  • Adicionar estrutura ao destino> binários incorporados
  • Altere o esquema para o projeto de aplicativo e escolha o simulador do iOS e , em seguida, crie.
  • Você deve poder ver as mensagens de saudação.

Observe que o exemplo acima demonstra como criar um aplicativo que é executado no simulador . Se você precisar criar uma biblioteca estática universal que seja executada no simulador e nos dispositivos , as etapas gerais serão:

  • Construir biblioteca para simulador
  • Construir biblioteca para dispositivo
  • Combine-os usando lipo

Há boas referências na web sobre isso, aqui por exemplo.

Criar um binário universal para o framework: navegue para o diretório Derived Data, em seguida, / Build / Products , o seguinte comando deve ajudá-lo a criar um binário universal no diretório Products :

 lipo -create -output "framework-test-01-universal" "Debug-iphonesimulator/framework-test-01.framework/framework-test-01" "Debug-iphoneos/framework-test-01.framework/framework-test-01" 

Observe que o framework-test-01 é o nome do meu projeto de framework.

Aqui estão os passos para criar uma estrutura de gordura (universal):

  1. Defina ONLY_ACTIVE_ARCH=NO nas Build Settings do seu projeto.

    • Construir biblioteca para simulador
    • Construir biblioteca para dispositivo
  2. Abra na pasta de Products console para o seu framework (você pode abri-lo pela pasta de estrutura aberta e cd .. de lá)

insira a descrição da imagem aquiinsira a descrição da imagem aqui

  1. Execute esse script na pasta Products . Cria um framework de gordura nesta pasta. (ou manualmente, como explicado abaixo em 4. 5. )

     framework_name="${$(basename $(find ./Debug-iphoneos -type d -name '*.framework' -maxdepth 1))%.*}" && \ cp -R Debug-iphoneos/$framework_name.framework ./$framework_name.framework && \ lipo -create -output "$framework_name.framework/$framework_name" "Debug-iphonesimulator/$framework_name.framework/$framework_name" "Debug-iphoneos/$framework_name.framework/$framework_name" 

Ou:

  1. Combine esses 2 Frameworks usando lipo por este script (substitua YourFrameworkName pelo nome do Framework)

     lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName" 
  2. Substitua por um novo binário dos frameworks existentes:

     cp -R Debug-iphoneos/YourFrameworkName.framework ./YourFrameworkName.framework mv YourFrameworkName ./YourFrameworkName.framework/YourFrameworkName 

  1. Lucro: ./YourFrameworkName.frameworkestá pronto para usar binário de gordura! Você pode importá-lo para o seu projeto!

Para projeto, isso não no xcworkspace -es:

Você também pode tentar usar essa essência. Mas parece que não funciona para projetos em espaços de trabalho.

A maneira como fiz isso é semelhante ao vladof, mas espero que seja um pouco mais simples. Eu fiz do framework um subprojeto do projeto de aplicativo.

Projeto Framework

  • Crie um novo iOS Cocoa Touch Framework. Chame isso de MyLib. Isto irá criar um único MyLib.h
  • Adicione uma class simples Obj-C do Cocoa Touch, MyClass (.h & .m) e, na implementação do .m, crie um método que retorne uma string, – (NSString *) greetings;
  • Em MyLib.h, adicione isso na parte inferior, #import “MyClass.h”
  • Na seção Build Phases / Headers do alvo, Move MyClass.h da seção Project para a seção Public.
  • Faça um Build (cmd-B)
  • Feche o projeto

Projeto App

  • Crie um novo projeto de aplicativo Single View, seja Swift ou Obj-C. Chame isso de MyApp.
  • No Finder, arraste seu arquivo de projeto MyLib para a seção esquerda do organizador da sua janela MyApp e certifique-se de que a linha de inserção esteja logo abaixo de MyApp. Isso faz do MyLib um subprojeto do MyApp. (Ele ainda pode ser usado da mesma maneira em outros projetos)
  • Clique em MyApp no ​​organizador e, em seguida, selecione o destino MyApp e selecione Construir fases.
  • Em Target Dependances, clique no sinal + e adicione MyLib.
  • Em Vincular com bibliotecas, clique no sinal de + e adicione MyLib.framework.

Para um aplicativo Obj-C

  • No ViewController.m, adicione #import
  • Em viewDidLoad, adicione as seguintes linhas:
  • MyLib * x = [[alocação MyLib] init];
  • NSLog (@ “% @”, x.greetings);
  • Execute o projeto e você deverá ver a mensagem na janela de debugging. –

Para um aplicativo Swift

  • Em ViewController.swift, adicione import MyLib
  • no viewDidLoad, adicione as seguintes linhas:
  • var x: MyLib = MyLib ()
  • println (“(x.greetings ())”) –

Ao fazer isso dessa maneira, o aplicativo depende da estrutura, portanto, se você fizer uma alteração nas classs da estrutura, não precisará alterar os alvos para criar a estrutura separadamente; ela apenas compilará a estrutura primeiro e, em seguida, o aplicativo.

Eu mudei o script de alguém um pouco para suportar todas as arquiteturas do Simulador:

 UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal # make sure the output directory exists mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" # Step 1. Build Device and Simulator versions xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator VALID_ARCHS="x86_64 i386" BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build # Step 2. Copy the framework structure to the universal folder cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/" # Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}" # Step 4. Convenience step to copy the framework to the project's directory cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}" # Step 5. Delete temporary build directory in the project's directory rm -rf "${PROJECT_DIR}/build" # Step 6. Convenience step to open the project's directory in Finder open "${PROJECT_DIR}" 

Um vídeo antigo que eu fiz desde o link acima anteriormente não está mais disponível.

Como criar um framework Cocoa Touch usando o Xcode 6

Poucos pontos adicionais em torno da abordagem compartilhada pelo vladof são mais aplicáveis ​​a Frameworks baseados em

  1. O script no link associado precisa ser modificado para copiar todos os arquivos do iphonesimulator e do iphoneos, já que o swift tem arquivos compilados separados para o i386 e o ​​arm
  2. Assegure-se de ter ARCHS = “x86_64” ONLY_ACTIVE_ARCH = NO na construção de iphonesimulator para evitar problemas de linker para o simulador
  3. Assegure-se de que sua interface / class estenda o NSObject, caso contrário, você terá problemas ao tentar usar o código no swift (ele se queixará de não conseguir criar o object usando ().

Finalmente, consegui que funcionasse para mim! E desculpe pelo grande quadro amarelo, não tenho idéia de como formatá-lo melhor.

A solução veio de Claudio Romandi, mas o script vinculado tem um pequeno problema. Eu não posso comentar sobre o post dele, pois eu preciso da reputação de 50, então não tenho mais escolha a não ser copiar o post dele para ter uma solução completa.

  1. Criar um novo alvo (agregado) em seu projeto de estrutura
  2. Selecione o agregado na área de trabalho e adicione uma “nova fase de script de execução”
  3. Coloque o seguinte código nele:

     #!/bin/sh UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal # make sure the output directory exists mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" # Step 1. Build Device and Simulator versions xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build # Step 2. Copy the framework structure (from iphoneos build) to the universal folder cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/" # Step 3. Copy Swift modules (from iphonesimulator build) to the copied framework directory cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/." "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule" # Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}" # Step 5. Convenience step to copy the framework to the project's directory cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}" # Step 6. Convenience step to open the project's directory in Finder open "${PROJECT_DIR}" 
  4. Selecione o agregado na seleção suspensa de seleção de esquema

  5. Construa, está feito!

O problema era que o diretório do simulador estava apontando para um diretório inexistente, mudando “Framework” para “$ {PROJECT_NAME}” em 2 lugares, deu certo 🙂

Desculpe por deixar este tópico aberto por um longo tempo … Alguns de vocês responderam corretamente à minha pergunta. Quando eu escrevi essa pergunta, não percebi que havia duas fatias em uma estrutura completa (também chamada de gordura) (pronta para uso). Um para os dispositivos iOS e outro para o simulador. Quando descobri que fiz um script usando o comando lipo para fundir as duas fatias e obtive automaticamente uma estrutura completa.