J'essaie de créer un cadre dynamique pour une application iOS. Grâce à la nouvelle version de Xcode (6), nous pouvons sélectionner un framework Cocoa Touch lorsque nous créons un nouveau projet et il n’est plus nécessaire d’ajouter une cible agrégée, d’exécuter un script et donc d’en créer un. Je n'ai aucun problème quand je construis le cadre. Mais lorsque j'essaie de l'utiliser dans une application iOS, des problèmes d'architecture se posent.
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)
Eh bien, j'ai essayé de modifier les paramètres du projet de cadre et de la cible (Architectures et construire une architecture valide uniquement et des architectures valides). J'ai fait la même chose pour le projet d'application iOS mais rien ne fonctionne. Je pense qu'il y a quelque chose que je n'ai pas compris.
Par exemple, lorsque je construis un cadre uniquement pour la vérification i386 (simulateur iOS) à l'aide de la ligne de commande "xcrun lipo -info MyFramework", un problème survient.
ld: avertissement: en ignorant le fichier /Library/Frameworks/MyFramework.framework/MyFramework, le fichier a été construit pour x86_64, ce qui n’est pas l’architecture liée (i386) ...
Si quelqu'un peut m'aider à obtenir un framework qui fonctionne pour toutes les architectures iOS, y compris les simulateurs.
Désolé de laisser ce sujet ouvert depuis si longtemps ... Certains d'entre vous ont bien répondu à ma question. Lorsque j'ai écrit cette question, je n'ai pas compris qu'il y avait deux tranches dans un cadre complet (également appelé gras) (prêt à l'emploi). Un pour les appareils iOS et un pour le simulateur. Quand j'ai découvert que j'avais créé un script en utilisant la commande lipo pour fusionner les deux tranches, j'ai obtenu automatiquement une structure complète.
Sur la base de toutes les réponses, le post sur raywenderlich.com et le Gist créé par Chris Conway je suis venu avec cela .
En exécutant les étapes suivantes, j'ai pu construire un framework Cocoa Touch (y compris les Swift et Objective-C)) qui contient toutes les architectures pour le simulateur et le périphérique:
J'espère que ça aide :)
UPDATE: Correction d'une erreur dans le Gist où les chemins d'accès à l'étape 3 étaient incorrects. Merci à Tokurik !!
[~ # ~] mettre à jour [~ # ~] Sous Xcode 7 et 8, cliquez sur Fichier> Nouveau> Cible ... et sélectionnez "Autre". groupe pour sélectionner cible globale
Essayez les étapes suivantes pour créer un espace de travail contenant un projet-cadre et un projet d'application.
Espace de travail:
Projet cadre:
Projet d'application:
Notez que l'exemple ci-dessus montre comment créer une application qui s'exécute dans le simulateur . Si vous devez créer une bibliothèque statique universelle fonctionnant à la fois sur simulateur et devices, les étapes générales sont les suivantes:
Il existe de bonnes références sur le Web à ce sujet, ici par exemple.
Créer un binaire universel pour le framework: accédez au répertoire de données dérivées du framework puis /Build/Products , la commande suivante devrait vous aider à créer un binaire universel dans Répertoire des produits :
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"
Notez que framework-test-01 est le nom de mon projet-cadre.
Ensemble ONLY_ACTIVE_Arch=NO
dans le Build Settings
dans votre projet.
Ouvrir le dossier console Products
de votre framework (vous pouvez l’ouvrir en ouvrant le dossier framework et cd ..
à partir de là)
Exécuter ce script à partir du dossier Products
. Cela crée un gros framework dans ce dossier. (ou faites-le manuellement comme expliqué ci-dessous dans 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:
Combinez ces 2 cadres en utilisant lipo par ce script (remplacez YourFrameworkName
par le nom de votre cadre)
lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName"
Remplacez par un nouveau binaire parmi les cadres existants:
cp -R Debug-iphoneos/YourFrameworkName.framework ./YourFrameworkName.framework
mv YourFrameworkName ./YourFrameworkName.framework/YourFrameworkName
./YourFrameworkName.framework
- est un gros binaire prêt à l'emploi! Vous pouvez l'importer dans votre projet! Pour le projet, cela ne se trouve pas dans xcworkspace
- es:
Vous pouvez également essayer d'utiliser ce Gist Mais il semble que cela ne fonctionne pas pour les projets dans les espaces de travail.
La façon dont je l'ai fait est similaire à vladof, mais un peu plus simple, espérons-le. J'ai fait du framework un sous-projet du projet de l'application.
Projet cadre
Projet d'application
Pour une application Obj-C
Pour un Swift app
En procédant de cette façon, l'application dépend du cadre. Ainsi, si vous modifiez les classes du cadre, vous n'avez pas besoin de changer de cible pour construire le cadre séparément, il ne fera que compiler le cadre en premier, puis l'application.
J'ai un peu modifié le script de quelqu'un pour prendre en charge toutes les architectures de Simulator:
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}"
Une ancienne vidéo que j'ai faite depuis le lien ci-dessus n'est plus disponible.
Enfin, je l’ai fait fonctionner pour moi! Et désolé pour le grand cadre jaune, je ne sais pas comment le formater mieux.
La solution est venue de Claudio Romandi mais le script lié a un problème mineur. Je ne peux pas commenter son message car j'ai besoin de 50 points de réputation, je n'ai donc pas d'autre choix que de le copier pour obtenir une solution complète ..
Mettez le code suivant dedans:
#!/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}"
Sélectionnez le total dans la liste déroulante Scheme Selection
Le problème était que le répertoire du simulateur pointait vers un répertoire non existant, changer "Framework" en "$ {PROJECT_NAME}" à 2 endroits a été une solution :)
Je voulais ajouter quelque chose à la réponse du script lipo fournie par skywinder ici . J'ai suivi les étapes mais je n'ai toujours pas réussi à faire fonctionner mon framework sur simulateur, uniquement sur périphérique. Pour résoudre ce problème:
-Je suis allé dans la version debug-iphonesimulator du framework, et dans Modules/[FrameworkName] .swiftmodule, j'ai copié tous les fichiers i386 et X86.
-Je suis ensuite allé dans la version fat nouvellement créée du framework, et ai navigué dans ce même dossier. J'ai collé dans les fichiers i386 et X86 (pour aller avec les ARM déjà présents)), puis j'ai ajouté mon fat framework à mon projet.
Voilà, elle travaille sur simulateur et appareil réel! Ceci est Xcode 10/Swift 4.2 btw
Quelques points supplémentaires autour de l’approche partagée par vladof qui s’appliquent davantage aux cadres basés sur Swift
Cette question a été posée il y a quelque temps (Xcode 6) mais j'ai rencontré le même problème récemment avec Xcode 10.
Le problème est donc le suivant: le framework construit ne supporte pas suffisamment d'architectures.
Au cas où vous ne sauriez pas quelles architectures représentent, différents appareils iPhone ont des architectures différentes, voici une liste complète:
Ainsi, si vous utilisez le framework sur simulateur, celui-ci doit prendre en charge i386 ou x86_64. Si vous exécutez votre application sur iPhone 6, le framework doit prendre en charge l’architecture arm64.
Par conséquent, dans la plupart des cas, un cadre doit prendre en charge toutes les architectures susmentionnées.
Revenons maintenant à la façon de résoudre le problème. Nous devons construire le cadre pour les appareils et les simulateurs.
Comment construire pour les périphériques:
Comment construire pour les simulateurs:
Comment construire des appareils et des simulateurs:
Une fois que vous avez le cadre pour les périphériques, vous devez combiner le cadre pour les simulateurs et le cadre pour les périphériques avec la commande "lipo". Renommez le cadre pour les simulateurs en [MyFrameworkProject] _sim.framework et copiez les deux cadres dans le même dossier. Exécutez la commande ci-dessous dans Terminal (assurez-vous d'être dans le dossier):
lipo -create -output [MyFrameworkProject].framework/[MyFrameworkProject] [MyFrameworkProject].framework/MyFrameworkProject [MyFrameworkProject]_sim.framework/MyFrameworkProject
Maintenant, [MyFrameworkProject] .framework est le produit final qui prend en charge les simulateurs et les appareils.