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