Je sais que ce n'est pas possible et Apple l'a prévu de cette façon pour forcer les utilisateurs à mettre à niveau leurs appareils. Mais je veux juste savoir s'il existe une solution de contournement ou des hacks pour le faire? Le client insiste sur le fait que nous devrions toujours prendre en charge armv6 en raison d'un pourcentage encore "important" des utilisateurs de l'application.
Je connais une commande appelée lipo
pour fusionner des bibliothèques statiques et j'ai lu quelque part que nous pouvons également l'utiliser pour fusionner des fichiers ipa mais je ne sais pas comment c'est exactement fait. J'ai déjà fait quelques recherches sur Google et ce site, mais il est difficile de trouver une réponse concrète.
J'ai réussi à le faire avec mon application qui se trouve dans l'App Store. Il prend en charge les versions armv6, armv7 et armv7s et iOS de 4.2 à 6.0. J'ai vérifié qu'il fonctionne sur des appareils plus anciens (iPhone 3G, iPod touch 2g) tout au long de l'iPhone 5.
Cette méthode nécessite l'installation simultanée de Xcode 4.5 et d'une ancienne version de Xcode. Je suis toujours sur 4.3.2 pour mon ancienne version, mais 4.4 devrait également fonctionner.
J'ai eu des captures d'écran pour cette réponse, mais Stack Overflow ne me laissera pas les poster parce que je suis nouveau. :(
Ajoutez une nouvelle configuration de build pour votre build armv6. J'ai dupliqué la configuration Release et je l'ai nommée Release_armv6.
Définissez les architectures et les architectures valides pour vos configurations de build. Pour tous sauf Release_armv6, utilisez la valeur par défaut. Pour Release_armv6, définissez-le manuellement sur armv6 . http://i.stack.imgur.com/h8Mpl.png
Si vous utilisez des fonctionnalités iOS 6 que Xcode 4.4 et versions ultérieures ne comprendront pas, vous devrez les #ifdef pour votre build armv6. Dans Build Settings sous Other C Flags et Other C++ Flags, j'ai ajouté - DARMV6_ONLY à ma configuration Release_armv6. Ensuite, chaque fois que le code utilise une nouvelle API iOS 6, je fais quelque chose comme #ifndef ARMV6_ONLY/#endif selon le cas. http://i.stack.imgur.com/czF6J.png
Ajoutez un nouveau schéma et définissez-le pour utiliser la configuration de version Release_armv6 dans tous les cas.
Sous Build Phases, ajoutez une Run Script Build Phase avec le script suivant (définissez le shell sur /bin/csh ). C'est là que la magie opère. Modifiez la section Configuration: Déterminez votre chemin d'accès complet à la version Release_armv6 et remplacez-le par ARMV6_EXECUTABLE_PATH. Définissez également MINIMUM_OS.
#
# Script to add armv6 architecture to iOS executable built with Xcode 4.5
#
#################
# Configuration #
#################
# Change this to the full path where Xcode 4.4 (or below) puts your armv6 output
setenv ARMV6_EXECUTABLE_PATH "$BUILD_ROOT/Release_armv6-iphoneos/$EXECUTABLE_PATH"
# Your "real" minimum OS version since Xcode 4.5 wants to make it iOS 4.3
# Must be 4.2 or below if you are supporting armv6...
setenv MINIMUM_OS 4.2
#####################
# End configuration #
#####################
# For debugging
echo CURRENT_Arch = $CURRENT_Arch
echo CONFIGURATION = $CONFIGURATION
# Don't need to do this for armv6 (built in older Xcode), simulator (i386), or debug build
if ("$CURRENT_Arch" == "armv6") exit 0
if ("$CURRENT_Arch" == "i386") exit 0
if ("$CONFIGURATION" != "Release" && "$CONFIGURATION" != "Beta Test") exit 0
# Paths
setenv LIPO_PATH "$CODESIGNING_FOLDER_PATH/${EXECUTABLE_NAME}.lipo"
setenv FINAL_PATH "$CODESIGNING_FOLDER_PATH/$EXECUTABLE_NAME"
setenv FULL_INFO_PLIST_PATH "$CONFIGURATION_BUILD_DIR/$INFOPLIST_PATH"
# Debug / sanity check
lipo -info "$FINAL_PATH"
ls -l "$ARMV6_EXECUTABLE_PATH"
# Make sure something exists at $LIPO_PATH even if the next command fails
cp -pv "$FINAL_PATH" "$LIPO_PATH"
# If rebuilding without cleaning first, old armv6 might already be there so remove it
# If not, lipo won't output anything (thus the cp command just above)
lipo -remove armv6 -output "$LIPO_PATH" "$FINAL_PATH"
# Add armv6 to the fat binary, show that it worked for debugging, then remove temp file
lipo -create -output "$FINAL_PATH" "$ARMV6_EXECUTABLE_PATH" "$LIPO_PATH"
lipo -info "$FINAL_PATH"
rm -f "$LIPO_PATH"
# Change Info.plist to set minimum OS version to 4.2 (instead of 4.3 which Xcode 4.5 wants)
/usr/libexec/PlistBuddy -c "Set :MinimumOSVersion $MINIMUM_OS" "$FULL_INFO_PLIST_PATH"
plutil -convert binary1 "$FULL_INFO_PLIST_PATH"
Lorsque vous êtes prêt à créer une version, faites-le dans l'ordre suivant:
Fermez Xcode 4.5 et ouvrez Xcode 4.4 ou inférieur. Sélectionnez votre schéma armv6 et construisez-le.
Fermez Xcode 4.4 ou inférieur et ouvrez Xcode 4.5. Sélectionnez votre schéma de version et construisez-le.
C'est à peu près ça. Vérifiez la sortie de la construction pour vérifier que vous avez obtenu ce que vous voulez - un exécutable avec trois architectures. La dernière sortie du script d'exécution devrait vous le dire.
Si quelqu'un a des idées pour améliorer cela, n'hésitez pas. J'imagine que vous pourriez être en mesure d'imaginer et d'appeler la commande "xcodebuild" de Xcode 4.4 à partir du script de construction, ce qui soulage la nécessité de basculer entre les versions de Xcode. Mais cela fonctionne assez bien pour moi. ;)
Mises en garde:
Juste pour être sûr, vous voudrez peut-être modifier vos fichiers xib dans l'ancienne version de Xcode. Jusqu'à présent, il semble que 4.5 soit rétrocompatible, mais on ne sait jamais.
En fait, vous pourriez envisager de faire la plupart de votre développement, à l'exception des éléments spécifiques à iOS 6, dans l'ancien Xcode. Cela dépend de ce qui est le plus simple pour vous.
Il existe un autre moyen car gcc-4.2 prend toujours en charge armv6, qui ne vous obligera pas à fermer Xcode 4.5 et à ouvrir une version précédente (pour la compilation, mais pas pour exécuter l'application sur un appareil 4.2):
Arches: $ (ARCHS_STANDARD_32_BIT) armv6
Architectures valides: armv6 armv7 armv7s
Ensuite, si vous construisez votre projet, vous verrez des avertissements:
avertissement: aucune règle pour traiter le fichier '$ (PROJECT_DIR) /App/AppDelegate.m' de type sourcecode.c.objc pour l'architecture armv6 avertissement: aucune règle pour traiter le fichier '$ (PROJECT_DIR ) /App/SomeFile.c 'de type sourcecode.cc pour l'architecture armv6
Build Rule
pour les fichiers source dont les noms correspondent: *.[mc]
qui utilisera LLVM GCC 4.2
Cela fonctionne pour les bibliothèques statiques, mais pas pour les applications:
ld: le fichier est universel (4 tranches) mais ne contient pas a(n) armv6 slice: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform /Developer/SDKs/iPhoneOS6.0.sdk/usr/lib/crt1.3.1.o pour l'architecture armv6
lipo /path/to-4.4/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/usr/lib/crt1.3.1.o -extract armv6 - sortie /tmp/crt1.3.1-armv6.o[.____.[lipo /Applications/Xcode.app/Contents//Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/usr/lib/crt1 .3.1.o /tmp/crt1.3.1-armv6.o -create -output /tmp/crt1.3.1-armv677s.o. platform/Developer/SDKs/iPhoneOS6.0.sdk/usr/lib/crt1.3.1.o /Applications/Xcode.app/Contents//Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/usr /lib/crt1.3.1.o.bkp[.____.[mv /tmp/crt1.3.1-armv677s.o /Applications/Xcode.app/Contents//Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6. 0.sdk/usr/lib/crt1.3.1.o
Compilez votre projet et vérifiez que votre application contient toutes les arches:
$ file DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app/TestApp DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app/TestApp: Mach-O binaire universel avec 3 architectures DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app/TestApp (pour l'architecture armv6): bras exécutable Mach-O DerivedData/TestApp/Build/Products /Debug-iphoneos/TestApp.app/TestApp (pour l'architecture armv7): bras exécutable Mach-O DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app/TestApp (pour l'architecture cputype (12) cpusubtype (11)): Bras exécutable Mach-O
Notez que le fichier dSYM contient également toutes les arches (utile pour la symbolisation des rapports d'erreur):
$ file DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app.dSYM/Contents/Resources/DWARF/TestApp DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp .app.dSYM/Contents/Resources/DWARF/TestApp: binaire universel Mach-O avec 3 architectures DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app.dSYM/Contents/Resources/DWARF/TestApp (pour l'architecture armv6): bras de fichier compagnon Mach-O dSYM DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app.dSYM/Contents/Resources/DWARF/TestApp (pour l'architecture armv7): Bras du fichier compagnon Mach-O dSYM DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app.dSYM/Contents/Resources/DWARF/TestApp (pour l'architecture cputype (12) cpusubtype (11)): Bras de fichier compagnon Mach-O dSYM
J'ai installé et lancé avec succès l'application sur un iPod touch iOS 4.2 2gen en ouvrant xcode 4.4.1, puis Product
-> Run without building
.
libarclite_iphoneos.a
ou libclang_rt.ios.a
:ld: le fichier est universel (2 tranches) mais ne contient pas a(n) armv6 slice: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain /usr/lib/arc/libarclite_iphoneos.a pour l'architecture armv6
ld: le fichier est universel (2 tranches) mais ne contient pas a(n) armv6 slice: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain /usr/lib/clang/4.1/libclang_rt.ios.a pour l'architecture armv6
La procédure utilisée pour crt1.3.1.o s'applique également à ces fichiers, et corrigera l'erreur permettant à Xcode d'archiver avec succès votre projet: vous pouvez utiliser le chemin imprimé par ld pour trouver le fichier et rejoindre la tranche armv6 avec lipo ; gardez juste à l'esprit que libclang_rt.ios.a dans les versions précédentes de Xcode ne se trouve pas dans Xcode.app/[...]/usr/lib/clang/4.1
mais en Xcode.app/[...]/usr/lib/clang/4.0
.
J'ai archivé le fichier avec succès, l'ai déployé avec un profil de distribution ad hoc et testé sur iPhone 3G (4.2.1) et iPhone 3GS (6.0).
Organizer
, il y a le message: Les appareils de type "iPhone 3G" ne sont pas supportés par cette version de Xcode.Mais un ls
dans le DeviceSupport
indique:
ls /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/ 4,2 4,3 5,0 5,1 6,0 (10A403)
Sans différences dans le répertoire 4.2 de Xcode 4.4.1.
La question est maintenant: comment Xcode détecte-t-il que le périphérique est pris en charge ou non?
Ouverture /Applications/Xcode.app/Contents/Developer//Platforms/iPhoneOS.platform/Developer//Library/PrivateFrameworks/DTDeviceKitBase.framework/DTDeviceKitBase
avec Hex Fiend
(ou un autre éditeur hexadécimal) et en remplaçant ascii 4.3
avec 4.2
fait disparaître le message d'erreur et l'application installée sur l'appareil est répertoriée (mais la puce de l'appareil dans la liste des appareils est toujours rouge).
Ensuite, nous devons modifier /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks//DTDeviceKit.framework/Versions/Current/DTDeviceKit
et remplacer:
Expired.deviceArchitecture.iPhone1,1.iPhone1,2.iPod1,1.iPod2,1.iPod2,2.armv6
à :
Expired.deviceArchitecture.iPhone0,1.iPhone0,2.iPod0,1.iPod0,1.iPod0,2.armv5
Ensuite, nous avons une puce orange dans l'Organisateur (Xcode 4.5.1):
La version d'iOS sur "iPhone" est trop ancienne pour être utilisée avec cette version du SDK iOS. Veuillez restaurer l'appareil dans une version du système d'exploitation répertoriée ci-dessous. Système d'exploitation installé sur l'iPhone 4.2.1 (8C148) Xcode pris en charge Versions iOS 6.0 (10A403) 5.1 5.0 4.3
La question est maintenant: où les versions iOS prises en charge par Xcode sont-elles définies?
Comme il y a un 4.2
répertoire dans /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/
, il devrait déjà être pris en charge ...
J'ai essayé de copier iPhoneOS4.2.sdk
de Xcode 4.4.1 à /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/
, mais cela ne rend pas le périphérique pris en charge.
Je n'ai donc pas trouvé comment ajouter la prise en charge des appareils 4.2 dans Xcode 4.5. Des idées ?
Conclusion: la compilation d'armv6/7/7s dans Xcode 4.5 est possible. Mais il n'est pas possible de démarrer une application sur un appareil armv6 4.2 sans démarrer Xcode 4.4.
Grande mise à jour: cela fonctionne avec Xcode 4.5.2!
Maintenant, la puce est verte dans Xcode 4.5.2 :-) L'appareil apparaît dans la liste déroulante près du bouton Exécuter. Mais lorsque vous essayez d'exécuter l'application, vous obtenez le message:
Xcode ne peut pas s'exécuter à l'aide du périphérique sélectionné. Choisissez une destination avec une architecture prise en charge afin de l'exécuter sur ce périphérique.
Ajoutez simplement armv6 aux architectures valides :-)
Autre remarque: le Build Rule
pour les fichiers source dont les noms correspondent: *.[mc]
peut utiliser LLVM GCC 4.2
ou Apple LLVM compiler 4.1
, ou Default compiler
Merci pour ce script utile!
J'ai réussi à combiner toutes les infos de cet article, le script complet résultant est ci-dessous. Ce script nécessite d'avoir à la fois Xcode 4.5.x et une version précédente de Xcode prenant en charge armv6 (Xcode 4.4.1 par exemple, installé dans/Applications/Xcode 4.4.1.app)
Le script ne nécessite PAS de compiler d'abord dans xcode 4.4.x, il vous suffit de lancer votre dernier Xcode, de sélectionner la configuration Release et de construire. (La configuration de Release-armv6 aurait dû être définie comme mentionné dans le post original de Mike).
Il produira un .app compatible avec armv6 armv7 et armv7s
Merci à Mike pour le script original!
#################
# Configuration #
#################
# Change this to the full path where Xcode 4.4 (or below) puts your armv6 output
setenv ARMV6_OUTPUT_PATH "$BUILD_ROOT/Release-armv6-iphoneos/"
setenv ARMV6_EXECUTABLE_PATH "$ARMV6_OUTPUT_PATH$EXECUTABLE_PATH"
# Your "real" minimum OS version since Xcode 4.5 wants to make it iOS 4.3
# Must be 4.2 or below if you are supporting armv6...
setenv MINIMUM_OS 4.2
#####################
# End configuration #
#####################
# For debugging
echo CURRENT_Arch = $CURRENT_Arch
echo CONFIGURATION = $CONFIGURATION
# Don't need to do this for armv6 (built in older Xcode), simulator (i386), or debug build
#if ("$CURRENT_Arch" == "armv6") exit 0
if ("$CURRENT_Arch" == "i386") exit 0
if ("$CONFIGURATION" != "Release" && "$CONFIGURATION" != "Beta Test") exit 0
# Paths
setenv LIPO_PATH "$CODESIGNING_FOLDER_PATH/${EXECUTABLE_NAME}.lipo"
setenv FINAL_PATH "$CODESIGNING_FOLDER_PATH/$EXECUTABLE_NAME"
setenv FULL_INFO_PLIST_PATH "$CONFIGURATION_BUILD_DIR/$INFOPLIST_PATH"
#log file for armv6 build
echo "------------------------- BUILDING ARMV6 NOW -------------------------"
setenv LOGFILE "$BUILD_ROOT/buildarmv6.txt"
setenv CONFIGURATION_ARMV6 "${CONFIGURATION}-armv6"
#build armv6 version
echo "Building $FULL_PRODUCT_NAME armv6 CONFIG=$CONFIGURATION-armv6 target=$TARGETNAME"
"/Applications/Xcode 4.4.1.app/Contents/Developer/usr/bin/xcodebuild" -project "${PROJECT_FILE_PATH}" -target "${TARGETNAME}" -sdk "${PLATFORM_NAME}" -configuration "$CONFIGURATION-armv6" CONFIGURATION_BUILD_DIR="$ARMV6_OUTPUT_PATH" >> "$LOGFILE"
echo "---------------------------- ARMV6 BUILT -------------------------"
# to check for armv6 build errors
open "$LOGFILE"
# Debug / sanity check
lipo -info "$FINAL_PATH"
ls -l "$ARMV6_EXECUTABLE_PATH"
# Make sure something exists at $LIPO_PATH even if the next command fails
cp -pv "$FINAL_PATH" "$LIPO_PATH"
# If rebuilding without cleaning first, old armv6 might already be there so remove it
# If not, lipo won't output anything (thus the cp command just above)
lipo -remove armv6 -output "$LIPO_PATH" "$FINAL_PATH"
# Add armv6 to the fat binary, show that it worked for debugging, then remove temp file
lipo -create -output "$FINAL_PATH" "$ARMV6_EXECUTABLE_PATH" "$LIPO_PATH"
echo "------------------------- CHECK ARMV6 ARMV7 ARMV7S ARE MENTIONED BELOW -------------------------"
lipo -info "$FINAL_PATH"
echo "------------------------------------------------------------------------------------------------"
rm -f "$LIPO_PATH"
# Change Info.plist to set minimum OS version to 4.2 (instead of 4.3 which Xcode 4.5 wants)
/usr/libexec/PlistBuddy -c "Set :MinimumOSVersion $MINIMUM_OS" "$FULL_INFO_PLIST_PATH"
plutil -convert binary1 "$FULL_INFO_PLIST_PATH"
Merci pour le post. Nous avons quelques applications à créer, nous avons donc automatisé la construction d'armv6 en utilisant xcodebuild comme vous l'avez suggéré. C'est la partie de notre script (modifiée lorsque nous utilisons bash) qui fait cela, qui peut être ajoutée à votre script ci-dessus. Cela pourrait être ajouté avant "# Debug/sanity check"
setenv LOGFILE "/Users/xyz/Desktop/buildarmv6.txt"
setenv CONFIGURATION_ARMV6 "${CONFIGURATION}_armv6"
echo "Building $FULL_PRODUCT_NAME armv6 CONFIG=$CONFIGURATION_ARMV6 target=$TARGETNAME"
"/Applications/Xcode 4.4.1.app/Contents/Developer/usr/bin/xcodebuild" -project "${PROJECT_FILE_PATH}" -target "${TARGETNAME}" -sdk "${PLATFORM_NAME}" -configuration "$CONFIGURATION_ARMV6" >> "$LOGFILE"
echo "Built armv6"
open "$LOGFILE" # to check for armv6 build errors
Je voudrais partager mon expérience avec la réponse de kenji. Je pense que c'est la meilleure et la meilleure façon de créer une application universelle qui fonctionne sur armv6/armv7/armv7s, d'iOS3.1 à iOS7.
Faites exactement comme le suggère le kenji. Vous pouvez ignorer les parties concernant l'archivage du produit, principalement si vous envoyez votre application à Apple via Application Loader (zippé).
Quelques conseils supplémentaires:
Lorsque vous construisez pour la configuration "distribution", xcode validera le produit et vous obtiendrez deux avertissements:
Bien sûr, parce que vous construisez réellement pour armv6 et que vous définissez la cible de déploiement sur 3.1 ou 4.2, par exemple!
Alors ... ignorez simplement ces avertissements.
Après avoir envoyé votre application à iTunes Connect, vous recevrez un e-mail d'avertissement d'Apple, vous indiquant que votre application n'est pas "Position Independent Executable". Bien sûr, encore une fois, c'est parce que votre objectif est inférieur à 4,3. Ignorez simplement cet avertissement.
À cette date (03 juillet 2013), j'ai réussi à mettre à jour une application vers l'appstore avec cette méthode, et elle a passé la validation. La cible de déploiement d'application est iOS 3.1.2 et prend en charge armv6-armv7-armv7s.
Je voudrais également dire que:
Merci à Mike pour ce tutoriel et ce script utiles. Comme mentionné par Piotr dans les commentaires, le script échoue si vous exécutez la commande archive à partir de Xcode car il utilise un autre répertoire de construction pour l'archivage.
Voici ci-dessous ma modification du script pour l'activer à la fois pour la version normale et la version spécifique à l'archive.
Il suppose que la version armv6 est exécutée avant selon les instructions originales de Mike. Il utilise la syntaxe bash car il est plus facile pour moi de supprimer le répertoire de construction de base commun. Cela implique donc la traduction du script d'origine en bash qui consiste uniquement à remplacer setenv par l'exportation et à modifier la syntaxe des instructions if.
# Find the common base directory for both build
XCODE_BUILD=${BUILD_ROOT%%/Build*}
# Change this to the full path where Xcode 4.4 (or below) puts your armv6 output, using the previously derived base
export ARMV6_EXECUTABLE_PATH="$XCODE_BUILD/Build/Products/Release_armv6-iphoneos/$EXECUTABLE_PATH"
Apple a cessé d'accepter les versions prenant en charge les appareils pré iOS5 et contenant une image de lancement de l'iPhone 5. Voici l'e-mail de la dernière version que j'ai soumise qui a été construite sur Xcode 4.4.1
Cher développeur,
Nous avons découvert un ou plusieurs problèmes avec votre livraison récente pour "". Pour traiter votre livraison, les problèmes suivants doivent être corrigés:
Image de lancement non valide - Votre application contient une image de lancement avec un modificateur de taille qui n'est pris en charge que pour les applications créées avec le SDK iOS 6.0 ou version ultérieure.
Une fois ces problèmes corrigés, accédez à la page Détails de la version et cliquez sur "Prêt à télécharger le binaire". Continuez le processus de soumission jusqu'à ce que l'état de l'application soit "En attente de téléchargement". Vous pouvez ensuite livrer le binaire corrigé.
Cordialement,
L'équipe App Store