我的编程空间,编程开发者的网络收藏夹
学习永远不晚

iOS问题记录 - Xcode 14.3版本打包项目报错

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

iOS问题记录 - Xcode 14.3版本打包项目报错


前言

前几天升级Xcode到14.3版本,运行项目报错,于是写了iOS问题记录 - Xcode 14.3版本运行项目报错这篇文章。没想到除了运行项目有问题,打包项目也有问题。

开发环境

  • macOS: 13.3
  • Xcode: 14.3
  • CocoaPods: 1.12.0

问题描述

[Xcode菜单栏] -> [Product] -> [Archive],进行打包操作。执行到Run custom shell script '[CP] Embed Pods Frameworks'时报错,报错相关日志如下:

Symlinked...rsync --delete -av --filter P .*.?????? --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "../../../IntermediateBuildFilesPath/UninstalledProducts/iphoneos/xxx.framework" "/Users/xxx/Library/Developer/Xcode/DerivedData/app-dukdzczlzijlklamofogqicmtktj/Build/Intermediates.noindex/ArchiveIntermediates/app/InstallationBuildProductsLocation/Applications/app.app/Frameworks"building file list ... rsync: link_stat "xxx/../../../IntermediateBuildFilesPath/UninstalledProducts/iphoneos/xxx.framework" failed: No such file or directory(2)rsync error: some files could not be transferred (code 23) at /AppleInternal/Library/BuildRoots/97f6331a-ba75-11ed-a4bc-863efbbaf80d/Library/Caches/com.apple.xbs/Sources/rsync/rsync/main.c(996) [sender=2.6.9]Command PhaseScriptExecution failed with a nonzero exit code

问题分析

从报错信息看,是因为文件或目录找不到报错。因为项目有改动,所以暂时不确定是不是Xcode 14.3版本的原因。找到一台装有14.2版本的电脑,拉取最新代码后执行打包操作,一切正常!那看来这锅Xcode得背,接下来就是找到具体原因和解决办法。

首先要确定这个错误是在执行什么代码的时候出现的,才能进一步分析。

找到Run custom shell script '[CP] Embed Pods Frameworks'的右侧按钮,展开详情:

screenshot1

可以看到执行的shell脚本路径是:

/Users/xxx/Library/Developer/Xcode/DerivedData/app-dukdzczlzijlklamofogqicmtktj/Build/Intermediates.noindex/ArchiveIntermediates/app/IntermediateBuildFilesPath/app.build/Release-iphoneos/app.build/Script-8D57CFCFEA49D25397FFD044.sh

shell脚本内容:

#!/bin/sh"${PODS_ROOT}/Target Support Files/Pods-app/Pods-app-frameworks.sh"

PODS_ROOT的值是什么呢?你可能会想,直接在shell脚本中加上一行echo "${PODS_ROOT}"不就知道了?不行的,每次执行打包操作都会重新生成这个shell脚本,改动不会生效。其实会执行这个自定义shell脚本,是因为在这有设置:

screenshot2

PODS_ROOT的定义在这:

screenshot3

验证这个很简单,只需要在这加上一行echo "${PODS_ROOT}"

screenshot4

重新执行打包操作,你会发现生成的shell脚本中也多了这一行:

#!/bin/shecho "${PODS_ROOT}""${PODS_ROOT}/Target Support Files/Pods-app/Pods-app-frameworks.sh"

同时在打包输出日志中也正常打印出PODS_ROOT的值。不知道有没有人和我有一样的疑问,生成的shell脚本中并没有导入其他shell脚本或定义PODS_ROOT,那么这个常量怎么来的?不难猜,PODS_ROOT应该来自环境变量。老办法,加上env命令打印一下环境变量:

screenshot5

重新执行打包操作,会打印一大堆环境变量,这里就不一一列出。看打印出来的环境变量,构建设置基本都在里面(没有一个个具体验证)。大致可以得出结论,在构建项目时,Xcode会把构建设置设为临时环境变量。

继续往下分析,找到Pods-app-frameworks.sh文件,根据报错相关日志,报错应该发生在install_framework函数中:

# Copies and strips a vendored frameworkinstall_framework(){  if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then    local source="${BUILT_PRODUCTS_DIR}/$1"  elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then    local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"  elif [ -r "$1" ]; then    local source="$1"  fi  local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"  if [ -L "${source}" ]; then    echo "Symlinked..."    source="$(readlink "${source}")"  fi  if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then    # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied    find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do      echo "Installing $f"      install_bcsymbolmap "$f" "$destination"      rm "$f"    done    rmdir "${source}/${BCSYMBOLMAP_DIR}"  fi  # Use filter instead of exclude so missing patterns don't throw errors.  echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""  rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"  local basename  basename="$(basename -s .framework "$1")"  binary="${destination}/${basename}.framework/${basename}"  if ! [ -r "$binary" ]; then    binary="${destination}/${basename}"  elif [ -L "${binary}" ]; then    echo "Destination binary is symlinked..."    dirname="$(dirname "${binary}")"    binary="${dirname}/$(readlink "${binary}")"  fi  # Strip invalid architectures so "fat" simulator / device frameworks work on device  if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then    strip_invalid_archs "$binary"  fi  # Resign the code if required by the build settings to avoid unstable apps  code_sign_if_enabled "${destination}/$(basename "$1")"  # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.  if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then    local swift_runtime_libs    swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)    for lib in $swift_runtime_libs; do      echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""      rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"      code_sign_if_enabled "${destination}/${lib}"    done  fi}

执行rsync --delete...命令的时候,source变量的路径有问题。修改Pods-app-frameworks.sh文件,增加一些日志打印用于追踪source变量的变化。经测试,在执行source="$(readlink "${source}")"之前,source变量中的路径是绝对路径:

/Users/xxx/Library/Developer/Xcode/DerivedData/app-dukdzczlzijlklamofogqicmtktj/Build/Intermediates.noindex/ArchiveIntermediates/app/BuildProductsPath/Release-iphoneos/SDWebImage/SDWebImage.framework

执行后,变为相对路径:

../../../IntermediateBuildFilesPath/UninstalledProducts/iphoneos/SDWebImage.framework

通过访达的前往文件夹功能,找到绝对路径所指向的位置:

screenshot6

SDWebImage.framework是一个替身(软链接/符号链接)。在SDWebImage目录路径下执行ls -l查看实际指向的路径:

lrwxr-xr-x  1 xxx  staff  85 Apr  7 20:23 SDWebImage.framework -> ../../../IntermediateBuildFilesPath/UninstalledProducts/iphoneos/SDWebImage.frameworkdrwxr-xr-x  3 xxx  staff  96 Apr  7 20:23 SDWebImage.framework.dSYM

看来readlink命令的作用就是获取软连接所指向的实际路径,那这路径为什么报错呢?有对比才能找到问题所在,同样的项目用Xcode 14.2版本执行打包操作,在SDWebImage目录路径下执行ls -l查看实际指向的路径:

lrwxr-xr-x  1 xxx  staff  212 Apr  7 20:30 SDWebImage.framework -> /Users/xxx/Library/Developer/Xcode/DerivedData/app-dukdzczlzijlklamofogqicmtktj/Build/Intermediates.noindex/ArchiveIntermediates/app/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/SDWebImage.frameworkdrwxr-xr-x  3 xxx  staff   96 Apr  7 20:30 SDWebImage.framework.dSYM

这么一对比,原因总算是找到了。Xcode 14.3版本构建时将软链接所指向的绝对路径改为了相对路径,导致找不到文件或目录。

那么该怎么修复呢?可以先看看readlink命令的文档,使用man(manual)命令查看:

man readlink

执行命令后得到的文档(省略部分):

NAME     stat, readlink – display file statusSYNOPSIS     stat [-FLnq] [-f format | -l | -r | -s | -x] [-t timefmt] [file ...]     readlink [-fn] [file ...]DESCRIPTION     The stat utility displays information about the file pointed to by file.  Read, write, or execute permissions of the named file are not required, but all directories listed in the pathname     leading to the file must be searchable.  If no argument is given, stat displays information about the file descriptor for standard input.     When invoked as readlink, only the target of the symbolic link is printed.  If the given argument is not a symbolic link and the -f option is not specified, readlink will print nothing and     exit with an error.  If the -f option is specified, the output is canonicalized by following every symlink in every component of the given path recursively.  readlink will resolve both     absolute and relative paths, and return the absolute pathname corresponding to file.  In this case, the argument does not need to be a symbolic link.     The information displayed is obtained by calling lstat(2) with the given argument and evaluating the returned structure.  The default format displays the st_dev, st_ino, st_mode, st_nlink,     st_uid, st_gid, st_rdev, st_size, st_atime, st_mtime, st_ctime, st_birthtime, st_blksize, st_blocks, and st_flags fields, in that order....

输入q退出文档查看。readlink命令参数不多,其中有个-f参数,这个参数的作用是递归找到第一个真实文件并返回该文件的绝对路径(个人理解)。举个例子🌰,假设A是真实文件,执行ln -s A B命令创建软链接B,执行ln -s B C命令创建软链接C,readlink C命令获取的是B,readlink -f C命令获取的是A的绝对路径。

修改install_framework函数中的readlink命令,加上-f参数。重新执行打包操作,打包成功!分析到这,问题似乎已经解决,可是当我执行完pod install命令后,Pods-app-frameworks.sh的文件内容又恢复原状了。这么看来,每次执行pod install命令都会重新生成Pods-app-frameworks.sh文件,那如果能找到生成文件的代码,在源头修改不就能解决吗?

不得不说macOS的可视化搜索真的不好用,电脑上的隐藏文件已经设置为显示,以install_framework为关键词搜索,搜不到有用的信息。没办法,只好用grep命令来搜索:

grep -R install_framework ~

-R表示递归搜索指定目录(~)下的全部文件,这里对用户目录进行搜索,如果你已经确定CocoaPods包所在目录,则可以指定更详细的目录路径加快搜索。搜索后,找到关键的文件路径:

/Users/xxx/.rvm/gems/ruby-3.0.0/gems/cocoapods-1.12.0/lib/cocoapods/generator/embed_frameworks_script.rb

embed_frameworks_script.rb文件内容:

require 'cocoapods/xcode'module Pod  module Generator    class EmbedFrameworksScript      # @return [Hash{String => Array}] Multiple lists of frameworks per      #         configuration.      #      attr_reader :frameworks_by_config      # @return [Hash{String => Array}] Multiple lists of frameworks per      #         configuration.      #      attr_reader :xcframeworks_by_config      # @param  [Hash{String => Array] frameworks_by_config      #         @see #frameworks_by_config      #      # @param  [Hash{String => Array] xcframeworks_by_config      #         @see #xcframeworks_by_config      #      def initialize(frameworks_by_config, xcframeworks_by_config)        @frameworks_by_config = frameworks_by_config        @xcframeworks_by_config = xcframeworks_by_config      end      # Saves the resource script to the given pathname.      #      # @param  [Pathname] pathname      #         The path where the embed frameworks script should be saved.      #      # @return [void]      #      def save_as(pathname)        pathname.open('w') do |file|          file.puts(script)        end        File.chmod(0755, pathname.to_s)      end      # @return [String] The contents of the embed frameworks script.      #      def generate        script      end      private      # @!group Private Helpers      # @return [String] The contents of the embed frameworks script.      #      def script        script = <<-SH.strip_heredoc#{Pod::Generator::ScriptPhaseConstants::DEFAULT_SCRIPT_PHASE_HEADER}if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then  # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy  # frameworks to, so exit 0 (signalling the script phase was successful).  exit 0fiecho "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"BCSYMBOLMAP_DIR="BCSymbolMaps"#{Pod::Generator::ScriptPhaseConstants::RSYNC_PROTECT_TMP_FILES}# Copies and strips a vendored frameworkinstall_framework(){  if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then    local source="${BUILT_PRODUCTS_DIR}/$1"  elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then    local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"  elif [ -r "$1" ]; then    local source="$1"  fi  local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"  if [ -L "${source}" ]; then    echo "Symlinked..."    source="$(readlink "${source}")"  fi  if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then    # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied    find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do      echo "Installing $f"      install_bcsymbolmap "$f" "$destination"      rm "$f"    done    rmdir "${source}/${BCSYMBOLMAP_DIR}"  fi  # Use filter instead of exclude so missing patterns don't throw errors.  echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \\"- CVS/\\" --filter \\"- .svn/\\" --filter \\"- .git/\\" --filter \\"- .hg/\\" --filter \\"- Headers\\" --filter \\"- PrivateHeaders\\" --filter \\"- Modules\\" \\"${source}\\" \\"${destination}\\""  rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"  local basename  basename="$(basename -s .framework "$1")"  binary="${destination}/${basename}.framework/${basename}"  if ! [ -r "$binary" ]; then    binary="${destination}/${basename}"  elif [ -L "${binary}" ]; then    echo "Destination binary is symlinked..."    dirname="$(dirname "${binary}")"    binary="${dirname}/$(readlink "${binary}")"  fi  # Strip invalid architectures so "fat" simulator / device frameworks work on device  if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then    strip_invalid_archs "$binary"  fi  # Resign the code if required by the build settings to avoid unstable apps  code_sign_if_enabled "${destination}/$(basename "$1")"  # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.  if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then    local swift_runtime_libs    swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\\\/\\(.+dylib\\).*/\\\\1/g | uniq -u)    for lib in $swift_runtime_libs; do      echo "rsync -auv \\"${SWIFT_STDLIB_PATH}/${lib}\\" \\"${destination}\\""      rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"      code_sign_if_enabled "${destination}/${lib}"    done  fi}#{Pod::Generator::ScriptPhaseConstants::INSTALL_DSYM_METHOD}#{Pod::Generator::ScriptPhaseConstants::STRIP_INVALID_ARCHITECTURES_METHOD}#{Pod::Generator::ScriptPhaseConstants::INSTALL_BCSYMBOLMAP_METHOD}# Signs a framework with the provided identitycode_sign_if_enabled() {  if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then    # Use the current code_sign_identity    echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"    local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"    if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then      code_sign_cmd="$code_sign_cmd &"    fi    echo "$code_sign_cmd"    eval "$code_sign_cmd"  fi}        SH        contents_by_config = Hash.new do |hash, key|          hash[key] = ''        end        frameworks_by_config.each do |config, frameworks|          frameworks.each do |framework|            contents_by_config[config] << %(  install_framework "#{framework.source_path}"\n)          end        end        xcframeworks_by_config.each do |config, xcframeworks|          xcframeworks.select { |xcf| xcf.build_type.dynamic_framework? }.each do |xcframework|            target_name = xcframework.target_name            name = xcframework.name            contents_by_config[config] << %(  install_framework "#{Target::BuildSettings::XCFRAMEWORKS_BUILD_DIR_VARIABLE}/#{target_name}/#{name}.framework"\n)          end        end        script << "\n" unless contents_by_config.empty?        contents_by_config.keys.sort.each do |config|          contents = contents_by_config[config]          next if contents.empty?          script << %(if [[ "$CONFIGURATION" == "#{config}" ]]; then\n)          script << contents          script << "fi\n"        end        script << <<-SH.strip_heredoc        if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then          wait        fi        SH        script      end      # @param  [Xcode::FrameworkPaths] framework_path      #         the framework path containing the dSYM      #      # @return [String, Nil] the name of the dSYM binary, if found      #      def dsym_binary_name(framework_path)        return nil if framework_path.dsym_path.nil?        if (path = Pathname.glob(framework_path.dsym_path.join('Contents/Resources/DWARF', '**/*')).first)          File.basename(path)        end      end    end  endend

关键代码是script方法,方法内部可以分为两部分:

  • 第一部分是<<-SH.strip_heredoc...SH,这是一个多行字符串(heredoc),用于生成一些比较固定的内容。在Ruby语法中,多行字符串一般这样表示<(XXX可以自定义,前后保持一致),加-是为了字符串内能缩进,strip_heredoc方法用于删除多余的缩进
  • 第二部分从contents_by_config = Hash.new do |hash, key|到方法结束,这部分代码会根据项目依赖的Pod库生成类似这样的内容:
if [[ "$CONFIGURATION" == "Debug" ]]; then  install_framework "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework"fiif [[ "$CONFIGURATION" == "Release" ]]; then  install_framework "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework"fiif [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then  waitfi

以上只是简单了解一下Pods-app-frameworks.sh文件内容是怎么生成的,如果你对这感兴趣,可以尝试自己调试CocoaPods源码,调试环境的搭建可以参考CocoaPods - 源码调试环境搭建

embed_frameworks_script.rb文件中的source="$(readlink "${source}")"改为source="$(readlink -f "${source}")",然后执行pod install命令重新生成Pods-app-frameworks.sh文件,接着重新打包,一切正常!

不过,这也不是长久之计,关键还是要CocoaPods修复这个问题。已经有人提了issue,连PR都有了,只不过还不知道啥时候发新版本。逛issue的过程中,发现了不同于前面的解决办法:

  1. 切换Command Line Tools版本

Xcode 14.2版本有7.15GB,重新下载有点费时间,所以先看看只下载Command Line Tools for Xcode 14.2(671MB)行不行,安装完成后发现不行,还是得下载Xcode 14.2版本。在Xcode 14.3版本中设置Command Line Tools版本为14.2,尝试打包还是报错。看来这方法不太行,而且如果都安装有14.2版本,那直接用不就好了。

  1. 利用Hook修改Pods-app-frameworks.sh文件内容

前面的解决方法是在生成文件的时候加上-f参数,而现在这个方法是在已经生成的文件上修改。

screenshot7

这想法很好,不过直接拿来用会有问题。一是替换内容的时候双引号没有转义,二是存在多target的时候会找不到文件。除了解决这两个问题,再简单优化一下,不再需要手动设置项目名称:

post_install do |installer|  installer.pods_project.targets.each do |target|    shell_script_path = "Pods/Target Support Files/#{target.name}/#{target.name}-frameworks.sh"    if File::exists?(shell_script_path)      shell_script_input_lines = File.readlines(shell_script_path)      shell_script_output_lines = shell_script_input_lines.map { |line| line.sub("source=\"$(readlink \"${source}\")\"", "source=\"$(readlink -f \"${source}\")\"") }      File.open(shell_script_path, 'w') do |f|        shell_script_output_lines.each do |line|          f.write line        end      end    end  endend

解决方案

如果没有看前面的问题分析,建议先看一下。解决问题的方法有很多,以下罗列一些,供大家随意选择。

2023/04/10更新:如果你的项目是Flutter项目,除了以下方法,还可以通过升级Flutter到3.7.10或更高版本的方式解决该问题。

  1. 升级CocoaPods版本

个人比较推荐的方法,但是可能暂时还无法使用。问题将在1.12.1版本修复,如果你遇到这个问题时,CocoaPods版本已经发布到1.12.1或更高版本,推荐通过升级到最新版本解决该问题。

  1. 修改Podfile文件

加上这段代码:

post_install do |installer|  installer.pods_project.targets.each do |target|    shell_script_path = "Pods/Target Support Files/#{target.name}/#{target.name}-frameworks.sh"    if File::exists?(shell_script_path)      shell_script_input_lines = File.readlines(shell_script_path)      shell_script_output_lines = shell_script_input_lines.map { |line| line.sub("source=\"$(readlink \"${source}\")\"", "source=\"$(readlink -f \"${source}\")\"") }      File.open(shell_script_path, 'w') do |f|        shell_script_output_lines.each do |line|          f.write line        end      end    end  endend

重新执行pod install命令解决问题。你可能会遇到以下报错:

undefined method `exists?' for File:Class

从Ruby 3.2.0版本开始,exists?方法被移除了,解决方法是替换为exist?方法。参考文档:Ruby 3.2.0 Released

  1. 修改embed_frameworks_script.rb文件

文件位于CocoaPods包下的lib/cocoapods/generator/embed_frameworks_script.rb路径,将文件中的source="$(readlink "${source}")"替换为source="$(readlink -f "${source}")",重新执行pod install命令解决问题。

  1. 使用Xcode 14.2版本

既然都升级了,个人不是很推荐退回低版本,如果确实有需要,Xcode历史版本官方下载(需要登录)。

最后

如果这篇文章对你有所帮助,请不要吝啬你的点赞👍加星🌟,谢谢~

来源地址:https://blog.csdn.net/crasowas/article/details/129974391

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

iOS问题记录 - Xcode 14.3版本打包项目报错

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

iOS问题记录 - Xcode 14.3版本打包项目报错

文章目录 前言开发环境问题描述问题分析解决方案最后 前言 前几天升级Xcode到14.3版本,运行项目报错,于是写了iOS问题记录 - Xcode 14.3版本运行项目报错这篇文章。没想到除了运行项目有问题,打包项目也有问题。
2023-08-17

iOS问题记录 - Xcode 14.3版本运行项目报错

文章目录 前言开发环境问题描述问题分析解决方案最后 前言 看到Xcode有新版本,没忍住点了升级,然后问题来了。 2023/06/24更新:关于Xcode 14.3版本打出来的包在iOS 13版本报错的问题,经过iOS 13.
2023-08-16

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录