首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在ios设备中测试不使用调试功能的bgtaskscheduler功能

如何在ios设备中测试不使用调试功能的bgtaskscheduler功能
EN

Stack Overflow用户
提问于 2021-12-05 01:08:51
回答 1查看 425关注 0票数 1

在我的ios设备非模拟器中使用调试功能时,我没有问题。(ex,e -l objc -)[BGTaskScheduler sharedScheduler BGTaskScheduler)

但是当不使用调试函数时,按照我的代码,它将在60秒后播放音乐到后台。然而,在设备中没有发生任何事情。

如何测试不使用调试功能的设备?

代码语言:javascript
复制
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()
    }
}
EN

回答 1

Stack Overflow用户

发布于 2021-12-06 14:11:53

FYI,BGAppResfreshTask用于“用小信息更新应用程序”,即执行一个小的网络请求来刷新应用程序,以便当用户下次启动应用程序时,您已经准备好了更多的最新信息并等待它们。但是这个应用程序刷新是在操作系统根据多种因素选择的时间内执行的,但不早于earliestBeginDate

因此,闹钟是不合适的,因为(a)您没有进行网络请求刷新您的应用程序;和(b)它不能保证在指定的“最早”日期运行,只有一段时间之后。

您可以考虑调度一个用户通知,而不是。

你问:

如何测试不使用调试功能的设备?

添加日志语句。但是,与其使用printNSLog,不如添加Logger语句,就像WWDC 2020 探索Swift中的日志记录中讨论的那样。(或者,如果在iOS 14之前支持iOS版本,则使用os_log;这在WWDC 2016视频统一日志记录和活动跟踪中已经描述过,但该视频已不再可用。)这些从Logger应用程序发出的iOS /os_log日志记录语句可以从macOS控制台应用程序中监视。

因此,一旦您使用Logger (或os_log)在代码中添加了日志记录消息,就可以使用

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

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

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

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70230772

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档