一、布景

iOS 运用开发的世界里,每次 Xcode 更新都带来了新的特性和应战。最近的 Xcode 15 更新不例外,这次晋级引入了对 SwiftUI 的主动强依靠。SwiftUI最低是从 iOS 13 开端支撑。

这一改变也带来了潜在的兼容性问题。如果您的项目在晋级到 Xcode 15 后仍需支撑 iOS 13 以下版别,那么在这些旧设备上运转运用时,将不可避免地遇到崩溃问题。

二、问题

Xcode15 晋级后 iOS13 以下崩溃问题

问题描述及原因

崩溃信息如下:

ExceptionType:EXC_CRASH(SIGABRT)
ExceptionCodes:0x0000000000000000,0x0000000000000000
ExceptionNote:EXC_CORPSE_NOTIFY
TerminationDescription:DYLD,Librarynotloaded:/System/Library/Frameworks/SwiftUI.framework/SwiftUI|Referencedfrom:/var/containers/Bundle/Application/E96C2AC1-F3D8-4A70-8FDE-FA34A0C73AD3/JDMobileLite.app/JDMobileLite|Reason:imagenotfound
TriggeredbyThread:0

Xcode15 默认会在 Build Setting 增加 ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOL_FRAMEWORKS 选项,默认值为:

SwitUIUIKitAppKit

因为 SwiftUI 是从 iOS13 开端支撑,这样导致在以下的设备上运转会崩溃。

官方文档如下:

developer.apple.com/documentati…

问题解决

检查一下Asset Catalog Compiler这一项 Generate Swift Asset Symbol Framework Support,把SwiftUI去掉

iOS依靠库版别一致性检测:保证运用兼容性

问题解决复查

1、重新出包,运用 iOS13以下 的设备安装运转验证;

2、运用 otool 检测 ipa 中的二进制验证:

问题解决前数据如下:

$otool-LJDMobileLite
JDMobileLite:
...
...
/System/Library/Frameworks/QuickLook.framework/QuickLook(compatibilityversion1.0.0,currentversion946.3.2)
/System/Library/Frameworks/SwiftUI.framework/SwiftUI(compatibilityversion1.0.0,currentversion5.2.12)
/System/Library/Frameworks/UserNotifications.framework/UserNotifications(compatibilityversion1.0.0,currentversion1.0.0)
...
...

问题解决后数据如下:

$otool-LJDMobileLite
JDMobileLite:
...
...
/System/Library/Frameworks/QuickLook.framework/QuickLook(compatibilityversion1.0.0,currentversion946.3.2)
/System/Library/Frameworks/UserNotifications.framework/UserNotifications(compatibilityversion1.0.0,currentversion1.0.0)
...
...

解决方案参考:

forums.developer.apple.com/forums/thre…

stackoverflow.com/questions/5…

三、规避东西

跟着 XcodeiOS SDK 的不断更新,我们作为开发者,面临着一个继续的应战:保证我们的运用在旧版别的iOS上仍然能够稳定运转。这一应战的核心在于保持 App支撑的最低体系版别号项目依靠的体系库支撑最低版别号 的一致性。这不仅仅是一个单次的修正问题,而是需求一个体系化的解决方案来继续监控和解决这一问题。以下是实现这一方针的三个关键思路:

1、怎么获取到 App 支撑的最低体系版别号?

每一个 App 中都会有一个 info.plist 文件,这儿经过 plistlib 读取该 App 支撑的最低体系版别号及当前 App 的版别信息,脚本如下:

defread_minimum_os_version(app_path):
info_plist_path=app_path+"/"+"info.plist"
try:
withopen(info_plist_path,'rb')asf:
data=plistlib.load(f)
returndata.get('MinimumOSVersion'),data.get('CFBundleShortVersionString'),data.get('CFBundleVersion')
except(KeyError,FileNotFoundError):
returnNone

2、怎么获取 App 依靠的体系库列表?

这儿需求运用到 otool 东西的能力,依靠 bash 环境,脚本代码如下:

#!/bin/bash
#otool.sh
file_path=$1
otool-L$file_path

Python 经过 subprocess 履行 otool.sh 并获取依靠体系库列表:

defsystem_frameworks_list(app_path):
filename=os.path.basename(app_path)
filename,extension=os.path.splitext(filename)
macho_path=app_path+"/"+filename
result=subprocess.run(["sh","otool.sh",macho_path],stdout=subprocess.PIPE)
#检查指令是否成功履行
ifresult.returncode==0:
#将输出解码为字符串
output_str=result.stdout.decode('utf-8')
#打印输出
print("t履行sh脚本获取体系列表信息成功")
frameworks=extract_frameworks(output_str)
returnframeworks
else:
print(f"t履行脚本失败,退出状况码:{result.returncode}")
returnNone

3、怎么获取这些体系库最低支撑的体系版别号?

经过查询资料,Apple 是有敞开 API 进行查询,查询方法为:developer.apple.com/tutorials/d…

解析可获取对应库的最低支撑体系版别号。

需求留心的是,如下库需求过滤:

defignore_frameworks():
#OpenAL(OpenAudioLibrary)是一个跨渠道的敞开源代码音频库,它提供了一组接口,
#使得游戏开发者能够更方便地处理音频。
#OpenAL提供了诸如3D声响定位、回声作用、混响作用等功能,使得游戏开发者能够创建愈加逼真的音效体验。
#https://www.openal.org/platforms/查询得到iOS开发中是在CoreAudio中,而CoreAudio从iOS2就开端支撑
#MobileCoreServices结构运用一致类型标识符(UTI)信息来创建和操作能够在您的运用和其他运用和服务之间交流的数据。
#底层直接引证CoreServices,MobileCoreServices支撑
#支撑的最低体系版别,这个结构自iOS的前期版别就已经存在,并且跟着操作体系的每次更新而得到更新和维护
#WebKit和JavaScriptCore在iOS7就开端支撑,但是有一些特性API会有版别限制,不再体系库这一层级去考虑
return["OpenAL","MobileCoreServices","WebKit","JavaScriptCore"]

东西实现的流程:

iOS依靠库版别一致性检测:保证运用兼容性

四、东西运用

履行 main.py, 并传入 app 包的途径即可

$python3main.py-f/Users/denglibing/Downloads/JDMOBILELITE-V6.0.0-100-1337-APPSTORE-d0e2839a/Payload/JDMobileLite.app
==Step1解析参数
app_path:/Users/denglibing/Downloads/JDMOBILELITE-V6.0.0-100-1337-APPSTORE-d0e2839a/Payload/JDMobileLite.app
output:/Users/denglibing/Downloads/JDMOBILELITE-V6.0.0-100-1337-APPSTORE-d0e2839a/Payload
==Step2经过sh脚本获取该app依靠的体系库列表(剔除weak依靠))
履行sh脚本获取体系列表信息成功
体系库列表:['AVFoundation','Accelerate','AdSupport','AddressBook','AddressBookUI','AssetsLibrary','AudioToolbox','CFNetwork','CoreFoundation','CoreGraphics','CoreLocation','CoreMedia','otion','CoreText','CoreVideo','EventKit','Foundation','GLKit','ImageIO','LocalAuthentication','MediaPlayer','OpenGLES','PassKit','QuartzCore','Security','StoreKit','SystemConfiguration','UIKit','VideoToolbox','WatchConnectivity','AVKit','CoreData','CoreImage','MapKit','MessageUI','Photos','QuickLook','iAd','SwiftUI']
==Step3读取info.plist文件获取该app版别信息
app_version:6.0.0app_build:1337min_ios_version:11.0
==Step4developer.apple.com查询获取体系库最低支撑版别号,得到反常依靠
反常依靠:SwiftUI
!!!请重点排查!!!,不然或许导致低版别体系启动崩溃
本次分析耗时:38.130

开源地址,欢迎运用并反应: github.com/erduoniba/a…