206 lines
5.4 KiB
Markdown
206 lines
5.4 KiB
Markdown
# 🔴 关键崩溃修复
|
||
|
||
## 问题定位
|
||
|
||
**症状:** 应用在打印 `"XS- 开始创建 BbbAdManager.shared 单例"` 后立即崩溃
|
||
|
||
**根本原因:** `BbbAdManager` 类中使用了 Swift Concurrency 的类型
|
||
|
||
```swift
|
||
// ❌ 这一行导致 iOS 12 崩溃!
|
||
private var initializationContinuations: [CheckedContinuation<Void, Never>] = []
|
||
```
|
||
|
||
**为什么崩溃:**
|
||
1. `CheckedContinuation` 是 Swift Concurrency 的类型,需要 iOS 13+
|
||
2. 在 iOS 12 上,这个类型根本不存在
|
||
3. 当 Swift 创建 `BbbAdManager` 实例时,会先初始化所有存储属性
|
||
4. 尝试初始化包含 `CheckedContinuation` 的数组时,因为类型不存在而崩溃
|
||
5. 崩溃发生在进入 `init()` 方法之前,所以 `"XS- BbbAdManager init 开始"` 日志永远不会打印
|
||
|
||
## ✅ 已修复
|
||
|
||
### 修改 1: 替换 Swift Concurrency 类型
|
||
|
||
**文件:** `PlayBTopOn/playB/bbbAdManager.swift`
|
||
|
||
```swift
|
||
// ❌ 旧代码(iOS 13+ 才能用)
|
||
private var initializationContinuations: [CheckedContinuation<Void, Never>] = []
|
||
|
||
// ✅ 新代码(iOS 12+ 都能用)
|
||
private var initializationCallbacks: [() -> Void] = []
|
||
```
|
||
|
||
### 修改 2: 更新 initAd 方法
|
||
|
||
```swift
|
||
// 调用所有等待的回调(而不是 resume continuations)
|
||
for callback in self.initializationCallbacks {
|
||
callback()
|
||
}
|
||
self.initializationCallbacks.removeAll()
|
||
```
|
||
|
||
### 修改 3: 简化 waitForSDKInitialization
|
||
|
||
```swift
|
||
// 基于回调队列的简单实现,无需轮询
|
||
func waitForSDKInitialization(completion: @escaping () -> Void) {
|
||
if isSDKInitialized {
|
||
completion()
|
||
return
|
||
}
|
||
|
||
// 添加到队列,initAd 完成时会调用
|
||
initializationCallbacks.append(completion)
|
||
}
|
||
```
|
||
|
||
## 🎯 所有修复总结
|
||
|
||
| 问题 | 解决方案 | 状态 |
|
||
|------|---------|------|
|
||
| Task { await ... } | 改用 DispatchQueue + 回调 | ✅ 已修复 |
|
||
| AppTrackingTransparency 导入 | 使用 #if canImport() | ✅ 已修复 |
|
||
| async/await 函数 | 标记 @available(iOS 15.0, *) | ✅ 已修复 |
|
||
| CheckedContinuation 类型 | 改用普通闭包数组 | ✅ 已修复 |
|
||
| Deployment Target = 17.4 | 需改为 12.0 | ⚠️ 需手动操作 |
|
||
| ATT 框架链接 | 需设为 Optional | ⚠️ 需手动操作 |
|
||
|
||
## 📝 接下来必须做的事
|
||
|
||
### 1. 在 Xcode 中修改 Deployment Target(最重要!)
|
||
|
||
```
|
||
打开 PlayBTopOn.xcworkspace
|
||
↓
|
||
选择项目 PlayBTopOn
|
||
↓
|
||
选择 TARGETS → PlayBTopOn
|
||
↓
|
||
General → Deployment Info
|
||
↓
|
||
iOS Deployment Target: 17.4 → 12.0
|
||
```
|
||
|
||
**同时修改 PROJECT 的设置:**
|
||
```
|
||
选择 PROJECT → PlayBTopOn
|
||
↓
|
||
Build Settings → Deployment
|
||
↓
|
||
iOS Deployment Target: 17.4 → 12.0
|
||
```
|
||
|
||
### 2. 设置 AppTrackingTransparency 为弱链接
|
||
|
||
```
|
||
TARGETS → PlayBTopOn
|
||
↓
|
||
Build Phases → Link Binary With Libraries
|
||
↓
|
||
找到 AppTrackingTransparency.framework
|
||
↓
|
||
Status: Required → Optional
|
||
```
|
||
|
||
### 3. 重新安装 Pods
|
||
|
||
```bash
|
||
cd /Users/mac/workspaces/projects/ios/build-ipa/ironSource/PlayBTopOn
|
||
pod install
|
||
```
|
||
|
||
### 4. 清理并重新编译
|
||
|
||
在 Xcode 中:
|
||
1. Product → Clean Build Folder (Cmd+Shift+K)
|
||
2. Product → Build (Cmd+B)
|
||
3. Product → Run (Cmd+R)
|
||
|
||
## 🔍 验证日志
|
||
|
||
成功运行后,你应该看到完整的日志序列:
|
||
|
||
```
|
||
XS- app start: xxx
|
||
XS- app start 2: xxx
|
||
XS- YL_PlayVC viewDidLoad 开始
|
||
XS- app start 21: xxx
|
||
XS- 准备访问 BbbAdManager.shared
|
||
XS- 开始创建 BbbAdManager.config
|
||
XS- bConfig init 开始
|
||
XS- bConfig init: allAdIds count = 3
|
||
XS- bConfig init 完成
|
||
XS- BbbAdManager.config 创建完成
|
||
XS- 开始创建 BbbAdManager.shared 单例
|
||
XS- BbbAdManager init 开始 ← 之前卡在这里之前
|
||
XS- BbbAdManager init 完成 ← 现在应该能看到这个
|
||
XS- BbbAdManager.shared 单例创建完成
|
||
XS- 准备调用 initConfig()
|
||
XS- init config ← 现在应该能看到这个了!
|
||
XS- init config 1
|
||
XS- init config 2
|
||
XS- init config 3
|
||
...
|
||
```
|
||
|
||
## 💡 技术要点
|
||
|
||
### Swift Concurrency 与 iOS 版本
|
||
|
||
| 特性 | 最低版本 |
|
||
|------|---------|
|
||
| Task | iOS 15.0 |
|
||
| async/await | iOS 15.0 |
|
||
| CheckedContinuation | iOS 13.0 |
|
||
| AsyncStream | iOS 15.0 |
|
||
| @MainActor | iOS 15.0 |
|
||
|
||
### 为什么 @available 不够用?
|
||
|
||
```swift
|
||
// ❌ 这样还是会崩溃!
|
||
@available(iOS 15.0, *)
|
||
private var continuation: CheckedContinuation<Void, Never>?
|
||
|
||
// 原因:属性声明在类加载时就会处理,
|
||
// @available 只能保护方法调用,无法保护类型本身的存在
|
||
```
|
||
|
||
### 正确的做法
|
||
|
||
```swift
|
||
// ✅ 方法 1: 使用与旧版本兼容的类型
|
||
private var callbacks: [() -> Void] = []
|
||
|
||
// ✅ 方法 2: 使用条件编译(但会增加代码复杂度)
|
||
#if swift(>=5.5)
|
||
private var continuation: CheckedContinuation<Void, Never>?
|
||
#endif
|
||
```
|
||
|
||
## 🚀 完成标志
|
||
|
||
当你完成所有修改后:
|
||
|
||
- [ ] Deployment Target 已改为 12.0
|
||
- [ ] AppTrackingTransparency 已设为 Optional
|
||
- [ ] 运行 `pod install` 完成
|
||
- [ ] 清理并重新编译成功
|
||
- [ ] 在 iOS 12/13 模拟器或真机上运行成功
|
||
- [ ] 看到完整的日志输出,包括 "XS- init config"
|
||
|
||
## 📚 相关文档
|
||
|
||
- [iOS12_COMPATIBILITY_GUIDE.md](./iOS12_COMPATIBILITY_GUIDE.md) - 详细配置指南
|
||
- [DEBUG_CRASH_GUIDE.md](./DEBUG_CRASH_GUIDE.md) - 调试崩溃指南
|
||
- [CHANGES_SUMMARY.md](./CHANGES_SUMMARY.md) - 完整修改记录
|
||
|
||
---
|
||
|
||
**关键修复完成时间:** 2025-01-01
|
||
**修复的根本问题:** Swift Concurrency 类型在 iOS 12 上不可用
|
||
**测试状态:** 代码已完成,待 Xcode 配置和测试
|