作者 | Timac
来源 | https://blog.timac.org
关于 iOS 13.1 中对 Swift 的使用,可参考
Apple 在 iOS 13.1 中使用 Swift 开发的应用程序
朴素的方法是检查应用程序是否在其 Frameworks 文件夹中包含 Swift 库:libswiftCore.dylib
、libswiftFoundation.dylib
等。
以下是 macOS 10.12.1 中的 MRT.app 的 Frameworks 文件夹的内容 /System/Library/CoreServices/MRT.app/Contents/Frameworks/
:
但是,这不是一个好方法,因为 iOS 和 macOS 在 /System/Library/PrivateFrameworks/Swift/
中包含 Swift 库的私有副本。iOS 和 macOS 中的多个应用程序直接链接到这些系统库。
以下是 macOS 10.12.1 中的 PIPAgent.app
的 Frameworks 文件夹的内容 /System/Library/CoreServices/PIPAgent.app/Contents/Frameworks/
:
更好的方法是检查二进制文件是否链接到 Swift 库。可以通过命令行工具 otool 中使用 -L
选项轻松完成此操作:
-L
显示目标文件使用的共享库的名称和版本号,以及如果文件是共享库,则显示共享库 ID。
在 PIPAgent 应用程序上运行此命令时:
otool -L /System/Library/CoreServices/PIPAgent.app/Contents/MacOS/PIPAgent | grep swift
您将获得以下输出:
/System/Library/PrivateFrameworks/Swift/libswiftAppKit.dylib (compatibility version 1.0.0, current version 800.8.18)
/System/Library/PrivateFrameworks/Swift/libswiftCore.dylib (compatibility version 1.0.0, current version 800.8.18)
/System/Library/PrivateFrameworks/Swift/libswiftCoreData.dylib (compatibility version 1.0.0, current version 800.8.18)
/System/Library/PrivateFrameworks/Swift/libswiftCoreGraphics.dylib (compatibility version 1.0.0, current version 800.8.18)
/System/Library/PrivateFrameworks/Swift/libswiftCoreImage.dylib (compatibility version 1.0.0, current version 800.8.18)
/System/Library/PrivateFrameworks/Swift/libswiftDarwin.dylib (compatibility version 1.0.0, current version 800.8.18)
/System/Library/PrivateFrameworks/Swift/libswiftDispatch.dylib (compatibility version 1.0.0, current version 800.8.18)
/System/Library/PrivateFrameworks/Swift/libswiftFoundation.dylib (compatibility version 1.0.0, current version 800.8.18)
/System/Library/PrivateFrameworks/Swift/libswiftIOKit.dylib (compatibility version 1.0.0, current version 800.8.18)
/System/Library/PrivateFrameworks/Swift/libswiftObjectiveC.dylib (compatibility version 1.0.0, current version 800.8.18)
建立一个脚本
使用 otool 命令行工具,可以很容易地编写一个 bash 函数来判断文件是否是链接到 Swift 库的二进制文件:
#------------------------------------------------------------------------
# Function to check if a file (passed as argument $1) is using Swift
# It returns the number of occurrences of the string 'swift'
# from the output of otool
#------------------------------------------------------------------------
isFileUsingSwift ()
{
otool -L $1 2>/dev/null | grep -o swift | wc -l
}
如果文件是链接到 Swift 库的二进制文件,则 processFile
bash 函数将文件作为参数并打印其路径:
#------------------------------------------------------------------------
# Function to process a file (passed as argument $1).
# It calls the function isFileUsingSwift() to determine
# if this is a binary using Swift and in this case
# print the path of this file.
#------------------------------------------------------------------------
processFile ()
{
isFileUsingSwift=$( isFileUsingSwift $1 )
if [ ${isFileUsingSwift} != 0 ]
then
# We found a binary using Swift
echo " $1"
fi
}
现在遍历文件夹的所有文件仅需一行:
find ${PATH_TO_CHECK} -type f -exec bash -c 'processFile "$0"' {} \;
最终脚本
下面是一个完整的 bash 脚本,该脚本循环遍历一个文件夹的所有文件,并显示找到的所有使用 Swift 的二进制文件的路径。
#!/bin/bash
#---------------------------------------------------------------------
# Bash script that loops through all the files of a folder and
# print the paths of all the binaries found that use Swift
# Created by Alexandre Colucci on 01.11.2016
# https://blog.timac.org/2016/1101-apples-use-of-swift-in-ios-10-1-and-macos-10-12
#---------------------------------------------------------------------
#---------------------------------------------------------------------
# Force expand a wildcard pattern into the list of matching pathnames
#---------------------------------------------------------------------
shopt -s nullglob
#---------------------------------------------------------------------
# Function to print the usage
#---------------------------------------------------------------------
printUsage ()
{
echo "Usage: detectSwift.sh PATH"
echo "PATH: Folder to search for binaries using Swift"
echo ""
echo "Examples:"
echo " detectSwift.sh /System/Library"
echo " detectSwift.sh /System"
echo " detectSwift.sh /"
echo ""
echo "Note: run as root in order to avoid permission issues."
echo ""
}
#---------------------------------------------------------------------
# Function to check if a file (passed as argument $1) is using Swift
# It returns the number of occurrences of the string 'swift'
# from the output of otool
#---------------------------------------------------------------------
isFileUsingSwift ()
{
otool -L $1 2>/dev/null | grep -o swift | wc -l
}
#---------------------------------------------------------------------
# Function to process a file (passed as argument $1).
# It calls the function isFileUsingSwift() to determine
# if this is a binary using Swift and in this case
# print the path of this file.
#---------------------------------------------------------------------
processFile ()
{
isFileUsingSwift=$( isFileUsingSwift $1 )
if [ ${isFileUsingSwift} != 0 ]
then
# We found a binary using Swift
echo " $1"
fi
}
#---------------------------------------------------------------------
# Check if the script was called with the expected usage
#---------------------------------------------------------------------
PARAMETER_NUMBER=$#
PARAMETER_REQUIRED=1
if [ $PARAMETER_NUMBER != $PARAMETER_REQUIRED ];
then
printUsage
exit 1
fi
#---------------------------------------------------------------------
# Get the folder path
#---------------------------------------------------------------------
PATH_TO_CHECK=$1
echo ""
echo "Start time:"
date
echo ""
echo "Apps using Swift in ${PATH_TO_CHECK}"
#---------------------------------------------------------------------
# Export the functions so that the subshell inherits them
#---------------------------------------------------------------------
export -f isFileUsingSwift
export -f processFile
#---------------------------------------------------------------------
# Find all the regular files in all subdirectories
# and call for each the function processFile()
#---------------------------------------------------------------------
find ${PATH_TO_CHECK} -type f -exec bash -c 'processFile "$0"' {} \;
#---------------------------------------------------------------------
# Finalizing
#---------------------------------------------------------------------
echo ""
echo "Completed at:"
date
echo ""
运行脚本
该脚本确实很慢:对于每个常规文件,它将创建一个 subshell,分别调用otool
,grep
和 wc
。
在 iOS 10.1 文件系统上运行此脚本大约需要 30 分钟。
对于 macOS 10.12.1,在 /
路径上运行脚本需要花费数十个小时。我建议仅在 /System
,/Applications
和 /usr
上运行此脚本。并行处理这 3 个文件夹大约需要 2 个小时。