如何在 ios 设备中测试不使用调试功能的 bgtaskscheduler 功能
Posted
技术标签:
【中文标题】如何在 ios 设备中测试不使用调试功能的 bgtaskscheduler 功能【英文标题】:how to test in ios device about bgtaskscheduler function not using debug function 【发布时间】:2022-01-10 19:02:25 【问题描述】:在我的 ios 设备而非模拟器中使用调试功能时没有问题。 (例如,e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"TASK_IDENTIFIER"])
但是当不使用调试功能时,按照我的代码,它将在进入后台 60 秒后播放音乐。但是设备中没有发生任何事情。
如何测试不使用调试功能的设备?
import UIKit
import BackgroundTasks
import os.log
import AVFoundation
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "AppDelegate")
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
let bgTaskIdentifier = "com.hakjun.bgTest.playMusic"
var alarmTime : Int = 0
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
// Override point for customization after application launch.
BGTaskScheduler.shared.register(forTaskWithIdentifier: bgTaskIdentifier, using: nil) task in
self.handleAppRefresh(task: task as! BGAppRefreshTask)
print("test bg")
return true
func scheduleAppRefresh(time : Double)
let request = BGAppRefreshTaskRequest(identifier: bgTaskIdentifier)
request.earliestBeginDate = Date(timeIntervalSinceNow: time)
do
try BGTaskScheduler.shared.submit(request)
print("schedule app refresh")
catch
print("Could not schedule app refresh task \(error.localizedDescription)")
func handleAppRefresh(task : BGAppRefreshTask)
scheduleAppRefresh(time: 60)
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
let appRefreshOperation = BlockOperation
Singleton.sharedInstance.play()
// queue.addOperation(appRefreshOperation)
task.expirationHandler =
print("expire background")
queue.cancelAllOperations()
let lastOperation = queue.operations.last
lastOperation?.completionBlock =
task.setTaskCompleted(success: !(lastOperation?.isCancelled ?? false))
print("background handle")
queue.addOperation(appRefreshOperation)
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>)
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
func applicationDidEnterBackground(_ application: UIApplication)
print("test bg os log2")
logger.log("App did enter background")
scheduleAppRefresh(time: 60)
class Singleton
static let sharedInstance = Singleton()
private var player: AVAudioPlayer?
func play()
let audioSession = AVAudioSession.sharedInstance()
guard let url = Bundle.main.url(forResource: "alarm2", withExtension: "mp3") else return
do
try audioSession.setCategory(.playback, mode: .default, options: [])
catch let error as NSError
print("audioSession 설정 오류 : \(error.localizedDescription)")
do
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
try AVAudioSession.sharedInstance().setActive(true)
player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
guard let player = player else return
player.play()
catch let error
print(error.localizedDescription)
func stop()
player?.stop()
【问题讨论】:
此音乐仅用于诊断目的吗?我问,因为这不是BGAppRefreshTaskRequest
的用途。首先,它的运行时间由操作系统自行决定(可能要等到很久很久以后)。其次,这不是在后台播放音乐的正确工具。这只会使应用程序在最终触发时在后台运行几秒钟/几分钟。
第三,如果我没看错你的代码,看起来你是在开始歌曲后立即结束后台任务。这是你的意图吗?这似乎不对。或者您是否打开了背景音乐播放作为背景功能?
感谢您的评论,我正在制作一个闹钟应用程序,实际上音乐应该在设置为闹钟的时间播放。以上代码写成bgtaskschedular示例代码,进入后台1分钟后生成了BGAppRefreshTaskRequest。在闹钟应用程序中,它将是设置为闹钟的时间。那我应该用BG Processing Task在后台特定时间播放音乐吗?
那么,BGAppRefreshTask
肯定不是正确的工具。请参阅下面的答案。
【参考方案1】:
仅供参考,BGAppResfreshTask
用于“使用少量信息更新您的应用程序”,即执行一个小的网络请求以刷新您的应用程序,以便在用户下次启动应用程序时,您可以准备好更多当前信息并等待他们。但此应用刷新是在操作系统根据多种因素自行选择的时间执行的,但不得早于earliestBeginDate
。
因此不适合闹钟,因为 (a) 您没有发出网络请求来刷新您的应用; (b) 不能保证在指定的“最早”日期运行,只能在之后的某个时间运行。
您可以考虑改为安排user notification。
你问:
如何测试不使用调试功能的设备?
您添加日志记录语句。但与其使用print
或NSLog
,不如添加Logger
语句,如WWDC 2020 Explore logging in Swift 中所述。 (或者,如果支持 iOS 14 之前的 iOS 版本,请使用 os_log
;这在 WWDC 2016 视频 Unified Logging and Activity Tracing 中有描述,但该视频不再可用。)这些 Logger
/os_log
从 iOS 应用发出的日志记录语句可以从 macOS 控制台应用进行监控。
因此,一旦您在相关位置的代码中添加了日志消息,使用Logger
(或os_log
),您就可以
请参阅Swift: print() vs println() vs NSLog() 中的第 3 点和第 4 点。
但请注意,您不想从 Xcode 运行应用程序。您可以通过从 Xcode 运行它来安装它,然后停止执行并直接在设备上重新启动应用程序,而不是使用 Xcode。不幸的是,附加到 Xcode 调试器后,应用程序会在后台人为地运行,而在设备上独立运行时,它实际上会被挂起。因此,在物理设备上测试后台执行时,不要直接从 Xcode 调试它,而是添加日志语句,直接从设备启动应用程序,并在 macOS 控制台中查看日志语句。
另外,有时后台进程会在数小时后发生,因此我偶尔也会将日志语句写入应用程序支持目录中的文本文件,并稍后重新访问该文件(稍后将容器下载回我的 Mac)。对于后台获取和后台任务(可能在数小时或数天后发生),这可能很有用。但是,对于警报应用程序,上面概述的 macOS 控制台方法是最简单的。
【讨论】:
以上是关于如何在 ios 设备中测试不使用调试功能的 bgtaskscheduler 功能的主要内容,如果未能解决你的问题,请参考以下文章