watchconnectivity - WKWatchConnectivityRefreshBackgroundTask is never triggered in background, but WKSnapshotRefreshBackgroundTask -


i want update watch app state in background iphone, using session.updateapplicationcontext(applicationcontext).

sending application contact while app on watch active work properly.
when activate home button on watch, watch app goes background, handle(_ backgroundtasks: set<wkrefreshbackgroundtask>) called, , wksnapshotrefreshbackgroundtask provided.

so don’t understand why wksnapshotrefreshbackgroundtask triggered properly, not wkwatchconnectivityrefreshbackgroundtask.

apple’s docswhen receive background data paired iphone, system launches app in background, instantiates wkwatchconnectivityrefreshbackgroundtask object, , passes task object extension delegate’s handlebackgroundtasks: method.“.

but not happen, neither on device, nor on simulator. wrong?

edit:

to check might wrong, downloaded apple’s demo project „quickswitch“ can downloaded here. here code should handle background tasks:

func handle(_ backgroundtasks: set<wkrefreshbackgroundtask>) {     backgroundtask in backgroundtasks {         if let wcbackgroundtask = backgroundtask as? wkwatchconnectivityrefreshbackgroundtask {             // store reference task objects might have wait complete them             self.wcbackgroundtasks.append(wcbackgroundtask)         } else {             // complete other task types have not added support them             backgroundtask.settaskcompleted()         }     }     completealltasksifready() } 

there, same happens:
did set breakponint in line of if statement , executed app.
when home button on watch simulator pressed, breakpoint reached wksnapshotrefreshbackgroundtask. ok (see above).
however, if different line selected on iphone simulator, watchos not schedule wkwatchconnectivityrefreshbackgroundtask, expected. after all, demo project should demo point.
maybe try demo project , confirm problem or not.

what wrong?

update answer


conclusion first

currently wkwatchconnectivityrefreshbackgroundtask called sure on watchos simulator when watchos extension's wcsession in notactivated state , extension not running in foreground (in background or terminated).

in real devices, won't called in tests. apple docs says may. shouldn't rely on won't called until apple changes docs.

wcsession cores

wcsession core

for wcsession, when activated, can transfer userinfo, , when counterpart active, can userinfo. counterpart won't need in foreground activated, can in high priority background.

testing results

here testing results.

in simulators , in devices

how make wcsession notactivated?

  1. using xcode terminate watchos extension. xcode send kill signal wkextension.
  2. or don't run wcsession.activate() in code on watchos extension side. wcsession notactivated default.

-------------below old post, can ignore safely if don't want read.-------------------

theory

enter image description here

please watch picture first explain.

because of history of watchos, there both wcsessiondelegate receiving functions (start watchos 2.0) , wkextensiondelegate.handle(_:) function (start watchos 3.0).

although claims background dealing, former works when app in foreground. data queued if app not in foreground (in background or being terminated) , executed later when app becomes in foreground again.

wkextensiondelegate.handle(_:) working in background. however, wkextensiondelegate.handle(_:) optional although recommended , well-prepared if use xcode.

if don't implement wkextensiondelegate.handle(_:) commenting it. app works in watchos 2.0 way.

if implement wkextensiondelegate.handle(_:) don't have wcsession in watchos app. result tricky. won't data when watchos app in foreground, don't has wcsession. when app in background, waken when data comes, can't data don't have session.

if implemented them both, in situations, data comes dealt depending on state of watchos app , never queued.


how proving it?

create new watchos project. in ios part, add button, each time clicked button, send userinfo watchos

session.transferuserinfo(["send test":""]) 

in watchos app, add label in interface.storyboard, , drag viewcontroller @iboutlet var label: wkinterfacelabel!, , implement both wkextensiondelegate.handle(_:) , func session(wcsession, didreceiveuserinfo: [string : any] = [:]) appdelegate.

var total = 0  func handle(_ backgroundtasks: set<wkrefreshbackgroundtask>) {     // sent when system needs launch application in background process tasks. tasks arrive in set, loop through , process each one.     task in backgroundtasks {         // use switch statement check task type         switch task {         case let backgroundtask wkapplicationrefreshbackgroundtask:             // sure complete background task once you’re done.             backgroundtask.settaskcompleted()         case let snapshottask wksnapshotrefreshbackgroundtask:             // snapshot tasks have unique completion call, make sure set expiration date             snapshottask.settaskcompleted(restoreddefaultstate: true, estimatedsnapshotexpiration: date.distantfuture, userinfo: nil)         case let connectivitytask wkwatchconnectivityrefreshbackgroundtask:             // sure complete connectivity task once you’re done.             total += 1             dispatchqueue.main.async {                 if let viewcontroller = wkextension.shared().rootinterfacecontroller as? interfacecontroller {                     viewcontroller.label.settext(string(self.total))                 }             }              connectivitytask.settaskcompleted()         case let urlsessiontask wkurlsessionrefreshbackgroundtask:             // sure complete url session task once you’re done.             urlsessiontask.settaskcompleted()         default:             // make sure complete unhandled task types             task.settaskcompleted()         }     } }  public func session(_ session: wcsession, didreceiveuserinfo userinfo: [string : any] = [:]) {     total += 4     dispatchqueue.main.async {         if let viewcontroller = wkextension.shared().rootinterfacecontroller as? interfacecontroller {             viewcontroller.label.settext(string(self.total))         }     } } 

if wkextensiondelegate.handle(_:) runs, add total 1. if func session(wcsession, didreceiveuserinfo: [string : any] = [:]) runs, add total 4.

debug

in xcode, choose product->scheme watchkit app can terminate watchos app in xcode.

  1. run project.
  2. when watchos app shows, open ios app manually.
  3. clicked button in ios app. can see label in watchos changes 4.
  4. in xcode, click product->stop(or cmd+.). watchos app disappear.
  5. click 1 or more times on ios app's button. manually open watchos app. see time label changes 1 multiply clicks.
  6. the step 4 again when watchos app in foreground.

Comments

Popular posts from this blog

sql server - Cannot query correctly (MSSQL - PHP - JSON) -

php - trouble displaying mysqli database results in correct order -

C++ Linked List -