0

我正在尝试在后台模式下运行我的手表应用程序。对于开始这样做,我从这个苹果直营店复制的例子:WKRefreshBackgroundTask无法正常工作

https://developer.apple.com/library/content/samplecode/WatchBackgroundRefresh/Listings/WatchBackgroundRrefresh_WatchKit_Extension_MainInterfaceController_swift.html#//apple_ref/doc/uid/TP40017295-WatchBackgroundRrefresh_WatchKit_Extension_MainInterfaceController_swift-DontLinkElementID_10

但它不工作。这是我的代码:

import WatchKit 
import Foundation 

class InterfaceController: WKInterfaceController, WKExtensionDelegate, URLSessionDownloadDelegate { 

@IBOutlet var unlink: WKInterfaceLabel! 

@IBAction func startActivity() { 
    // fire in 20 seconds 
    let fireDate = Date(timeIntervalSinceNow: 20.0) 
    // optional, any SecureCoding compliant data can be passed here 
    let userInfo = ["reason" : "background update"] as NSDictionary 

    WKExtension.shared().scheduleBackgroundRefresh(withPreferredDate: fireDate, userInfo: userInfo) { (error) in 
     if (error == nil) { 
      print("successfully scheduled background task, use the crown to send the app to the background and wait for handle:BackgroundTasks to fire.") 
     } 
    } 
} 

let sampleDownloadURL = URL(string: "http://devstreaming.apple.com/videos/wwdc/2015/802mpzd3nzovlygpbg/802/802_designing_for_apple_watch.pdf?dl=1")! 

// MARK: WKInterfaceController 

override func awake(withContext context: Any?) { 
    super.awake(withContext: context) 

    // Configure interface objects here. 
    WKExtension.shared().delegate = self 
    updateDateLabel() 
} 

let sampleDownloadURL = URL(string: "http://devstreaming.apple.com/videos/wwdc/2015/802mpzd3nzovlygpbg/802/802_designing_for_apple_watch.pdf?dl=1")! 

// MARK: WKExtensionDelegate 
func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) { 
    for task : WKRefreshBackgroundTask in backgroundTasks { 
     print("received background task: ", task) 
     // only handle these while running in the background 
     if (WKExtension.shared().applicationState == .background) { 
      if task is WKApplicationRefreshBackgroundTask { 
       // this task is completed below, our app will then suspend while the download session runs 
       print("application task received, start URL session") 
       scheduleURLSession() 
      } 
     } 
     else if let urlTask = task as? WKURLSessionRefreshBackgroundTask { 
      let backgroundConfigObject = URLSessionConfiguration.background(withIdentifier: urlTask.sessionIdentifier) 
      let backgroundSession = URLSession(configuration: backgroundConfigObject, delegate: self, delegateQueue: nil) 

      print("Rejoining session ", backgroundSession) 
     } 
     // make sure to complete all tasks, even ones you don't handle 
     task.setTaskCompleted() 
    } 
} 

// MARK: Snapshot and UI updating 

func scheduleSnapshot() { 
    // fire now, we're ready 
    let fireDate = Date() 
    WKExtension.shared().scheduleSnapshotRefresh(withPreferredDate: fireDate, userInfo: nil) { error in 
     if (error == nil) { 
      print("successfully scheduled snapshot. All background work completed.") 
     } 
    } 
} 

func updateDateLabel() { 
    let currentDate = Date() 
    self.unlink.setHidden(false) 
    unlink.setText(dateFormatter.string(from: currentDate)) 
} 

// MARK: URLSession handling 

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { 
    print("NSURLSession finished to url: ", location) 
    updateDateLabel() 
    scheduleSnapshot() 
} 

func scheduleURLSession() { 
    let backgroundConfigObject = URLSessionConfiguration.background(withIdentifier: NSUUID().uuidString) 
    backgroundConfigObject.sessionSendsLaunchEvents = true 
    let backgroundSession = URLSession(configuration: backgroundConfigObject) 

    let downloadTask = backgroundSession.downloadTask(with: sampleDownloadURL) 
    downloadTask.resume() 
} 

} 

它打印成功调度后台任务,使用冠应用程序发送到后台,等待句柄:BackgroundTasks火,然后我的应用程序发送到后台,但从来没有输入处理方法。

有什么帮助?谢谢!!!

回答

0

我从来没有得到过Apple的例子。但我确实使用下面的代码进行了后台刷新。请注意,与Apple的例子不同,您需要在后台会话中让自己成为代表。 (你也不需要Swift中的“self”,我只是在这里用它来表示属性/函数)。

var backgroundUrlSession:URLSession? 
var pendingBackgroundURLTask:WKURLSessionRefreshBackgroundTask? 

func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) { 

    for task in backgroundTasks { 
     if let refreshTask = task as? WKApplicationRefreshBackgroundTask { 
      // this task is completed below, our app will then suspend while the download session runs 
      print("application task received, start URL session") 

      if let request = self.getRequestForRefresh() { 
       let backgroundConfig = URLSessionConfiguration.background(withIdentifier: NSUUID().uuidString) 
       backgroundConfig.sessionSendsLaunchEvents = true 
       backgroundConfig.httpAdditionalHeaders = ["Accept":"application/json"] 
       //Be sure to set self as delegate on this urlSession 
       let urlSession = URLSession(configuration: backgroundConfig, delegate: self, delegateQueue: nil) 
       let downloadTask = urlSession.downloadTask(with: request) 

       print("Dispatching data task at \(self.getTimestamp())") 
       downloadTask.resume() 
      } 
      self.scheduleNextBackgroundRefresh(refreshDate: self.getNextPreferredRefreshDate()) 
      refreshTask.setTaskCompleted() 
     } 
     else if let urlTask = task as? WKURLSessionRefreshBackgroundTask   
     { 
      //awakened because background url task has completed 
      let backgroundConfigObject = URLSessionConfiguration.background(withIdentifier: urlTask.sessionIdentifier) 
      //Be sure to set self as delegate on this urlSession 
      self.backgroundUrlSession = URLSession(configuration: backgroundConfigObject, delegate: self, delegateQueue: nil) //set to nil in task:didCompleteWithError: delegate method 

      print("Rejoining session ", self.backgroundUrlSession as Any) 
      self.pendingBackgroundURLTask = urlTask //Saved for .setTaskComplete() in downloadTask:didFinishDownloadingTo location: (or if error non nil in task:didCompleteWithError:) 

     } else { 
      //else different task, not handling but must Complete all tasks (snapshot tasks hit this logic) 
      task.setTaskCompleted() 
     } 
    } 
} 

func getRequestForRefresh() -> URLRequest? { 

    guard let url = URL(string: "https://pokeapi.co/api/v2/pokemon") else{ 
     return nil 
    } 

    return URLRequest(url: url) 
} 

// MARK: URLSession handling 

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { 
    print("NSURLSession finished to url: ", location) 
    updateDateLabel() 
    scheduleSnapshot() 

    self.pendingBackgroundURLTask.setTaskCompleted() 
    self.backgroundUrlSession = nil 
} 

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { 
    if error != nil { 
     self.pendingBackgroundURLTask.setTaskCompleted() 
     self.backgroundUrlSession = nil 
    } 
} 

还没有打印/断点我有时打任务:didCompleteWithError错误:喜欢毫秒我打downloadTask前:didFinishDownloadingTo位置:.

因此,我改为在downloadTask中完成self.pendingBackgroundURLTask:didFinishDownloadingTo location :.我只在任务中将其设置完成:didCompleteWithError错误:if error!= nil。我已经更新了我的答案,也包含了这个逻辑。

希望这可以帮助你。它正在为我们生产。

+0

请分享一下这两个函数的代码(*** getRequestForRefresh()***和*** scheduleNextBackgroundRefresh()***)和这两个变量的初始化*(*** backgroundUrlSession ***和*** pendingBackgroundURLTask ***) – ainovela

+0

对于两个变量,我不初始化它们,而是将它们声明为可选项。我无法分享getRequestForRefresh(),但我会更新我的答案以显示我将为您的代码执行的操作。 scheduleNextBackgrounRefresh()方法只调用WKExtension.shared()。scheduleBackgroundRefresh(withPreferredDate:与您在startActivity方法中执行的方式相同,但在下一次计算的日期和时间内应该尝试刷新(您总是希望先安排下一次刷新设置完成WKApplicationRefreshBackgroundTask)。 – CodenameDuchess