Post

Replies

Boosts

Views

Activity

Reply to CGPathAddPath in a loop extremely slow
I have similar issues. I have a view drawing lots of simple lines, working just OK performance wise. But if I draw ellipses instead (commented out line below), the code slows down considerably. func path(in rect: CGRect) -> Path {       var path = Path() 			// ...       path.addLine(to: CGPoint(x: xOrigin + xTarget, y: yOrigin))       // path.addEllipse(in: CGRect(origin: CGPoint(x: xOrigin + xTarget, y: yOrigin-1), size: CGSize(width: 3, height: 3))) Most of the time (84.9% according to Instruments profiler ) is spent in CG::Path::recalculate_bounding_box(). Any hints on how to draw repeatedly and effectively hundreds of rects using Path?
Jun ’20
Reply to WatchOS: background refresh file is downloaded but didFinishDownloadingTo: never called...
Same issue with my app. I can see from the logs that just before the error, system is looking at the Info.plist file of the app and then notifies about the "not support BAR" -- should I have something in the Info.plist to tell the system the app supports launching from the background? unixio debug 20:21:49.342657+0300 com.apple.securityd Carousel open(/private/var/containers/Bundle/Application/C8EF6D34-73C3-45C7-A669-0E501F622A44/Xxxx WatchKit App.app/Info.plist,0x0,0x1b6) = 37 workspace error 20:21:49.356798+0300 com.apple.Carousel Carousel com.myorg.MyApp.watchkitapp: app does not support BAR, not creating action for reason CSLSDuetActivationReasonComplication -- openApplicationOptions: { 		CSLSDuetActivationServiceReasons =		 ( 				CSLSDuetActivationReasonComplication 		); 		"__ActivateSuspended" = 1; 		"__PayloadOptions" =		 { 				budgetdictionary = "/watch/budget/launches"; 				kCSLBackgroundActivityUUID = "089EE1D6-7B07-46AE-9889-90847D350D99"; 				kCSLBackgroundActivityUserString = "E4D6101A-7ACD-495F-AB7C-6571A042DA48"; 		}; }
Jul ’20
Reply to WatchOS: background refresh file is downloaded but didFinishDownloadingTo: never called...
I do not have the background modes on, since my app does not fulfill those use cases listed there. My app just needs to download a small JSON every 30-60 minutes and process it (environmental data). Reading the docs and watching the videos on the topic do not explicitly mention anywhere that background processing should be set nor required. Unless your app runs "constantly". Anyways, after extension is woken up to handle the background processing, the URLSession task is handled in the background in nsulrsessiond daemon when requested (after say 30 mins) and when the download task completes, system should wake up the app to handle the downloaded content. Though I am starting to suspect that this is not the case because of that log error I posted. Alternatively (and hopefully), the system yet does not yet support this but will in the final watchOS 7. My interpretation is that background modes are not needed, but the watch face must have a complication from your app and/or it should be in the doc (recently used) to background URLSession downloads to happen as requested. And even then, system may decide that app requests are not processed according to the schedule (battery low, bad network, app has made too many requests or using too much CPU, .... I do not know where "BAR" comes from, but it is used in one of the WWDC2020 videos in the sample code. And since it is visible in the logs, it must be something the system "knows". Haven't found any explanation of what it is about. Sample code used the term BAR too, e.g. in my code where the function name is from the sample code:    private func scheduleBAR(_ first: Bool) {       logger.debug("ExtensionDelegate: scheduling background data refresh.")       let now = Date()       let timeInterval = first ? 5.0 : 15.0 * 60.0       let scheduledDate = now.addingTimeInterval(timeInterval)       let info: NSDictionary = ["submissionDate": now]       let wkExt = WKExtension.shared()       wkExt.scheduleBackgroundRefresh(withPreferredDate: scheduledDate, userInfo: info) { (error: Error?) in          if error != nil {             self.logger.error("background refresh could not be scheduled: \(error.debugDescription)")          } else {             self.logger.info("background refresh scheduled successfully after \(timeInterval) secs")          }       }    }
Jul ’20
Reply to Unkown WKExtension Error
Yes, I have the same issue. My watchOS app has no iPhone companion app at all. Are you using SwiftUI? How do you declare you extension? I have the ExtensionDelegate class name listed in the extension's Info.plist and then in the App: @main struct MyWatchApp: App {    @StateObject private var dataProvider = AppDataProvider.shared    @WKExtensionDelegateAdaptor(ExtensionDelegate.self) var extensionDelegate My other issue is that the extension delegate is launching background operations using URLSession, but these are not initiated. Trying to find out where I am doing wrong... Perhaps this way of declaring/creating the extension delegate is not the right way with the new SwiftUI watch apps?
Jul ’20
Reply to WatchOS: background refresh file is downloaded but didFinishDownloadingTo: never called...
No luck. Still refusing to launch my extension/bg functionality (see log below at line 12). I also noticed this error in the logs: [WKExtension sharedExtension]:38: Extensionless WatchKit apps should use WKApplication Which is also discussed in another thread - https://developer.apple.com/forums/thread/655476?login=true&amp;page=1#623962022. Maybe this is related, I do not know. But your problem is different, you succeed in launching the background request but then the URLSessionDownloadDelegate's urlSession is not called. So my comments do not help solving your issue. I'll try out something else. Thanks for your suggestions though! Common default 13:22:43.829113+0300 com.apple.FrontBoard dasd [FBSSystemService][0x8a65] Sending request to open "com.mydomain.myapp.watchkitapp" Common default 13:22:43.830375+0300 com.apple.FrontBoard Carousel [FBSystemService][0x8a65] Received request to open "com.mydomain.myapp.watchkitapp" from dasd:91. workspace tiedot 13:22:43.830965+0300 com.apple.Carousel Carousel handleOpenApplicationRequest for com.mydomain.myapp.watchkitapp from dasd workspace default 13:22:43.831234+0300 com.apple.Carousel Carousel com.mydomain.myapp.watchkitapp: Duet activation requested by &lt;FBProcess: 0x1617b3f0; daemon<com.apple.dasd&gt;:91(v17E)> for reasons: ( &#9;&#9;CSLSDuetActivationReasonComplication ) workspace default 13:22:43.831532+0300 com.apple.Carousel Carousel com.mydomain.myapp.watchkitapp: Duet initiated launch allowed to proceed unixio debug 13:22:43.835551+0300 com.apple.securityd Carousel open(/private/var/containers/Bundle/Application/C84E1395-6686-46DA-AD72-10C8FDEF7AAE/My WatchKit App.app/My WatchKit App,0x0,0x1b6) = 36 unixio debug 13:22:43.835742+0300 com.apple.securityd Carousel open(/private/var/containers/Bundle/Application/C84E1395-6686-46DA-AD72-10C8FDEF7AAE/My WatchKit App.app/My WatchKit App,0x0,0x1b6) = 37 machorep debug 13:22:43.836451+0300 com.apple.securityd Carousel 6676 signing bytes in 5 blob(s) from /private/var/containers/Bundle/Application/C84E1395-6686-46DA-AD72-10C8FDEF7AAE/My WatchKit App.app/My WatchKit App(arm64_32) unixio debug 13:22:43.841957+0300 com.apple.securityd Carousel open(/private/var/containers/Bundle/Application/C84E1395-6686-46DA-AD72-10C8FDEF7AAE/My WatchKit App.app/Info.plist,0x0,0x1b6) = 36 workspace error 13:22:43.844990+0300 com.apple.Carousel Carousel com.mydomain.myapp.watchkitapp: app does not support BAR, not creating action for reason CSLSDuetActivationReasonComplication -- openApplicationOptions: { &#9;&#9;CSLSDuetActivationServiceReasons =&#9;&#9; ( &#9;&#9;&#9;&#9;CSLSDuetActivationReasonComplication &#9;&#9;); &#9;&#9;"__ActivateSuspended" = 1; &#9;&#9;"__PayloadOptions" =&#9;&#9; { &#9;&#9;&#9;&#9;budgetdictionary = "/watch/budget/launches"; &#9;&#9;&#9;&#9;kCSLBackgroundActivityUUID = "A3368012-79B9-4170-9008-EA7D0A23651F"; &#9;&#9;&#9;&#9;kCSLBackgroundActivityUserString = "F4FE89A5-28A9-4F2D-A78E-B8F8B0263D1F"; &#9;&#9;}; }
Jul ’20
Reply to Unkown WKExtension Error
I have the same problem. Initiating the scheduled background update in similar manner. See my other post here - https://developer.apple.com/forums/thread/654464?login=true&amp;page=1#623865022. I do get calls to handle() but only to handle snapshots, not background tasks. If you look at the logs in my other post, I get workspace error 13:22:43.844990+0300 com.apple.Carousel Carousel com.mydomain.myapp.watchkitapp: app does not support BAR, not creating action for reason CSLSDuetActivationReasonComplication -- openApplicationOptions: { CSLSDuetActivationServiceReasons = ( CSLSDuetActivationReasonComplication ); "ActivateSuspended" = 1; "PayloadOptions" = { budgetdictionary = "/watch/budget/launches"; kCSLBackgroundActivityUUID = "A3368012-79B9-4170-9008-EA7D0A23651F"; kCSLBackgroundActivityUserString = "F4FE89A5-28A9-4F2D-A78E-B8F8B0263D1F"; };} I tried adding background capability to the app but that didn't help.
Jul ’20
Reply to WatchOS: background refresh file is downloaded but didFinishDownloadingTo: never called...
Finally got this working. What I needed to do: Not use the new SwiftUI app architecture, but implement a class HostingController: WKHostingController&lt;AppMainView&gt; Include a Interface.storyboard in your watch app (not extension) which refers to the HostingController as the main scene.         &lt;!--Hosting Controller--&gt;         &lt;scene sceneID="Kua-8L-UD8"&gt;             &lt;objects&gt;                 &lt;hostingController id="E91-za-DJq" customClass="HostingController" customModule="YourApp_WatchKit_Extension"/&gt;             &lt;/objects&gt;             &lt;point key="canvasLocation" x="-35" y="125"/&gt;         &lt;/scene&gt; Then, in your Extension, initiate the background request e.g. when the app is put to background, using WKExtension.scheduleBackgroundRefresh(). When handling the background task request in Extension, first repeat the request (if you need periodical updates), and initiate your URLSession background request as usual:          case let backgroundTask as WKApplicationRefreshBackgroundTask:             scheduleBAR(false)             YourAppDataProvider.shared.fetch(false) // initiates the URLSession background request here The YourAppDataProvider is a URLSessionDownloadDelegatehandling the downloading. Also make sure Extension gives the urlsession task to the provider to handle when it comes:          case let urlSessionTask as WKURLSessionRefreshBackgroundTask:             YourAppDataProvider.shared.handleDownload(urlSessionTask) And there, refresh the session in case the app/extension was closed while in background:    func handleDownload(_ bgTask: WKURLSessionRefreshBackgroundTask) {       let configuration = URLSessionConfiguration.background(withIdentifier: bgTask.sessionIdentifier)       backgroundSession = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)       pendingBackgroundTasks.append(bgTask)    } In addition to the usual urlSession(_ session: , downloadTask: , didFinishDownloadingTo location: ) and urlSession(_ session: , task: , didCompleteWithError error: )I also implemented this below, though I haven't yet tested if this is really needed (I can see from the logs that it is called):    func urlSession(_ session: URLSession, task: URLSessionTask, willBeginDelayedRequest request: URLRequest, completionHandler: @escaping (URLSession.DelayedRequestDisposition, URLRequest?) -> Void) {       completionHandler(URLSession.DelayedRequestDisposition.continueLoading, nil)    } Finally I mark the download done (the YourAppDataProvider has a var pendingBackgroundTasks = [WKURLSessionRefreshBackgroundTask]():    func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {       DispatchQueue.main.async {          self.pendingBackgroundTasks.forEach {             $0.setTaskCompletedWithSnapshot(true)          }          self.pendingBackgroundTasks.removeAll()       }    } Finally, make sure the backgroundSession var is not a lazy var, but initiated in the YourAppDataProvider.init. Now my new issue is that the complications do not update but show the complication templates...
Jul ’20
Reply to Unkown WKExtension Error
Got it working, see the other thread. Unfortunately background ops worked only when not using SwiftUI App architecture. Maybe someone finds a way to make it work or future updates to watchOS 7 make it work also with SwiftUI App architecture.
Jul ’20
Reply to WatchOS: background refresh file is downloaded but didFinishDownloadingTo: never called...
Yes, using an Interface.storyboard and a HostingController instead of SwiftUI and @main App got the background ops working. Perhaps the App architecture is so in beta that it yet doesn't work, or I am missing something in my code to make App architecture solution work. If I reboot the watch, and not launch my app, the background operation is executed after a while, looking at how the complication on the watch face changed. Then (without opening the app) I again changed the server JSON file and soon the complication was again updated. So no need to launch the app to get the background ops running. This was while the watch is on my wrist. I am requesting for the background task both in the Extension's applicationDidFinishLaunching() and applicationDidEnterBackground(). Reading your issues, I need to test more while watch is on the charger and/or locked. I am reading cached data from the watch using UserDefaults, so I have the previously fetched and stored data to show instead of "no data". And when the background fetch completes, then update the UserDefault storage and the complications. ComplicationController does not request any network ops. Only thing done there is that the ComplicationController uses the MyAppDataProvider.shared (potentially initialising it?) to get the cached data and in the init, the background session configuration object URLSessionConfiguration.background and the session backgroundSession = URLSession are created. No network ops are explicitly requested from the ComplicationController. Don't know if this has any impact on anything. This is my first watchOS app and I am still a bit unsure when and how the OS instants and executes which methods under which process. Anyways, this may influence something since the session object - when created with the same session id - somehow creates (?) a connection with the NSURLSession daemon (?).
Aug ’20
Reply to WatchOS: background refresh file is downloaded but didFinishDownloadingTo: never called...
OK so the use cases are so different that what I found out probably won't help you solve the issues your app has. Too bad. Hope you can solve the issue, if not by other means then by using push notifications. I'll continue to work on the "SwiftUI way" at some point, maybe after the next beta comes out. Currently busy with an other app. Thanks for your comments Sal!
Aug ’20