如何在xcode 4.5中同时支持armv6和armv7版本



我知道这是不可能的,苹果计划用这种方式迫使用户升级他们的设备。但我只想知道是否有一些变通方法或技巧可以做到这一点?客户端坚持我们仍然应该支持armv6,因为应用程序用户的比例仍然"很大"。

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

我已经能够用应用商店中的应用程序成功地做到这一点。它支持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,手动将其设置为armv6。https://i.stack.imgur.com/h8Mpl.png

  3. 如果你使用的是Xcode 4.4及以下版本无法理解的iOS 6功能,你需要为你的armv6版本#ifdef这些功能。在"其他C标志"one_answers"其他C++标志"下的"构建设置"中,我将-DAMV6_ONLY添加到Release_armv6配置中。然后,无论代码在哪里使用新的iOS 6 API,我都会适当地执行#ifndef ARMV6_ONLY/#endif之类的操作。https://i.stack.imgur.com/czF6J.png

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

  5. 在"构建阶段"下,添加带有以下脚本的"运行脚本构建阶段"(将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特定的东西。取决于对你来说最简单的。

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

  • 将armv6添加到有效的archs和archs:

Archs:$(Archs_STANDARD_32_BIT)armv6

有效架构:armv6 armv7 armv7s

  • Vim(或TextEdit)您的项目.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.c.c类型的文件"$(PROJECT_DIR)/App/SomeFile.c">
  • 为名称匹配的源文件添加Build Rule:将使用LLVM GCC 4.2*.[mc]

它适用于静态库,但不适用于应用程序:

ld:file是通用的(4个切片),但不包含(n)armv6切片:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Develer/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/DDeveloper/SDKs/iPhoneOS5.1.sdk/usr/lib/crt1.3.1.o-提取armv6-输出/tmp/crt1.3.1-armv6.olipo/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/crt 1.3.1-armv677s.omv/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DDeveloper/sdk/iPhoneOS6.0.sdk/usr/lib/crt1.3.1.o/Applications/Xcode.app/Contents/Developer/Platorms/iPhoneOS/platform/Driver/SDKs/iPhoneOS6.0.dk/usr/lib/crt1.3.1.o.bkpmv/tmp/crt1.3.1-armv677s.o/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Develer/SDKs/iPhoneOS6.0.sdk/usr/lib/crt1.3.1.o

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

$file DerivedData/TestApp/Build/Products/Debug iphoneos/TestApp.app/TestAppDerivedData/TestApp/Build/Products/Debug iphoneos/TestApp.app/TestApp:Mach-O通用二进制,具有3种架构DerivedData/TestApp/Build/Products/Debug iphoneos/TestApp.app/TestApp(用于体系结构armv6):Mach-O可执行armDerivedData/TestApp/Build/Products/Debug iphoneos/TestApp.app/TestApp(适用于架构armv7):Mach-O可执行armDerivedData/TestApp/Build/Products/Debug iphoneos/TestApp.app/TestApp(用于体系结构cputype(12)cpusubtype(11)):Mach-O可执行臂

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

$file DerivedData/TestApp/Build/Products/Debug iphoneos/TestApp.app.dSYM/Contents/Resources/DWARF/TestAppDerivedData/TestApp/Build/Products/Debug iphoneos/TestApp.app.dSYM/Contents/Resources/DWARF/TestApp:Mach-O通用二进制,具有3种架构DerivedData/TestApp/Build/Products/Debug iphoneos/TestApp.app.dSYM/Contents/Resources/DWARF/TestApp(用于体系结构armv6):Mach-O dSYM配套文件armDerivedData/TestApp/Build/Products/Debug iphoneos/TestApp.app.dSYM/Contents/Resources/DWARF/TestApp(用于体系结构armv7):Mach-O dSYM配套文件armDerivedData/TestApp/Build/Products/Debug iphoneos/TestApp.app.dSYM/Contents/Resources/DWARF/TestApp(用于体系结构cputype(12)cpusubtype(11)):Mach-O dSYM配套文件arm

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

  • 当您归档您的产品时,您可能会再次遇到Apple Mach-O Linker错误,这次涉及其他文件,如libarclite_iphoneos.alibclang_rt.ios.a
ld:file是通用的(2个切片),但不包含(n)armv6切片:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/ac/libarclite_iphoneos.a对于体系结构armv6
ld:file为通用的(两个切片)但不包括(n)armv6切片:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/crang/4.1/libcrang_rt.ios.a for architecture armv6

用于crt11.3.1.o的过程也适用于这些文件,并将修复允许Xcode成功存档您的项目的错误:您可以使用ld打印的路径查找文件,并使用lipo连接armv6切片;请记住,以前版本的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"类型的设备

但是DeviceSupport中的ls显示:

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检测设备是否支持?

Hex Fiend(或另一个十六进制编辑器)打开/Applications/Xcode.app/Contents/Developer//Platforms/iPhoneOS.platform/Developer//Library/PrivateFrameworks/DTDeviceKitBase.framework/DTDeviceKitBase,用4.2替换ascii4.3,会使错误消息消失,并列出设备上安装的应用程序(但设备列表中的设备项目符号仍然为红色)。

然后我们需要编辑/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.154.3

现在的问题是:Xcode支持的iOS版本在哪里定义?

由于/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/中有一个4.2目录,应该已经支持了。。。

尝试将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中的项目符号为绿色:-)该设备显示在"运行"按钮附近的下拉列表中。但当尝试运行该应用程序时,得到了消息:

Xcode无法使用所选设备运行。选择一个具有支持体系结构的目标以便在此设备上运行

只需将armv6添加到有效的体系结构中:-)

其他注意:名称匹配的源文件的Build Rule*.[mc]可以使用LLVM GCC 4.2Apple LLVM compiler 4.1,或Default compiler

感谢您提供这个有用的脚本!

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

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

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

感谢迈克的原创剧本!

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

感谢您的帖子。我们有一些应用程序需要构建,所以我们按照您的建议使用xcodebuild自动构建armv6。这是我们的脚本中执行此操作的部分(在使用bash时进行了修改),可以添加到上面的脚本中。这可以在"#调试/健全性检查"之前添加

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

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

下面是我对脚本的修改,使其既适用于普通版本构建,也适用于归档特定构建。

它假设armv6构建之前是按照Mike的原始指令运行的。它使用bash语法,因为我更容易去掉公共的基本构建目录。因此,这意味着将原始脚本转换为bash,这只是通过导出和更改if语句语法来替换setenv的问题。

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

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

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

更多建议:

当您为"分布式"配置构建时,xcode将验证产品,您将收到两个警告:

  • "不支持体系结构armv6…">
  • "不支持低于4.3的iOS部署目标…">

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

所以。。。忽略这些警告。

将你的应用程序发送到itunes connect后,你会收到苹果公司的警告电子邮件,称你的应用不是"职位独立可执行程序"。当然,这也是因为你的目标低于4.3。忽略这个警告。

在这个日期(2013年7月3日),我已经用这个方法成功地将一个应用程序更新到了应用商店,并且它已经通过了验证。应用程序部署目标是iOS 3.1.2,它支持armv6-armv7-armv7s。

我还想说:

  • 如果你制作了一个全新的应用程序,只需将部署目标设置为iOS6或iOS5即可。忽略旧操作系统
  • 如果你有一款自2010年以来销售的旧应用程序,拥有数万用户,那么在armv6上使用它的人实际上可能比苹果通常说的要多得多。我认为3年时间太短,不能放弃对这些旧设备的支持,主要是如果你的应用程序可以在它们上运行的话

苹果已经停止接受支持iOS5之前的设备并包含iPhone 5发布图像的构建。这是我提交的最后一个构建的电子邮件,它是在Xcode 4.4.1 上构建的

尊敬的开发人员,

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

无效的启动映像-您的应用程序包含一个带有大小修改器的启动映像,该大小修改器仅适用于使用iOS 6.0 SDK或更高版本构建的应用程序。

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

问候,

应用商店团队

最新更新