Как поддержать и armv6 и armv7s для сборки выпуска в xcode 4.5

Я знаю, что это невозможно, и Apple планировала это таким образом, чтобы заставить пользователей обновить свои устройства. Но я просто хочу знать, есть ли какой-нибудь обходной путь или хаки, способные сделать это? Клиент настаивает на том, что мы все еще должны поддерживать armv6 из-за все еще "большого" процента пользователей приложения.

Я знаю команду под названием lipo объединить статические библиотеки, и я где-то читал, что мы также можем использовать его для объединения файлов ipa, но я не уверен, как именно это делается. Я уже несколько раз искал в Google и на этом сайте, но трудно найти конкретный ответ.

7 ответов

Решение

Я смог сделать это успешно с моим приложением, которое находится в App Store. Он поддерживает версии armv6, armv7, armv7s и iOS от 4.2 до 6.0. Я проверял, что он работает на старых устройствах (iPhone 3G, iPod touch 2g) на всем протяжении iPhone 5.

Этот метод требует одновременной установки Xcode 4.5 и более старой версии Xcode. Я все еще на 4.3.2 для моей старой версии, но 4.4 также должна работать.

У меня были скриншоты для этого ответа, но Stack Overflow не позволяет мне публиковать их, потому что я новичок.:(

Настройка в Xcode 4.5

  1. Добавьте новую конфигурацию сборки для вашей сборки armv6. Я продублировал конфигурацию выпуска и назвал ее Release_armv6.

  2. Установите Архитектуры и Действительные архитектуры для ваших конфигураций сборки. Для всех, кроме Release_armv6, используйте значение по умолчанию. Для Release_armv6 вручную установите его на armv6.

  3. Если вы используете функции iOS 6, которые Xcode 4.4 и ниже не поймут, вам нужно #ifdef использовать их для сборки armv6. В настройках сборки в разделе "Другие флаги C и другие флаги C++" я добавил -DARMV6_ONLY в свою конфигурацию Release_armv6. Затем, где бы код ни использовал новый API iOS 6, я делаю что-то вроде #ifndef ARMV6_ONLY / #endif в зависимости от ситуации.

  4. Добавьте новую схему и настройте ее на использование конфигурации сборки Release_armv6 во всех случаях.

  5. В разделе "Этапы сборки" добавьте этап создания сценария запуска с помощью следующего сценария (установите для командной консоли значение / bin / csh). Вот где происходит волшебство. Отредактируйте раздел "Конфигурация": определите полный путь к сборке Release_armv6 и замените его на ARMV6_EXECUTABLE_PATH. Также установите 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"

Процесс сборки

Когда вы будете готовы создать сборку релиза, сделайте это в следующем порядке:

  1. Закройте Xcode 4.5 и откройте Xcode 4.4 или ниже. Выберите схему armv6 и постройте ее.

  2. Закройте Xcode 4.4 или ниже и откройте Xcode 4.5. Выберите схему выпуска и постройте ее.

Вот и все. Проверьте выходные данные сборки, чтобы убедиться, что вы получили то, что хотите - исполняемый файл с тремя архитектурами. Последний вывод из скрипта запуска должен сообщить вам об этом.

Если у кого-то есть идеи по улучшению этого, пожалуйста, не стесняйтесь. Я полагаю, что вы можете быть в моде и вызывать команду "xcodebuild" в Xcode 4.4 из скрипта сборки, избавляя от необходимости вообще переключаться между версиями Xcode. Но это работает достаточно хорошо для меня.;)

Предостережения:

  • Просто чтобы быть в безопасности, вы можете отредактировать ваши файлы XIB в более старой версии XCode. До сих пор кажется, что 4.5 обратно совместимо, но вы никогда не знаете.

  • На самом деле, вы можете рассмотреть возможность выполнения большей части своей разработки, за исключением специфических для iOS 6 вещей, в более старом Xcode. Зависит от того, что легче для вас.

Существует еще один способ, поскольку gcc-4.2 по-прежнему поддерживает armv6, который не требует закрытия Xcode 4.5 и открытия предыдущей версии (для компиляции, но не для запуска приложения на устройстве 4.2):

  • Добавьте armv6 как к действительным аркам, так и к аркам:

Archs: $ (ARCHS_STANDARD_32_BIT) armv6

Действительные архитектуры: armv6 armv7 armv7s

  • Vim (или TextEdit) ваш файл project.pbxproj для замены IPHONEOS_DEPLOYMENT_TARGET на 4.0 - 4.1 - 4.2, как вам нужно, Xcode 4.5 не позволит вам опуститься ниже 4.3.

Затем, если вы создадите свой проект, вы увидите предупреждения:

предупреждение: нет правила для обработки файла '$(PROJECT_DIR)/App/AppDelegate.m' типа sourcecode.c.objc для архитектуры armv6
предупреждение: нет правила для обработки файла '$(PROJECT_DIR)/App/SomeFile.c' типа sourcecode.cc для архитектуры armv6
  • Добавить Build Rule для исходных файлов с совпадающими именами: *.[mc] что будет использовать LLVM GCC 4.2

Это работает для статических библиотек, но не для приложений:

ld: файл универсален (4 слайса), но не содержит (n) слайса armv6: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/usr/lib/crt1.3.1.o для архитектуры armv6
  • Чтобы заставить его работать для приложений, нам нужно добавить кусочек armv6 в этот объектный файл (который поставляется с 5.1 SDK):
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 -output / 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
mv /Applications/Xcode.app/Contents//Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/usr/lib/crt1.3.1.o /Applications/Xcode.app/Contents//Developer/ Платформы / iPhoneOS.platform / Разработчик / SDKs / iPhoneOS6.0.sdk / USR / Библиотека /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

Скомпилируйте ваш проект и убедитесь, что ваше приложение содержит все арки:

$ file DerivedData / TestApp / Build / Products / Debug-iphoneos / TestApp.app / TestApp 
DerivedData / TestApp / Build / Продукты /Debug-iphoneos/TestApp.app/TestApp: универсальный двоичный файл Mach-O с 3 архитектурами
DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app/TestApp (для архитектуры armv6): исполняемый файл Mach-O
DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app/TestApp (для архитектуры armv7): исполняемый файл Mach-O
DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app/TestApp (для архитектуры cutype (12) cpusubtype (11)): исполняемый манипулятор Mach-O

Обратите внимание, что файл dSYM также содержит все арки (полезно для обозначения отчета о сбое):

$ file DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app.dSYM/ Содержание / Ресурсы /DWARF/TestApp 
DerivedData/TestApp/Build/ Продукты /Debug-iphoneos/TestApp.app.dSYM/ Содержание / Ресурсы /DWARF/TestApp: универсальный двоичный файл Mach-O с 3 архитектурами
DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app.dSYM/ Содержание / Ресурсы /DWARF/TestApp (для архитектуры armv6): файл-компаньон Mach-O dSYM
DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app.dSYM/ Содержание / Ресурсы /DWARF/TestApp (для архитектуры armv7): файл-компаньон Mach-O dSYM
DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app.dSYM/ Содержание / Ресурсы /DWARF/TestApp (для архитектуры cutype (12) cpusubtype (11)): файл-компаньон Mach-O dSYM

Я успешно установил и запустил приложение на iPod touch на iOS 4.2 2gen, открыв xcode 4.4.1, затем Product -> Run without building,

  • При архивировании вашего продукта вы можете снова столкнуться с ошибкой Apple Mach-O Linker, на этот раз с другими файлами, такими как libarclite_iphoneos.a или же libclang_rt.ios.a:
ld: файл универсальный (2 среза), но не содержит (n) среза armv6: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphoneos.a для архитектуры armv6
ld: файл универсальный (2 слайса), но не содержит (n) слайса armv6: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/4.1/libclang_rt.ios.a для архитектуры armv6

Процедура, используемая для crt1.3.1.o, также применима к этим файлам и исправит ошибку, позволяющую Xcode успешно заархивировать ваш проект: вы можете использовать путь, напечатанный ld, чтобы найти файл и присоединить фрагмент armv6 с помощью lipo; просто имейте в виду, что libclang_rt.ios.a в предыдущих версиях Xcode не находится в Xcode.app/[...]/usr/lib/clang/4.1 но в Xcode.app/[...]/usr/lib/clang/4.0,

Я успешно заархивировал файл, развернул его со специальным профилем распространения и протестировал на iPhone 3G (4.2.1) и iPhone 3GS (6.0).

  • Последняя проблема: мы не можем запустить приложение. в Organizer, появляется сообщение: Устройства типа "iPhone 3G" не поддерживаются этой версией Xcode.

Но ls в DeviceSupport показывает:

 ls /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/ 
4,2          4,3          5,0          5,1          6,0 (10A403)

Без различий в каталоге 4.2 от Xcode 4.4.1.

Теперь вопрос: как Xcode Detect поддерживает устройство или нет?

открытие /Applications/Xcode.app/Contents/Developer//Platforms/iPhoneOS.platform/Developer//Library/PrivateFrameworks/DTDeviceKitBase.framework/DTDeviceKitBase с Hex Fiend (или другой шестнадцатеричный редактор) и замена ascii 4.3 с 4.2 сделать так, чтобы сообщение об ошибке исчезло, и приложение, установленное на устройстве, появилось в списке (но маркер устройства в списке устройств все еще красный).

Тогда нам нужно отредактировать /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks//DTDeviceKit.framework/Versions/Current/DTDeviceKit и заменить:

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

Затем у нас есть оранжевая пуля в Организаторе (Xcode 4.5.1):

Версия iOS на "iPhone" устарела для использования с этой версией iOS SDK. Пожалуйста, восстановите устройство до версии ОС, указанной ниже.

ОС установлена ​​на iPhone
4.2.1 (8C148)

Xcode Поддерживаемые версии iOS
6,0 (10А403)
5,1
5.0
4,3

Теперь вопрос: где определены поддерживаемые версии Xcode iOS?

Как есть 4.2 каталог в /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/, это уже должно быть поддержано...

Пытался скопировать iPhoneOS4.2.sdk из Xcode 4.4.1 в /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/, но это не делает устройство поддерживаемым.

Так что не нашел, как добавить поддержку устройства 4.2 в Xcode 4.5. Есть идеи?

Вывод: возможна компиляция для armv6/7/7s в Xcode 4.5. Но невозможно запустить приложение на устройстве 4.2 armv6 без запуска Xcode 4.4.

Большое обновление: это работает с Xcode 4.5.2!

Теперь маркер зеленого цвета в Xcode 4.5.2:-) Устройство появляется в выпадающем списке рядом с кнопкой Run. Но при попытке запустить приложение получило сообщение:

XCode не может работать с использованием выбранного устройства.
Выберите пункт назначения с поддерживаемой архитектурой для запуска на этом устройстве.

Просто добавьте armv6 к действующим архитектурам:-)

Другое примечание: Build Rule для исходных файлов с совпадающими именами: *.[mc] можешь использовать LLVM GCC 4.2 или же Apple LLVM compiler 4.1, или же Default compiler

Спасибо за этот полезный скрипт!

Я успешно объединил всю информацию из всего этого поста, полученный полный скрипт приведен ниже. Для этого сценария требуется наличие Xcode 4.5.x и предыдущей версии Xcode, поддерживающей armv6 (например, Xcode 4.4.1, установленный в /Applications/Xcode 4.4.1.app)

Скрипт НЕ требует первой компиляции в xcode 4.4.x, вам просто нужно запустить ваш последний Xcode, выбрать конфигурацию Release и построить. (Конфигурация Release-armv6 должна была быть определена так, как указано в исходном посте Майка).

Он будет производить.app совместимый с armv6 armv7 и armv7s

Спасибо Майку за оригинальный сценарий!

#################
# 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"

Спасибо за пост. У нас есть несколько приложений для сборки, поэтому мы автоматизировали сборку armv6 с помощью xcodebuild, как вы и предлагали. Это та часть нашего скрипта (модифицированная, когда мы используем bash), которая делает это, которую можно добавить в ваш скрипт выше. Это может быть добавлено перед "# 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

Я хотел бы поделиться своим опытом с ответом Кендзи. Я думаю, что это лучший и лучший способ создать универсальное приложение, которое работает на armv6 / armv7 / armv7s, от iOS3.1 до iOS7.

Просто делай так, как предлагает Кендзи. Вы можете игнорировать части об архивации продукта, особенно если вы отправляете свое приложение в Apple через Application Loader (zip).

Еще несколько советов:

Когда вы создаете конфигурацию для "распространения", xcode проверит продукт, и вы получите два предупреждения:

  • "архитектура armv6 не поддерживается..."
  • msgstr "Цели развертывания iOS ниже 4.3 не поддерживаются...".

Конечно, потому что вы на самом деле строите для armv6 и устанавливаете цель развертывания, например, 3.1 или 4.2!

Так что... просто игнорируйте эти предупреждения.

После отправки вашего приложения на itunes connect вы получите электронное письмо с предупреждением от Apple, в котором говорится, что ваше приложение не является "Независимым от позиции исполняемым файлом". Конечно, это потому, что ваша цель ниже 4,3. Просто игнорируйте это предупреждение.

На эту дату (2013 июл 03) я успешно обновил приложение до магазина приложений с помощью этого метода, и оно прошло проверку. Цель развертывания приложения - iOS 3.1.2, и она поддерживает armv6-armv7-armv7s.

Я хотел бы также сказать, что:

  • Если вы создаете новое приложение, просто установите цель развертывания на iOS6 или iOS5. Игнорировать старую ОС.
  • Если у вас есть старое приложение, продаваемое с 2010 года, с десятками тысяч пользователей, на самом деле у вас может быть гораздо больше людей, которые используют его на armv6, чем обычно говорит Apple. Я думаю, что 3 года - слишком короткий период, чтобы отказаться от поддержки этих старых устройств, особенно если ваше приложение МОЖЕТ работать на них.

Спасибо Майку за этот полезный урок и скрипт. Как упоминал Петр в комментариях, сценарий завершается ошибкой, если вы запускаете команду архивирования из XCode, поскольку он использует другой каталог сборки для архивирования.

Здесь ниже моя модификация скрипта, чтобы включить его как для нормальной сборки релиза, так и для конкретной сборки архива.

Предполагается, что сборка armv6 запускается раньше, в соответствии с оригинальными инструкциями Майка. Он использует синтаксис bash, потому что мне проще удалить общий базовый каталог сборки. Таким образом, это подразумевает перевод оригинального скрипта на bash, который заключается только в замене setenv на экспорт и изменении синтаксиса операторов 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 прекратила принимать сборки, которые поддерживают устройства до iOS5 и содержат образ запуска iPhone 5. Вот электронная почта для последней представленной мной сборки, которая была построена на Xcode 4.4.1

Уважаемый разработчик,

Мы обнаружили одну или несколько проблем с вашей недавней доставкой для "". Для обработки вашей доставки необходимо исправить следующие проблемы:

Неверное начальное изображение - Ваше приложение содержит начальное изображение с модификатором размера, которое поддерживается только для приложений, созданных с помощью iOS 6.0 SDK или более поздней версии.

После устранения этих проблем перейдите на страницу сведений о версии и нажмите "Готово к загрузке двоичного файла". Продолжайте процесс отправки, пока приложение не получит статус "Ожидание загрузки". Затем вы можете доставить исправленный двоичный файл.

С Уважением,

Команда App Store

Другие вопросы по тегам