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'的右侧按钮,展开详情:

iOS问题记录 - Xcode 14.3版本打包项目报错_第1张图片

可以看到执行的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脚本,是因为在这有设置:

iOS问题记录 - Xcode 14.3版本打包项目报错_第2张图片

PODS_ROOT的定义在这:

iOS问题记录 - Xcode 14.3版本打包项目报错_第3张图片

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

iOS问题记录 - Xcode 14.3版本打包项目报错_第4张图片

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

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

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

iOS问题记录 - Xcode 14.3版本打包项目报错_第5张图片

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

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

# Copies and strips a vendored framework
install_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

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

iOS问题记录 - Xcode 14.3版本打包项目报错_第6张图片

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

lrwxr-xr-x  1 xxx  staff  85 Apr  7 20:23 SDWebImage.framework -> ../../../IntermediateBuildFilesPath/UninstalledProducts/iphoneos/SDWebImage.framework
drwxr-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.framework
drwxr-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 status

SYNOPSIS
     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 0
fi

echo "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 framework
install_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 identity
code_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
  end
end

关键代码是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"
fi
if [[ "$CONFIGURATION" == "Release" ]]; then
  install_framework "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework"
fi
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
  wait
fi

以上只是简单了解一下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参数,而现在这个方法是在已经生成的文件上修改。

iOS问题记录 - Xcode 14.3版本打包项目报错_第7张图片

这想法很好,不过直接拿来用会有问题。一是替换内容的时候双引号没有转义,二是存在多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
  end
end

解决方案

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

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
  end
end

重新执行pod install命令解决问题。

  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历史版本官方下载(需要登录)。

最后

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

你可能感兴趣的:(问题记录,xcode,ios,cocoapods)