XuqmCoreSDK - 新增 userId / token(nonisolated) / deviceId 公开属性,对齐 BugCollectSDK / WebViewSDK 引用 XuqmWebViewSDK - XWebViewTypes:新增 jsBridgeName / onClose / onPageError / onProgressChanged / onNavigationChanged - XWebViewView:注册双 bridge(ReactNativeWebView 内部 + 自定义 jsBridgeName)、KVO progress、nav delegate - XWebViewStandardHandlers:@MainActor,injectedJavaScript 改 nonisolated,兼容 macOS - 新增 import XuqmCoreSDK XuqmBugCollectSDK - 全局 #if canImport(UIKit) 兼容 macOS 编译 - isReady 从 computed var 改为 func 消除歧义 - LogQueue 修正 LogStorage 为 enum 静态方法调用 XuqmUpdateSDK - getDeviceInfo() #if canImport(UIKit) 兼容 macOS XuqmLicenseSDK - ensureInitializedFromSDK() 用 DispatchQueue.main.sync 访问 @MainActor 属性 CI - 重写 Jenkinsfile:增加 SNAPSHOT/Release 模式,统一版本号管理,修正 git URL,对齐 Android 流水线 - 新增 version.properties:统一追踪 SDK_VERSION - 更新 .gitignore:移除 JS/Java 噪音,补 Swift/Xcode 规则 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
99 行
2.4 KiB
Swift
99 行
2.4 KiB
Swift
import Foundation
|
|
|
|
/// 日志队列 - 内存队列 + 定时上传
|
|
final class LogQueue {
|
|
|
|
private let appKey: String
|
|
private let sdkName: String
|
|
private let sdkVersion: String
|
|
private let uploader: LogUploader
|
|
|
|
private var queue: [Any] = []
|
|
private let queueLock = NSLock()
|
|
private var timer: Timer?
|
|
private let flushInterval: TimeInterval = 30
|
|
private let maxQueueSize = 50
|
|
|
|
init(appKey: String, sdkName: String, sdkVersion: String) {
|
|
self.appKey = appKey
|
|
self.sdkName = sdkName
|
|
self.sdkVersion = sdkVersion
|
|
self.uploader = LogUploader(appKey: appKey)
|
|
}
|
|
|
|
/// 启动定时上传
|
|
func start() {
|
|
// 上传待处理的崩溃
|
|
uploadPendingCrashes()
|
|
|
|
// 启动定时器
|
|
timer = Timer.scheduledTimer(withTimeInterval: flushInterval, repeats: true) { [weak self] _ in
|
|
self?.flush()
|
|
}
|
|
}
|
|
|
|
/// 停止队列
|
|
func stop() {
|
|
timer?.invalidate()
|
|
timer = nil
|
|
flush()
|
|
}
|
|
|
|
/// 推送事件
|
|
func push(_ event: Any) {
|
|
queueLock.lock()
|
|
queue.append(event)
|
|
let count = queue.count
|
|
queueLock.unlock()
|
|
|
|
// 达到阈值时自动上传
|
|
if count >= maxQueueSize {
|
|
flush()
|
|
}
|
|
}
|
|
|
|
/// 刷新队列
|
|
private func flush() {
|
|
queueLock.lock()
|
|
let events = queue
|
|
queue = []
|
|
queueLock.unlock()
|
|
|
|
guard !events.isEmpty else { return }
|
|
|
|
// 分离 issues 和 events
|
|
var issues: [IssueEvent] = []
|
|
var logEvents: [LogEvent] = []
|
|
|
|
for event in events {
|
|
if let issue = event as? IssueEvent {
|
|
issues.append(issue)
|
|
} else if let logEvent = event as? LogEvent {
|
|
logEvents.append(logEvent)
|
|
}
|
|
}
|
|
|
|
// 上传 issues
|
|
if !issues.isEmpty {
|
|
uploader.uploadIssues(issues)
|
|
}
|
|
|
|
// 上传 events
|
|
if !logEvents.isEmpty {
|
|
uploader.uploadEvents(logEvents)
|
|
}
|
|
}
|
|
|
|
/// 上传待处理的崩溃
|
|
private func uploadPendingCrashes() {
|
|
let crashes = LogStorage.loadPendingCrashes()
|
|
guard !crashes.isEmpty else { return }
|
|
|
|
uploader.uploadIssues(crashes) { success in
|
|
if success {
|
|
LogStorage.clearPendingCrashes()
|
|
}
|
|
}
|
|
}
|
|
}
|