I have found a great description of the process for refreshing both the watchapp UI and its complications here. That works for me, even though sometimes the UI is only updated when I actually bring the app to the foreground (but that's another issue).
what I have been doing so far is this:
1 - I schedule a background refresh;
2 - When the background refresh task is called, I schedule a background downloadTask;
3 - After completion, the downloadTask call its delegate method (didFinishDownloadingTo), where I call another method to update the UI, reload my complications with new data and to schedule a snapshot refresh and another background refresh.
This is almost working fine (with the ocasional problem I mentioned above). But I put my watch on flight mode sometimes. What happens here is that the error delegate method is called, and so I schedule another app refresh for about 1 hour. If still in flight mode, it will request another refresh in one hour, and so on.
The problem with this approach is that when I turn off the flight mode, the app takes a long time to update its UI, depending on when the next update is scheduled.
Can someone suggest a better approach to get new data as soon as one gets internet connectivity back?
At the moment (watchOS 3.2) there is no framework in watchOS that could tell you when the device connects to the internet. However, you could leverage the Reachability framework in your iOS app and use the WatchConnectivity framework to signal your Watch app when it can refresh its UI.
Related
(It looks like this issue has been encountered by others in previous weeks, but there haven't been any solutions that I've found.)
I'm trying to do a really basic thing: Get data from either my iOS app or my Watch app to my Complication Controller.
I am turning out to be way less capable of getting this done than I thought. watchOS 2 Transition Guide indicates that I should "[fetch] the needed data from the extension delegate" using the following code:
ExtensionDelegate* myDelegate = [[WKExtension sharedExtension] delegate];
NSDictionary* data = [myDelegate.myComplicationData objectForKey:ComplicationCurrentEntry];
Great. Except, I haven't been able to figure out how to get this to work on the extension side. Though even more importantly, I can't seem to even get the extension delegate code to run at all from a complication controller launch. When I run the complication, I get this message: "Extension received request to wake up for complication support." However, none of the code within any of the extension delegate's methods seems to run. I've also set breakpoints within every method and none of those breakpoints are hit.
It also looks like "transferCurrentComplicationUserInfo:" is also suggested to be used for complication updates, though it's unclear precisely how it's used. As much as I've gathered, it's used to wake up the watch extension so that ExtensionDelegate can store the new data for the next time the complication controller runs, but due to the previous issue I haven't been able to confirm.
I've got one maybe workaround (pinging the server from the complication controller and hoping that session variables persist so I can send relevant data), but there's every chance that if I can't get this worked out my complication work will be hosed. Any help here would be tremendous.
By the way, here's the code I have for "getCurrentTimelineEntryForComplication", if that's helpful at all.
- (void)getCurrentTimelineEntryForComplication:(CLKComplication *)complication withHandler:(void(^)(CLKComplicationTimelineEntry * __nullable))handler {
NSDate* entryDate = [NSDate date];
ExtensionDelegate* myDelegate = [[WKExtension sharedExtension] delegate];
NSString* data = [myDelegate.complicationData objectForKey:#"meow"];
NSLog(#"complication data: %#", data);
CLKComplicationTimelineEntry* entry = [self getTimelineEntry:#"2015-08-25 00:19:42" entryDate:entryDate complication:complication];
handler(entry);
}
I've been working with Complications in WatchOS2 since Xcode 7 Beta 4. I'm now on the latest, Xcode Beta 6. I've had a number of issues as in both Beta versions running on the Watch, running on the iPhone then installing to the Watch, and running on the simulator frequently give false negatives due to what appears to be buggy APIs and OS releases. I have been able to get data to show on complications in the following way.
Ensure that your primary Interface Controller implements the WCSessionDelegate protocol.
Implement both the didReceiveMessage and didReceiveApplicationContext methods in your Interface Controller.
In your iPhone app, attempt to send a message using the WCSession to the Watch.
If the message fails to send from the iPhone app, send the application context.
Back in the Interface Controller, when you receive a message -or- a context, update the values in your Extension Delegate.
Still in the Interface Controller and still after receiving a message -or- context, get a handle to the CLKComplicationServer and for each complication in activeComplications call reloadTimelineForComplication.
In your Complication Controller's getCurrentTimelineEntryForComplication grab the data you set in the Extension Delegate and set the values in your CLKComplicationTimelineEntry.
This will work usually when the App is already open on the Watch, the app is still resident in memory, but backgrounded on the Watch, or you start the app and their is context waiting which it consumes.
I have not been able to get the historical timeline entries to function (or the future ones). Nor, I have I been able to get the timeline to update independently of the Watch app.
If you are having trouble, here are some debugging things to try. As I stated above, the API and OS appears to be very buggy. The steps below do work (sometimes).
In the sim, use the Reset all Settings option on both the iPhone and Watch sim.
On the device, restart the Watch. If necessary, unpair and repair the Watch, although this takes a really long time to do.
On the iPhone, delete the app (which will also delete the Watch app if installed) and reinstall.
I hope that helps!
Justin
In order to make the ComplicationController respond to WCSession activity you must make the controller conform to WCSessionDelegate, then manage didReceiveUserInfo from within the ComplicationController. The ExtensionDelegate is not woken up for these updates when in the background. You can still update your delegate from the controller if necessary.
Also, as of right now, the simulator does not send transferCurrentComplicationUserInfo to the watch sim, you have to test on devices.
I'am developing an application that keep a WebService informed for device location each 5minute (for exemple) :
So when the application leave the foreground execution and enter background I have to lunch a timer who
1 - Update the device location
2 - Send the location to a web service
How can I perform this action ? Or do you know any code exemple that I can follow to achieve this design ?
Thank you for your help !
Doesn't look like anyone gave you a solid answer, so allow me.
There is no iOS approved way of running a 5 minute (or any minute) timer in the background (unless your app is VOIP or music). What you CAN do is register your app as requiring location services in the background (edit the info.plist and add a key Required Background Modes and then add a value App registers for location updates. What this means is your locationManager:didUpdateToLocation:fromLocation: method and corresponding region monitoring/SLC methods will fire on location change, but Timers will not work at all.
The reason why is that timers require a run loop (a thread executing code) to be running and must piggy-back on that thread, but when the app is in the background even when executing code from the LocationManager, the run loop that executes the code almost always finishes before your timer would go off.
Hope this helps!
you cannot do this (on iOS).
(unless your app requests permissions that are meant for Navigation apps)
Hello #Aladdin Gallas,
I have developed a simple application that supports background location updates for iOS and Android in Xamarin.
The app pushes a new location every 2 seconds (you can change it to 5 minutes if you want to).
There is a feature I haven't been able to add; it is to keep the service up when the user closes the app (for iPhone). Other than that, as long as the app is open, even if the phone is locked, the service keeps running.
You can take a look at the application as a reference if it helps.
GitHub Repo
I have an iPhone application like facebook for iPhone. My application must connect my server and read all message every two hours regularly. I have a thread to read all message but when the application is terminated the thread cannot work. Can the thread run undependently from main delegate or how can I find solution for this problem?
You cannot have your app do stuff in the background. There is an API to finish tasks like uploading a photo but even that will be killed after around 10 minutes.
But the Apple Push Notification Service seems like the most appropriate solution for your problem. Your server notifies the device that there is something new happening and you fetch the actual messages when the user opens the app.
edit: As of iOS 7 Apple implemented a feature where you can schedule running tasks to fetch data in the background. Those tasks are not guaranteed to run at any specific times. See the release notes for iOS 7 and the linked methods below:
Apps that regularly update their content by contacting a server can
register with the system and be launched periodically to retrieve that
content in the background. To register, include the UIBackgroundModes
key with the fetch value in your app’s Info.plist file. Then, when
your app is launched, call the setMinimumBackgroundFetchInterval:
method to determine how often it receives update messages. Finally,
you must also implement the
application:performFetchWithCompletionHandler: method in your app
delegate.
There is no solution.
Apple does not permit applications to run in the background unless they are of a specific type such as location or audio or voip or newstand (your app can continue to run for about 10 minutes after it was active if it uses shouldBeginBackgroundTaskWithExpirationHandler).
There is no workaround, many many other people have wondered how to do the same thing as yourself before, but there is no legitimate way. Your app cannot schedule any sort of periodic call home activity.
The only way your app can run once its gone into a suspended or terminated state is for the user to launch it, either explicitly or in reponse to a local notification or remote push notification.
A piece of code need to be executed even after the iPhone app sent to background.
Based on the values the UI need to get changed.
When I bring the App to foreground.It need to be updated with the changes made at the background time.
Eg.When I sent a GPS application to BackGround.It need to receive the positions accordingly and update the UI.
As far as i know, you may not update the UI while in background (As per memory guidelines, you should release any unused/cached portions of your interface). However, you can schedule your update to the moments after your app is reactivated.
I have an iphone app that has a 30second process that does some network IO. Basically, while the app is in the background, i want this process to run every hour (actually once a day, but if it fails i want it to re-run in an hours time).
With the background features of ios 4, is this possible? If so, how? What are the limitations that i'll come up against?
Thanks so much!
Take a look at Apple's documentation about running code in the background.
http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/BackgroundExecution/BackgroundExecution.html
There are few different ways of approaching backgrounded tasks. The only apps that can have fully backgrounded processes are "audio", "voip" and "location" apps, and this needs to be declared in the Info.plist.
If your app is not of this type, you'll probably find it difficult to do what you want easily. There are methods which allow you to keep your app alive in the background for a finite period of time (also at that link), but eventually your app will be shut down.
Local Notifications will only prompt the user to open the app - do you really want to have an alert pop-up on the phone every 30 seconds?
I was making some kind of similar research, have a look at this SO answer in case you didn't manage to find it before. Applications like DataMan or Data Usage must have some sort of periodic code execution in the background, so I'm not 100% convinced that what you're asking for is impossible..
I believe that Using Local notifications will help....
check following....
http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/IPhoneOSClientImp/IPhoneOSClientImp.html#//apple_ref/doc/uid/TP40008194-CH103-SW1
An application can create and schedule a local notification, and the operating system then delivers it at the schedule date and time. If it delivers it when the application is not active in the foreground, it displays an alert, badges the application icon, or plays a sound—whatever is specified in the UILocalNotification object. If the application is running in the foreground, there is no alert, badging, or sound; instead, the application:didReceiveLocalNotification: method is called if the delegate implements it.
The delegate can inspect the properties of the notification and, if the notification includes custom data in its userInfo dictionary, it can access that data and process it accordingly. On the other hand, if the local notification only badges the application icon, and the user in response launches the application, the application:didFinishLaunchingWithOptions: method is invoked, but no UILocalNotification object is included in the options dictionary.