提交到应用商店问题:不支持的架构 x86

286

我试图使用Shopify API,当我归档并验证该应用程序时,没有问题,但是当我将其提交到应用商店时,会出现以下问题:

  1. ERROR ITMS-90087:"不支持的架构。您的可执行文件包含不受支持的架构 '[x86_64, i386]'."
  2. ERROR ITMS-90209:"无效的段对齐。SJAPP.app/Frameworks/Buy.framework/Buy处的应用程序二进制文件没有正确的段对齐。尝试使用最新版本的Xcode重新构建应用程序。”(我已经在使用最新版本了。)
  3. ERROR ITMS-90125:"二进制文件无效。 LC_ENCRYPTION_INFO加载命令中的加密信息丢失或无效,或者二进制文件已经加密。此二进制文件似乎没有使用苹果的链接器构建。
  4. WARNING ITMS-90080:"可执行负载/..../Buy.framework不是位置独立可执行文件。请确保您的构建设置配置为创建PIE可执行文件。"

4
第一条信息听起来像是一个模拟器构建。 - Phillip Mills
当我创建一个提交的存档时,我选择设备选项中的iOS设备,然后创建一个存档,如果这就是你所问的。 - Saurabh Jain
2
我同意@PhillipMills的观点。集中精力解决你的第一个错误。为什么你的iOS应用程序中有一个x86_64二进制文件?要么是你在构建设置方面做了一些奇怪的事情... 要么你上传了一个模拟器构建版本。 - Stephen Darlington
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Saurabh Jain
我在使用Application Loader 3.5上传时遇到了这种情况。 - SudoPlz
请参见此处以获取更好的上下文。 - mfaani
17个回答

419

问题在于Buy框架包含了针对模拟器(x86_64)和实际设备(ARM)的构建。

当然,你不允许向App Store提交一个不支持的架构的二进制文件,因此解决方案是在提交之前“手动”从最终二进制文件中删除不需要的架构。

Daniel Kennett提出了一种好的解决方案,并提供了这个脚本以添加到构建阶段:

APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"

# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
    FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
    FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
    echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"

    EXTRACTED_ARCHS=()

    for ARCH in $ARCHS
    do
        echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
        lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
        EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
    done

    echo "Merging extracted architectures: ${ARCHS}"
    lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
    rm "${EXTRACTED_ARCHS[@]}"

    echo "Replacing original executable with thinned version"
    rm "$FRAMEWORK_EXECUTABLE_PATH"
    mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"

done

我使用过它,它完美地发挥了作用。

编辑:确保查看Varrry发布的修改脚本,因为这个有一些小问题。


6
我在我的Xcode项目中使用了这个脚本来修复上述的App Store问题,但现在当我开始构建时,会出现许多致命错误 -> 致命错误:lipo:当指定-extract选项时,输入文件(/...Frameworks/Bolts.framework/Bolts)必须是一个fat文件。有什么想法如何解决这个问题? - SamoanProgrammer
65
我觉得这很愚蠢:你需要结合arm和x86,才能让你的应用程序在模拟器和设备上运行,并且必须剥离x86才能提交到应用商店。为什么苹果不在检测到x86的情况下自己剥离?他们可能会提出很多技术原因来为此辩护,但没有任何商业原因,因为这根本不用户友好。 - superarts.org
5
请选择相关目标,然后进入“构建阶段”,将其放置在“嵌入框架”操作之后。 - Piotr Tobolski
8
以上的脚本很有用,但是并没有提到在Xcode中运行脚本的步骤。要运行这个脚本,请前往TARGETS --> 选择Build Phases,然后在Xcode的上部标题中点击Editor --> Add build phases --> Add run script Build phases,然后您将在TARGET的Build Phase部分中获得一个栏目。在此处,您可以复制粘贴以上的脚本,并成功上传到Appstore。 - shashi Gupta
6
在Xcode 11.2中无法工作 - 有人找到解决方案了吗? - JMIT
显示剩余21条评论

210

pAkY88提供的答案可行,但我遇到了和Mario A Guzman在https://dev59.com/3lsW5IYBdhLWcg3wOlDO#35240555中一样的问题:一旦我们削减了未使用的架构,就无法再运行脚本,因为Xcode不会每次重新嵌入二进制文件。 我的想法是-在构建档案时仅删除i386和x86_64切片,因此我修改了脚本:

echo "Target architectures: $ARCHS"

APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"

find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
echo $(lipo -info "$FRAMEWORK_EXECUTABLE_PATH")

FRAMEWORK_TMP_PATH="$FRAMEWORK_EXECUTABLE_PATH-tmp"

# remove simulator's archs if location is not simulator's directory
case "${TARGET_BUILD_DIR}" in
*"iphonesimulator")
    echo "No need to remove archs"
    ;;
*)
    if $(lipo "$FRAMEWORK_EXECUTABLE_PATH" -verify_arch "i386") ; then
    lipo -output "$FRAMEWORK_TMP_PATH" -remove "i386" "$FRAMEWORK_EXECUTABLE_PATH"
    echo "i386 architecture removed"
    rm "$FRAMEWORK_EXECUTABLE_PATH"
    mv "$FRAMEWORK_TMP_PATH" "$FRAMEWORK_EXECUTABLE_PATH"
    fi
    if $(lipo "$FRAMEWORK_EXECUTABLE_PATH" -verify_arch "x86_64") ; then
    lipo -output "$FRAMEWORK_TMP_PATH" -remove "x86_64" "$FRAMEWORK_EXECUTABLE_PATH"
    echo "x86_64 architecture removed"
    rm "$FRAMEWORK_EXECUTABLE_PATH"
    mv "$FRAMEWORK_TMP_PATH" "$FRAMEWORK_EXECUTABLE_PATH"
    fi
    ;;
esac

echo "Completed for executable $FRAMEWORK_EXECUTABLE_PATH"
echo $(lipo -info "$FRAMEWORK_EXECUTABLE_PATH")

done

如果运行时不是模拟器(也就是目标文件夹不像“Debug-iphonesimulator”),则此脚本将从fat二进制文件中简单地删除i386和x86_64片段(如果存在)。

很抱歉,我不熟悉shell脚本,所以可能有人能够以更优雅的方式编写它。但它有效)


1
谢谢您的建议。我只是在while循环中添加了一个检查,来自已接受答案的代码 case "${TARGET_BUILD_DIR}" in *"iphonesimulator") echo "Skip simulator target"; continue ;; esac,它非常有效。 - Michael Radionov
2
PiterPan,将其作为单独的RunScript阶段添加。 - Varrry
1
我刚刚勾选了“仅在安装时运行脚本”选项,但它除了归档之外都被跳过了。 - Rivera
你在Xcode 9上测试过吗?我在Xcode 9上测试,但无法进行归档操作,有什么办法可以解决吗? - magofdl
@magofdl,由于框架位于应用程序包装器(*.APP目录)内部,因此脚本不应该依赖于目标构建目录的位置。我认为您的问题在其他地方,请提供更多细节:错误、日志等。 - Varrry
显示剩余22条评论

91
If you're using Carthage, you may encounter this problem because the project lacks the carthage copy-frameworks build phase or the build phase does not include all the frameworks (incomplete list). This operation filters the frameworks to a list of valid architectures (code).

建立copy-frameworks构建阶段

Carthage building for iOS steps开始:

在你的应用程序目标的“Build Phases”设置选项卡中,点击“+”图标并选择“New Run Script Phase”。创建一个运行脚本,在其中指定你的 shell(例如:bin/sh),将以下内容添加到 shell 下面的脚本区域中: ``` /usr/local/bin/carthage copy-frameworks ``` 并在“Input Files”下添加要使用的框架的路径,例如: ``` $(SRCROOT)/Carthage/Build/iOS/Box.framework $(SRCROOT)/Carthage/Build/iOS/Result.framework $(SRCROOT)/Carthage/Build/iOS/ReactiveCocoa.framework ``` 此脚本解决了由于通用二进制文件引起的 App Store 提交错误,并确保在归档时复制必要的与 bitcode 相关的文件和 dSYMs。

另外需要注意的是,最近我遇到了这个问题,因为我从使用旧版本的第三方框架切换到使用使用Carthage安装的同一框架的新版本。即使Carthage已经完全设置好,我仍然会继续收到此错误。对我来说,解决方法是完全从项目中删除该框架,然后再将其添加回来。如果您正在使用Carthage并且此答案无法解决问题,请尝试执行此操作。 - Ash
1
确实,一篇很棒的文章。请注意,通常最好的方法就是删除所有框架,然后从Carthage重新添加所有框架。干杯! - Fattie
我正在使用Carthage和Marshal,并且添加$(SRCROOT)/Carthage/Build/iOS/Marshal.framework就可以了。 - Ricardo Mutti
在现代iOS中,99%的情况下这就是问题所在 - 你只是忘记了复制框架。 (现在100%的项目都使用Carthage。) - Fattie

42

我通过将一个框架(优秀的SVProgressHUD)从“嵌入式二进制文件”部分(Xcode目标->常规选项卡)中移除来解决了ITMS-90080错误。

输入图像描述


5
这个答案应该有更多的赞。我怀疑这是许多人使用Carthage的根本原因。 - mm2001
15
如果您尝试嵌入动态框架,然后将其删除,我会收到此错误消息:"原因:找不到图像"。 - electronix384128
1
这对我有用。您必须从“嵌入式二进制文件”中删除框架,仅将其添加到“链接的框架和库”中。另外,您还需要执行其他操作,例如运行在其他答案中找到的脚本。 - SmileBot

34

如果您正在使用 Carthage ,请确保您的 Embed Frameworks Build StepCarthagecopy-frameworks 之前。


在一些特殊情况下(例如:Lottie-iOS 框架):

  • 通常情况下,您只需将其添加到“Link Library”中。

  • 但是,您还必须显式地将其添加到“Embed Frameworks”中(尽管看起来毫无意义,因为当您只有将其添加到“Embed Frameworks”中时,它完全可以正常工作),

  • 并且将其放入 copy-frameworks 中

  • 并且确保 copy-frameworks 在“Embed Frameworks”之后


这是我的问题。谢谢。 - DookieMan

21

使用以下步骤从框架中移除[x86_64、i386][x86_64、i386] 用于模拟器。

  1. 打开Terminal

  2. 将相应框架的路径拖到终端中打开项目

    示例:cd /Users/MAC/Desktop/MyProject/Alamofire.framework

  3. 在下面的命令中设置您的框架名称并运行

lipo -remove i386 Alamofire -o Alamofire && lipo -remove x86_64 Alamofire -o Alamofire

  1. 现在重新打开项目,执行清理、构建和运行,并创建归档...

@mahipal Singh,使用lipo命令删除后,应用程序在模拟器中无法工作。出现了像iPhone模拟器缺少x84_64的错误。但在真实设备上运行良好。 - Hitarth
这是因为模拟器仅支持调试框架。 - MAhipal Singh
这适用于任何已下载的框架,只需将“Alamofire”重命名为您遇到问题的框架即可。感谢这个答案。 - Vitor

16

我会在这里加上我的2美分(以一种不那么可怕的方式 :-)。我遇到过许多厂商提供的庞大库,它们(由于某种原因)不能像苹果公司文档中所述通过将它们添加到Frameworks目录来正常工作。我们唯一能够使它们正常工作的方法是将.framekwork直接拉入项目目录,并手动在构建设置中链接Embedded FrameworksLink Binary with Libraries。这似乎可以正常工作而没有任何问题,但是,与任何庞大的库一样,它们附带了冗余的模拟器架构i386x86_64以及arm体系结构。

检查庞大库体系结构的快速方法是

$ cd 'Project_dir/Project'
$ lipo -info 'YourLibrary.framework/YourLibExec`

应该输出类似于这样的输出

Architectures in the fat file: YourLibrary.framework/YourLibExec are: i386 x86_64 armv7 arm64

这证实了在上传到iTunesConnect归档之前,您将需要从您的框架中剪裁掉i386x86_64这两种不受iOS支持的架构。现在,所有的答案(或者至少有些答案)都提供了这些非常好用的运行脚本,但是只有当你的框架位于Frameworks目录中时才适用。除非你是一个shell脚本迷,否则这些脚本在不作出修改的情况下,无法胜任我上面解释的情景。然而,有一种非常简单的方法可以从框架中删除i386x86_64这些架构。

  1. 在项目目录中打开终端。

  2. 直接进入.framekwork所在目录,例如:

    cd YourProjectDir/YourProject/YourLibrary.framework

  3. 运行如下命令序列:

$ mv YourLibrary YourLibrary_all_archs
$ lipo -remove x86_64 YourLibrary_all_archs -o YourLibrary_some_archs
$ lipo -remove i386 YourLibrary_some_archs -o YourLibrary
$ rm YourLibrary_all_archs YourLibrary_some_archs

这里需要注意几点 - 每次要移除一个体系结构,都必须使用lipo -remove命令进行操作。 lipo不会修改输入文件,它只会生成一个文件,因此您需要先为x86_64i386分别运行一次lipo -remove。上面的命令只是通过首先重命名可执行文件,然后最终删除所需的架构,并清理剩余文件来实现这一点。这样就可以在Application Loader归档上传到iTunesConnect时看到绿色的勾号了。

需要记住的事情: 上述步骤应该只在生产构建期间执行,因为模拟器结构将被剥离,因此,在模拟器上构建将停止工作(这是预期的)。在开发环境中,不应将.framework文件中的架构剥离,因为您希望能够在模拟器和实际设备上进行测试。如果你的fat库驻留在项目的Frameworks文件夹中,请参考接受的答案。


对于那些不想编写脚本的人来说,这是一个简单的解决方案。 - user5578554
只需运行上述命令,架构大小就会减少一半。希望能有所改善。 - showmyroutes
尽管我已经部署了脚本使一切正常工作,但对于如何解决问题,必须提供适当的描述。 - Sharkes Monken
喜欢这个答案的本质。干净简洁。 - Hudi Ilfeld

16

感谢以上所有答案。下面是一个适用于swift 4.2和5的脚本,请将Your_Framework_Name字符串替换为您的框架的原始名称。

APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
FRAMEWORK_NAME="Your_Framework_Name.framework"
# Check if Framework is present.
FRAMEWORK_LOCATION=$(find "$APP_PATH" -name "$FRAMEWORK_NAME" -type d)
if [ -z $FRAMEWORK_LOCATION ]; then
echo "Couldn't find Your_Framework_Name.framework in $APP_PATH. Make sure 'Embed Frameworks' build phase is listed before the 'Strip Unused Architectures' build phase."
exit 1
fi
# This script strips unused architectures
find "$APP_PATH" -name "$FRAMEWORK_NAME" -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
rm "${EXTRACTED_ARCHS[@]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
done

谢谢!这个对我有用,而被接受的答案则没有。 - besserwisser

14

即使添加了脚本并多次更新框架,我仍然遇到了同样的问题。

请确保在xCode中将脚本添加在嵌入后面的最后位置。我想我不小心把脚本移到了嵌入式框架之前。

输入图像描述

注意:我的xCode版本是9.1


这对我有用。在我将近一年前发布的版本中,只有@pAkY88的脚本就足够了。 - RedHotPawn.com
我曾经遇到过相同的问题,这种方法对我很有效。确保每次移除或添加框架时检查运行脚本的位置(仅在移除了一个框架时才需要)。 - Baran Emre
你救了我的一天。只需在嵌入式框架后添加脚本即可。 - Mayuri R Talaviya
1
谢谢,这对我有用,只需在所有脚本的末尾添加此脚本即可。 - Amit Thakur

9

已更新适用于Xcode 10.1,以下解决方案对我有效:

你只需从“嵌入二进制文件”中删除框架,然后将其添加到“链接的框架和库”中即可。

请参阅下面的截图;

输入图像描述


1
适合我的工作解决方案 (y) - Alok
它会从链接的框架和库中删除相同的内容。 - Ranu Dhurandhar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接