53

我知道这是不可能的,Apple 计划这样做是为了迫使用户升级他们的设备。但我只想知道是否有一些解决方法或黑客能够做到这一点?客户坚持认为我们仍然应该支持 armv6,因为应用程序用户的比例仍然“很大”。

我知道一个名为lipo合并静态库的命令,我在某处读到我们也可以使用它来合并 ipa 文件,但我不确定它是如何完成的。我已经在谷歌和这个网站上进行了几次搜索,但很难找到具体的答案。

4

7 回答 7

93

我已经能够使用 App Store 中的应用成功地做到这一点。它支持 armv6、armv7 和 armv7s 以及从 4.2 到 6.0 的 iOS 版本。我已经验证它可以在旧设备(iPhone 3G、iPod touch 2g)上一直运行到 iPhone 5。

此方法需要同时安装 Xcode 4.5 和旧版本的 Xcode。对于我的旧版本,我仍在使用 4.3.2,但 4.4 应该也可以工作。

我有这个答案的截图,但 Stack Overflow 不允许我发布它们,因为我是新手。:(

Xcode 4.5 中的设置

  1. 为您的 armv6 构建添加新的构建配置。我复制了 Release 配置并将其命名为 Release_armv6。

  2. 为您的构建配置设置架构和有效架构。对于除 Release_armv6 之外的所有版本,使用默认值。对于 Release_armv6,手动将其设置为armv6http://i.stack.imgur.com/h8Mpl.png

  3. 如果您正在使用 Xcode 4.4 及更低版本无法理解的 iOS 6 功能,则需要为您的 armv6 构建#ifdef 这些功能。在其他 C 标志和其他 C++ 标志下的构建设置中,我将-DARMV6_ONLY添加到了我的 Release_armv6 配置中。然后,无论代码使用新的 iOS 6 API,我都会根据需要执行 #ifndef ARMV6_ONLY / #endif 之类的操作。 http://i.stack.imgur.com/czF6J.png

  4. 添加一个新方案并将其设置为在所有情况下都使用 Release_armv6 构建配置。

  5. 在 Build Phases 下,使用以下脚本添加 Run Script Build Phase(将 Shell 设置为/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。选择您的发布方案并构建它。

差不多就是这样。检查构建输出以验证您是否得到了您想要的 - 一个包含三个体系结构的可执行文件。运行脚本的最后一个输出应该告诉你这一点。

如果有人有改进的想法,请随意。我想你可能会喜欢并从构建脚本中调用 Xcode 4.4 的“xcodebuild”命令,从而完全减轻在 Xcode 版本之间切换的需要。但这对我来说已经足够好了。;)

注意事项:

  • 为了安全起见,您可能希望在旧版本的 Xcode 中编辑您的 xib 文件。到目前为止,4.5 似乎是向后兼容的,但你永远不知道。

  • 事实上,您可能会考虑只在较旧的 Xcode 中进行大部分开发,除了 iOS 6 特定的东西。取决于对您来说最简单的方法。

于 2012-10-01T17:29:05.223 回答
26

还有另一种方式,因为 gcc-4.2 仍然支持 armv6,它不需要您关闭 Xcode 4.5 并打开以前的版本(用于编译,但不适用于在 4.2 设备上运行应用程序):

  • 将 armv6 添加到有效的拱门和拱门:

拱门:$(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。

然后,如果您构建项目,您将看到警告:

警告:没有规则为架构 armv6 处理 sourcecode.c.objc 类型的文件“$(PROJECT_DIR)/App/AppDelegate.m”
警告:没有规则为架构 armv6 处理 sourcecode.cc 类型的文件 '$(PROJECT_DIR)/App/SomeFile.c'
  • 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 -输出/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/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

编译您的项目并检查您的应用程序是否包含所有拱门:

$ 文件 DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app/TestApp
DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app/TestApp:具有 3 种架构的 Mach-O 通用二进制文件
DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app/TestApp(用于架构 armv6):Mach-O 可执行 arm
DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app/TestApp(用于架构 armv7):Mach-O 可执行 arm
DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app/TestApp(用于架构 cputype (12) cpusubtype (11)):Mach-O 可执行 arm

请注意,dSYM 文件还包含所有拱门(用于崩溃报告符号化):

$ 文件 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:具有 3 种架构的 Mach-O 通用二进制文件
DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app.dSYM/Contents/Resources/DWARF/TestApp(用于架构 armv6):Mach-O dSYM 配套文件 arm
DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app.dSYM/Contents/Resources/DWARF/TestApp(用于架构 armv7):Mach-O dSYM 配套文件 arm
DerivedData/TestApp/Build/Products/Debug-iphoneos/TestApp.app.dSYM/Contents/Resources/DWARF/TestApp(用于架构cputype(12)cpusubtype(11)):Mach-O dSYM配套文件arm

Product我通过打开 xcode 4.4.1,然后->成功地在 iOS 4.2 2gen iPod touch 上安装并启动了该应用程序Run without building

  • 当您存档您的产品时,您可能会再次遇到 Apple Mach-O 链接器错误,这一次涉及其他文件,例如libarclite_iphoneos.alibclang_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连接;请记住,以前版本的 Xcode 中的 libclang_rt.ios.a 不是位于,Xcode.app/[...]/usr/lib/clang/4.1而是位于Xcode.app/[...]/usr/lib/clang/4.0.

我已成功归档文件,使用临时分发配置文件部署它,并在 iPhone 3G (4.2.1) 和 iPhone 3GS (6.0) 上进行了测试。

  • 最后一个问题:我们无法启动应用程序。在 中Organizer,有消息:此版本的 Xcode 不支持“iPhone 3G”类型的设备。

但是lsDeviceSupport节目中:

ls /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/
4.2 4.3 5.0 5.1 6.0 (10A403)

Xcode 4.4.1 的 4.2 目录中没有差异。

现在的问题是:Xcode 如何检测设备是否受支持?

/Applications/Xcode.app/Contents/Developer//Platforms/iPhoneOS.platform/Developer//Library/PrivateFrameworks/DTDeviceKitBase.framework/DTDeviceKitBase使用(或其他十六进制编辑器)打开Hex Fiend,并将 ascii 替换4.34.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

然后我们在 Organizer (Xcode 4.5.1) 中有一个橙色的子弹:

“iPhone”上的 iOS 版本太旧,无法与此版本的 iOS SDK 一起使用。请将设备恢复到下列操作系统版本。

安装在 iPhone 上的操作系统
4.2.1 (8C148)

Xcode 支持的 iOS 版本
6.0 (10A403)
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/,但它不支持设备。

所以还没有找到如何在 Xcode 4.5 中添加 4.2 设备支持。有任何想法吗 ?

结论:在 Xcode 4.5 中编译 armv6/7/7s 是可能的。但是如果不启动 Xcode 4.4,就无法在 4.2 armv6 设备上启动应用程序。

大更新:它适用于 Xcode 4.5.2!

现在项目符号在 Xcode 4.5.2 中是绿色的 :-) 该设备出现在 Run 按钮附近的下拉列表中。但是在尝试运行该应用程序时,收到消息:

Xcode 无法使用所选设备运行。
选择具有受支持架构的目标,以便在此设备上运行。

只需将 armv6 添加到有效架构中:-)

其他说明:Build Rule对于名称匹配的源文件:*.[mc]可以使用LLVM GCC 4.2or Apple LLVM compiler 4.1, orDefault compiler

于 2012-10-11T09:50:52.427 回答
7

感谢这个有用的脚本!

我成功地结合了整篇文章中的所有信息,生成的完整脚本如下。此脚本需要 Xcode 4.5.x 和支持 armv6 的先前 Xcode 版本(例如 Xcode 4.4.1,安装在 /Applications/Xcode 4.4.1.app 中)

该脚本不需要在 xcode 4.4.x 中首先编译,您只需启动最新的 Xcode,选择发布配置并构建。(Release-armv6 配置应该像 Mike 的原始帖子中提到的那样定义)。

它将生成与 armv6 armv7 和 armv7s 兼容的 .app

感谢 Mike 的原始脚本!

#################
# 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"
于 2012-11-23T12:23:11.737 回答
4

谢谢你的帖子。我们有一些应用程序要构建,因此我们按照您的建议使用 xcodebuild 自动化了 armv6 构建。这是执行此操作的脚本的一部分(在我们使用 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
于 2012-10-17T00:58:49.223 回答
3

感谢 Mike 提供了这个有用的教程和脚本。正如 Piotr 在评论中提到的,如果您从 Xcode 运行归档命令,脚本将失败,因为它使用另一个构建目录进行归档。

下面是我对脚本的修改,以使其适用于正常发布构建和存档特定构建​​。

它假定 armv6 构建之前按照 Mike 的原始指令运行。它使用 bash 语法,因为我更容易剥离公共基础构建目录。因此,这意味着将原始脚本转换为 bash,这只是通过 export 替换 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"
于 2012-10-30T23:50:43.167 回答
3

我想与kenji的回答分享我的经验。我认为这是构建在 armv6 / armv7 / armv7s 上运行的通用应用程序的最佳方法,从 iOS3.1 到 iOS7。

完全按照kenji的建议去做。您可能会忽略有关归档产品的部分,主要是如果您通过应用程序加载器(压缩)将您的应用程序发送到苹果。

更多建议:

当您为“分发”配置构建时,xcode 将验证产品,您将收到两个警告:

  • “不支持架构 armv6..​​.”
  • “不支持低于 4.3 的 iOS 部署目标......”。

当然,因为您实际上是为 armv6 构建的,并且您将部署目标设置为 3.1 或 4.2,例如!

所以......只是忽略这些警告。

将您的应用程序发送到 iTunes Connect 后,您会收到一封来自 Apple 的警告电子邮件,说您的应用程序不是“Position Independent Executable”。当然,再次,这是因为你的目标低于 4.3。忽略这个警告。

在此日期(2013 年 7 月 3 日),我已使用此方法成功将应用更新到应用商店,并且已通过验证。应用部署目标为 iOS 3.1.2,支持 armv6-armv7-armv7s。

我还想说:

  • 如果您制作一个全新的应用程序,只需将部署目标设置为 iOS6 或 iOS5。忽略旧操作系统。
  • 如果你有一个自 2010 年以来销售的旧应用程序,拥有成千上万的用户,那么实际上在 armv6 上使用它的人可能比苹果通常说的要多得多。我认为 3 年对于放弃对这些旧设备的支持来说太短了,主要是如果您的应用程序可以在它们上运行。
于 2013-07-04T08:14:30.450 回答
1

Apple 已停止接受支持 iOS5 之前的设备并包含 iPhone 5 启动图像的版本。这是我提交的基于 Xcode 4.4.1 构建的最后一个构建的电子邮件

亲爱的开发者,

我们发现您最近交付的“”存在一个或多个问题。要处理您的交付,必须更正以下问题:

无效的启动图像 - 您的应用包含一个带有大小修饰符的启动图像,仅支持使用 iOS 6.0 SDK 或更高版本构建的应用。

更正这些问题后,请转到“版本详细信息”页面并单击“准备上传二进制文件”。继续完成提交过程,直到应用状态为“等待上传”。然后,您可以提供更正后的二进制文件。

问候,

应用商店团队

于 2013-02-17T14:27:46.840 回答