如何檢測 iOS 應用程序是否使用 Swift?

原文連接ios

更多好文,請關注公衆號 知識小集 (ID: zsxjtip)shell

關於 iOS 13.1 中對 Swift 的使用,可參考 Apple 在 iOS 13.1 中使用 Swift 開發的應用程序macos

樸素的方法是檢查應用程序是否在其 Frameworks 文件夾中包含 Swift 庫:libswiftCore.dyliblibswiftFoundation.dylib 等。swift

如下是 macOS 10.12.1 中的 MRT.app 的 Frameworks 文件夾的內容 /System/Library/CoreServices/MRT.app/Contents/Frameworks/bash

可是,這不是一個好方法,由於 iOS 和 macOS 在 /System/Library/PrivateFrameworks/Swift/ 中包含 Swift 庫的私有副本。iOS 和 macOS 中的多個應用程序直接連接到這些系統庫。app

如下是 macOS 10.12.1 中的 PIPAgent.app 的 Frameworks 文件夾的內容 /System/Library/CoreServices/PIPAgent.app/Contents/Frameworks/函數

更好的方法是檢查二進制文件是否連接到 Swift 庫。能夠經過命令行工具 otool 中使用 -L 選項輕鬆完成此操做:工具

-L 顯示目標文件使用的共享庫的名稱和版本號,以及若是文件是共享庫,則顯示共享庫 ID。oop

在 PIPAgent 應用程序上運行此命令時:ui

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,分別調用otoolgrepwc

在 iOS 10.1 文件系統上運行此腳本大約須要 30 分鐘。

對於 macOS 10.12.1,在 / 路徑上運行腳本須要花費數十個小時。 我建議僅在 /System/Applications/usr 上運行此腳本。並行處理這 3 個文件夾大約須要 2 個小時。

相關文章
相關標籤/搜索