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 docs „when 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
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.
how make wcsession notactivated?
- using xcode terminate watchos extension. xcode send kill signal wkextension.
- or don't run
wcsession.activate()in code on watchos extension side.wcsessionnotactivateddefault.
-------------below old post, can ignore safely if don't want read.-------------------
theory
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.
- run project.
- when watchos app shows, open ios app manually.
- clicked button in ios app. can see
labelin watchos changes 4. - in xcode, click
product->stop(or cmd+.). watchos app disappear. - click 1 or more times on ios app's button. manually open watchos app. see time
labelchanges 1 multiply clicks. - the step 4 again when watchos app in foreground.



Comments
Post a Comment