You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

iOS后台上传时无法通过Live Activities实时追踪进度的问题求助

iOS后台上传时无法通过Live Activities实时追踪进度的问题求助

嘿,这个问题我之前做类似功能时也踩过坑,来给你捋捋思路和解决方案~

首先得明确一个核心点:后台URLSession的设计逻辑不是让APP在后台持续获取实时进度回调。当APP进入后台后,系统会暂停APP的大部分代码执行,包括URLSessionTaskDelegate里的进度更新方法——只有当任务完成、失败,或者系统需要唤醒APP处理关键事件(比如任务需要认证)时,才会通过application(_:handleEventsForBackgroundURLSession:completionHandler:)唤醒你的APP。这就是为什么你后台几秒后看不到进度更新,但切回前台进度会立刻同步的原因,属于系统的正常限制。

那要在后台实时更新Live Activities的进度,得绕开这个限制,这里有几个可行的方案:

方案1:用BackgroundTasks框架定期唤醒APP更新进度

这是不需要后端支持的本地方案,适合对实时性要求不是特别高的场景:

  • 第一步,在Info.plist里声明允许的后台任务标识符,比如添加BGTaskSchedulerPermittedIdentifiers数组,里面放com.yourcompany.upload-progress
  • 第二步,在APP启动时注册这个后台任务:
    BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.yourcompany.upload-progress", using: nil) { task in
        self.handleUploadProgressUpdate(task as! BGAppRefreshTask)
    }
    
  • 第三步,上传开始时,调度第一个后台刷新任务:
    let refreshRequest = BGAppRefreshTaskRequest(identifier: "com.yourcompany.upload-progress")
    refreshRequest.earliestBeginDate = Date(timeIntervalSinceNow: 30) // 30秒后第一次唤醒,可按需调整
    do {
        try BGTaskScheduler.shared.submit(refreshRequest)
    } catch {
        print("提交后台任务失败:\(error.localizedDescription)")
    }
    
  • 第四步,实现任务处理方法,更新Live Activities并重新调度下一次任务:
    func handleUploadProgressUpdate(_ task: BGAppRefreshTask) {
        // 获取当前上传任务的进度
        if let uploadTask = yourActiveUploadTask, let progress = uploadTask.progress {
            // 更新Live Activities
            let activityAttributes = YourUploadActivityAttributes()
            let activityState = YourUploadActivityState(progress: progress.fractionCompleted)
            Task {
                let targetActivity = try? Activity<YourUploadActivityAttributes>.activities.first(where: { $0.id == yourActivityID })
                await targetActivity?.update(using: activityState)
            }
        }
        // 重新调度下一次任务,保证后续还能更新
        let nextRefreshRequest = BGAppRefreshTaskRequest(identifier: "com.yourcompany.upload-progress")
        nextRefreshRequest.earliestBeginDate = Date(timeIntervalSinceNow: 30)
        do {
            try BGTaskScheduler.shared.submit(nextRefreshRequest)
        } catch {
            print("重新提交后台任务失败:\(error.localizedDescription)")
        }
        // 标记任务完成,避免系统惩罚
        task.setTaskCompleted(success: true)
    }
    
    注意:后台任务的唤醒频率由系统管控,不能保证严格按时执行,而且每次唤醒的执行时间有限(大概30秒内),所以适合分钟级的进度更新。

方案2:结合后端推送实现更实时的进度更新

如果你的项目有后端服务,这种方式能实现更接近实时的进度同步:

  • 让后端在上传进度有明显变化时,给设备发送静默推送通知(注意要设置推送的content-available: 1字段)。
  • 在APP里配置好远程推送权限,同时开启“Background App Refresh”权限。
  • 当APP收到静默推送时,在didReceiveRemoteNotification或者userNotificationCenter(_:didReceive:withCompletionHandler:)方法里,解析推送里的进度数据,然后更新Live Activities。
    这种方式的优势是进度更新更及时,但依赖后端的配合,还要处理推送丢失、延迟等可靠性问题。

方案3:调整URLSession配置的小细节(效果有限)

你当前的配置已经比较合理了,不过可以试试这两个小调整,可能会稍微改善进度回调的频率:

  • 确保config.httpMaximumConnectionsPerHost = 1,避免系统合并请求导致进度回调被合并。
  • 检查是否开启了APP的“Background App Refresh”权限,这个是后台任务和推送能正常工作的前提。

最后还要提醒下:Live Activities本身也有更新频率的限制,后台时系统可能会延迟显示更新内容,所以即使你拿到了进度,也不是立刻就能在锁屏上看到的。另外更新Live Activities时,一定要用异步的await activity?.update(using: state)方法,避免阻塞主线程。

备注:内容来源于stack exchange,提问作者Yuri Frota

火山引擎 最新活动