iOS依赖库版本一致性检测:确保应用兼容性

news2024/11/26 4:36:38

一、背景

iOS 应用开发的世界里,每次 Xcode 更新都带来了新的特性和挑战。最近的 Xcode 15 更新不例外,这次升级引入了对 SwiftUI 的自动强依赖。SwiftUI最低是从 iOS 13 开始支持。

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

二、问题

Xcode15 升级后 iOS13 以下崩溃问题

问题描述及原因

崩溃信息如下:

Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note:  EXC_CORPSE_NOTIFY
Termination Description: DYLD, Library not loaded: /System/Library/Frameworks/SwiftUI.framework/SwiftUI | Referenced from: /var/containers/Bundle/Application/E96C2AC1-F3D8-4A70-8FDE-FA34A0C73AD3/JDMobileLite.app/JDMobileLite | Reason: image not found
Triggered by Thread:  0

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

SwitUI UIKit AppKit

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

官方文档如下:

https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes

问题解决

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

问题解决复查

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

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

问题解决前数据如下:

$ otool -L JDMobileLite
JDMobileLite:
        ...
        ...
	/System/Library/Frameworks/QuickLook.framework/QuickLook (compatibility version 1.0.0, current version 946.3.2)
	/System/Library/Frameworks/SwiftUI.framework/SwiftUI (compatibility version 1.0.0, current version 5.2.12)
	/System/Library/Frameworks/UserNotifications.framework/UserNotifications (compatibility version 1.0.0, current version 1.0.0)
	...
        ...

问题解决后数据如下:

$ otool -L JDMobileLite
JDMobileLite:
        ...
        ...
	/System/Library/Frameworks/QuickLook.framework/QuickLook (compatibility version 1.0.0, current version 946.3.2)
	/System/Library/Frameworks/UserNotifications.framework/UserNotifications (compatibility version 1.0.0, current version 1.0.0)
	...
        ...

解决方案参考:

https://forums.developer.apple.com/forums/thread/126506

https://stackoverflow.com/questions/57907817/dyld-library-not-loaded-swiftui-when-app-runs-on-ios-12-using-availableios-13

三、规避工具

随着 XcodeiOS SDK 的不断更新,我们作为开发者,面临着一个持续的挑战:确保我们的应用在旧版本的iOS上仍然能够稳定运行。这一挑战的核心在于保持 App支持的最低系统版本号项目依赖的系统库支持最低版本号 的一致性。这不仅仅是一个单次的修复问题,而是需要一个系统化的解决方案来持续监控和解决这一问题。以下是实现这一目标的三个关键思路:

1、如何获取到 App 支持的最低系统版本号?

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

def read_minimum_os_version(app_path):
    info_plist_path = app_path + "/" + "info.plist"
    try:
        with open(info_plist_path, 'rb') as f:
            data = plistlib.load(f)
        return data.get('MinimumOSVersion'), data.get('CFBundleShortVersionString'), data.get('CFBundleVersion')
    except (KeyError, FileNotFoundError):
        return None

2、如何获取 App 依赖的系统库列表?

这里需要使用到 otool 工具的能力,依赖 bash 环境,脚本代码如下:

#!/bin/bash
# otool.sh

file_path=$1
otool -L $file_path

Python 通过 subprocess 执行 otool.sh 并获取依赖系统库列表:

def system_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)
    # 检查命令是否成功执行
    if result.returncode == 0:
        # 将输出解码为字符串
        output_str = result.stdout.decode('utf-8')

        # 打印输出
        print("\t执行 sh 脚本获取系统列表信息成功")
        frameworks = extract_frameworks(output_str)
        return frameworks
    else:
        print(f"\t执行脚本失败,退出状态码:{result.returncode}")
        return None

3、如何获取这些系统库最低支持的系统版本号?

通过查询资料,Apple 是有开放 API 进行查询,查询方式为:https://developer.apple.com/tutorials/data/documentation/{frameworkname}.json

解析可获取对应库的最低支持系统版本号。

需要留意的是,如下库需要过滤:

def ignore_frameworks():
    # OpenAL(Open Audio Library)是一个跨平台的开放源代码音频库,它提供了一组接口,
    # 使得游戏开发者能够更方便地处理音频。
    # OpenAL 提供了诸如3D声音定位、回声效果、混响效果等功能,使得游戏开发者能够创建更加逼真的音效体验。
    # https://www.openal.org/platforms/ 查询得到 iOS 开发中是在 Core Audio 中,而 Core Audio从 iOS2就开始支持

    # MobileCoreServices框架使用统一类型标识符(UTI)信息来创建和操作可以在您的应用和其他应用和服务之间交换的数据。
    # 底层直接引用 CoreServices,MobileCoreServices支持
    # 支持的最低系统版本,这个框架自 iOS 的早期版本就已经存在,并且随着操作系统的每次更新而得到更新和维护

    # WebKit 和 JavaScriptCore 在 iOS7就开始支持,但是有一些特性API会有版本限制,不再系统库这一层级去考虑
    return ["OpenAL", "MobileCoreServices", "WebKit", "JavaScriptCore"]

工具实现的流程:

四、工具使用

执行 main.py, 并传入 app 包的路径即可

$ python3 main.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.0       app_build:1337  min_ios_version:11.0 

==Step4 developer.apple.com查询获取系统库最低支持版本号,得到异常依赖
	异常依赖:SwiftUI
	!!!请重点排查!!!,不然可能导致低版本系统启动崩溃

本次分析耗时:38.130秒

开源地址,欢迎使用并反馈:
https://github.com/erduoniba/abnormal_system_framework

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1600155.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《大话数据结构》02 算法

算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。 1. 两种算法的比较 大家都已经学过一门计算机语言,不管学的是哪一种,学得好不好,好歹是可以写点小程序了。现在…

为什么你不用懒人建站工具?套用这四个wordpress主题模板,1小时轻松搭建网站

懒人建站工具,凭借简单易用、快速上手和个性化定制的特点,为不熟悉代码和程序的人提供了搭建美观实用网站的便捷途径。无需专业的前端开发知识,无需雇佣专业开发人员,用户便能轻松实现网站搭建,满足个人或企业需求。懒…

【可实战】测试体系与测试方案设计(业务按公司实际情况,技术可参考通用测试方案)

一、如果我们要测试一个系统,首先我们要了解被测系统的架构 (一)业务架构-从需求里面去了解(角色和行为): 业务模型分析(是一个电商,还是一个企业的crm,还是一个网站&a…

高等数学——一文搞定二重积分

文章目录 二重积分的基本概念二重积分的性质累次积分计算二重积分的方法和技巧描点画图法对称性利用函数的奇偶性变量的轮换对称性 积分次序的选择积分区域的确认先看变量和先积变量基本原则穿线法确定先积变量的曲线范围 常见的曲线经典题目 二重积分的基本概念 定义&#xf…

ChatGPT 可以预测未来吗?

推荐 4月13日的一篇有趣的 paper,特来分享。 👉 当前的大型语言模型(LLMs)具有强大的数据合成和推理能力,但它们在直接预测尚未发生事件的准确性上常常受到限制。传统的预测方法依赖于直接询问模型关于未来的问题。 …

测出Bug就完了?从4个方面教你Bug根因分析

01 现状及场景 🎯 1.缺失bug根因分析环节 工作10年,虽然不是一线城市,也经历过几家公司,规模大的、规模小的都有,针对于测试行业很少有Bug根因环节,主流程基本上都是测试提交bug-开发修改-测试验证-发送报…

Spring学习(二)

图解: 2.核心容器总结 2.2.1 容器相关 BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载 ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载 ApplicationContext接口提供基础的be…

为什么科拓停车选择OceanBase来构建智慧停车SaaS应用

本文来自OceanBase的客户——拓客停车的实践分享 科拓停车简介与业务背景 作为智慧停车行业的佼佼者,科拓停车致力于提供全方位的智慧停车解决方案。服务涵盖车场运营管理、互联网智慧停车平台以及停车场增值服务等。通过不断研发创新,打造出了多样化的…

C++命名空间在内部声明函数,在外部定义函数

C命名空间在内部声明函数&#xff0c;在外部定义函数 #include <iostream> namespace A {int a;void func(); } void A::func() {std::cout << "Hello World!" << std::endl; } void main() {A::func(); }实际运行的代码和结果图如下&#xff1a;…

十大排序——10.基数排序

下面我们来看一下基数排序 目录 1.介绍 2.代码实现 3.总结与思考 1.介绍 基数排序&#xff08;Radix sort&#xff09;是一种非比较型整数排序算法 基本思想&#xff1a; 它的原理是将整数按位数切割成不同的数字&#xff0c;然后按每个位数分别比较。基数排序的方式可以…

「51媒体」如何有效进行媒体邀约,提升宣传传播效果?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 进行有效的媒体邀约&#xff0c;提升宣传传播效果的关键在于策略性和专业性。以下是具体的做法&#xff1a; 明确目标&#xff1a;要确立清晰的品牌推广目标和策略&#xff0c;包括确定目…

DBUtils工具类的使用

1、DBUtils是什么 为了更加简单地使用JDBC&#xff0c;Apache组织提供了一个DBUtils工具&#xff0c;它是操作数据库的一个组件&#xff0c;实现了对JDBC的简单封装&#xff0c;可以在不影响数据库访问性能的情况下简化JDBC的编码工作量。DBUtils工具要有2个作用。 写数据&am…

【Linux】服务器硬件及RAID配置实战

目录 一、服务器 1.服务器 2.查看服务器信息 二、RAID 磁盘阵列 三、软RAID的创建和使用 1.添加硬盘&#xff0c;fdisk分区&#xff0c;分区类型ID设置为 fd 2.使用mdadm创建软raid 3.格式化 4.挂载使用 5.mdadm 一、服务器 1.服务器 分类机架式居多 塔…

Yolo-world+Python-OpenCV之摄像头视频实时目标检测

上一次介绍了如何使用最基本的 Yolo-word来做检测&#xff0c;现在我们在加opencv来做个实时检测的例子 基本思路 1、读取离线视频流 2、将视频帧给yolo识别 3、根据识别结果 对视频进行绘制边框、加文字之类的 完整代码如下&#xff1a; import datetimefrom ultralytics …

Lagent AgentLego 智能体介绍

本文主要介绍智能体相关基础知识&#xff0c;主流的智能体开源项目&#xff0c;重点介绍Lagent智能体和AgentLego框架。 一. 为什么要有智能体 目前的大预言模型有一些局限性&#xff0c;包括有时候会生成虚假信息&#xff0c;也就是我们说的“大模型胡言乱语”&#xff0c;还…

多线程意义

直接上代码 我们来看两个程序 由一个线程和两个线程运行的区别&#xff1a; 单线程&#xff08;main&#xff09;&#xff1a; public static void test(){long a 0;long b 0;for(long i 0; i < 10000000000l; i){a;}for(long i 0; i < 10000000000l; i){b;}} 多…

外包干了1年....字节跳动面试高频考点,懒加载

一、文章内容 什么是懒加载懒加载的优点什么时候使用懒加载学习懒加载前置内容实战懒加载图片 二、什么是懒加载? 从语法角度分析懒加载,懒是adj形容词,加载是名词;或者懒看为副词,加载作为动词,这样就能理解懒加载了就是懒懒的/地加载,更通俗的讲就是通过一种手段来加载.就…

docker 环境变量设置实现方式

1、前言 docker在当前运用的越来广泛&#xff0c;很多应用或者很多中间软件都有很多docker镜像资源&#xff0c;运行docker run 启动镜像资源即可应用。但是很多应用或者中间件有很多配置参数。这些参数在运用过程怎么设置给docker 容器呢&#xff1f;下面介绍几种方式 2 、do…

软件测试---性能测试

1.常见的性能问题有哪些 如图所示 系统内部以及软件的代码实现 1&#xff0c;资源泄漏&#xff0c;包括内存泄漏。 2&#xff0c;CPU使用率达到100%&#xff0c;系统被锁定等。 3&#xff0c;线程死锁&#xff0c;阻塞等造成系统越来越慢。 4&#xff0c;查询速度慢&#xff0c…

MySQL死锁与死锁检测

一、什么是MySQL死锁 MySQL中死锁是指两个或多个事务在互相等待对方释放资源&#xff0c;导致无法继续执行的情况。 MySQL系统中当两个或多个事务在并发执行时&#xff0c;就可能会遇到每项事务都持有某些资源同时又请求其他事务持有的资源&#xff0c;从而形成事务之间循环等…