【问题标题】:how to test in ios device about bgtaskscheduler function not using debug function如何在 ios 设备中测试不使用调试功能的 bgtaskscheduler 功能
【发布时间】: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 肯定不是正确的工具。请参阅下面的答案。

标签: swift iphone bgtaskscheduler


【解决方案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),您就可以

  • 在您的设备上安装应用,
  • 将设备连接到您的计算机,
  • 直接从您的设备启动应用并
  • 您可以在 macOS 控制台中查看您的应用发出的日志语句。

请参阅Swift: print() vs println() vs NSLog() 中的第 3 点和第 4 点。

但请注意,您不想从 Xcode 运行应用程序。您可以通过从 Xcode 运行它来安装它,然后停止执行并直接在设备上重新启动应用程序,而不是使用 Xcode。不幸的是,附加到 Xcode 调试器后,应用程序会在后台人为地运行,而在设备上独立运行时,它实际上会被挂起。因此,在物理设备上测试后台执行时,不要直接从 Xcode 调试它,而是添加日志语句,直接从设备启动应用程序,并在 macOS 控制台中查看日志语句。

另外,有时后台进程会在数小时后发生,因此我偶尔也会将日志语句写入应用程序支持目录中的文本文件,并稍后重新访问该文件(稍后将容器下载回我的 Mac)。对于后台获取和后台任务(可能在数小时或数天后发生),这可能很有用。但是,对于警报应用程序,上面概述的 macOS 控制台方法是最简单的。

【讨论】:

    猜你喜欢
    • 2011-04-13
    • 1970-01-01
    • 1970-01-01
    • 2022-11-11
    • 1970-01-01
    • 2020-12-18
    • 1970-01-01
    • 2011-11-03
    • 1970-01-01
    相关资源
    最近更新 更多