I have a Problem with my Sony SmartWatch App. I've developed a widget with control, but after the App is installed by users on the device the scheduled refresh task of the widget starts automatically. This means the refresh task is running all the time, even if the user did not turn on SmartWatch Display or start the widget. This drains the battery. If I go to the widget screen and then turn the display from off, the scheduled Task stops like expected. But if I don't do this the task is running and running and running....
How can I detect if the Display is on and the widget is running?
Thank you very much!
P.S.: It makes no difference if the "Activate Widget" preference is checked or not....
EDIT: I've found out that the widget sourcecode does not fire if I uncheck the "Display as Widget" Checkbox in preferences. This means if the refresh schedule is running and I uncheck this box, the onDestroy is never called and so the cancel schedule also not....
Thank you - I think you have uncovered a bad behavior by the SmartWatch host application, or in other terms, a bug.
When installed, the host application sends a START_REFRESH_IMAGE_REQUEST to be able to cache information about the widget. However, it does not call STOP_REFRESH_IMAGE_REQUEST, which it probably should. This needs be investigated.
While we are investigating this bad behavior, you should try to find a workaround to solve the problem. E.g. you could have a global static variable, or a SharedPreference, that is used to track when the first START_REFRESH-signal is sent, and thus be able to stop the refresh cycle.
Thanks again, and sorry.
I will post again in this thread when I know more about fixing the problem.
Related
First off, I'm on iOS 13.6.1
I'm downloading HLS videos to later play offline. It all works as expected when in foreground, all the logic does what it should and there doesn't seem to be any problem.
But when the app goes to background I stop getting updates for the AVAggregateAssetDownloadTask (I mean, I don't see the logs in the delegate callbacks printing in the Xcode console).
I followed the documentation:
NSURLSessionConfiguration sessionSendsLaunchEvents is set to true
The AppDelegate implements handleEventsForBackgroundURLSession
The Session delegate implements URLSessionDidFinishEventsForBackgroundURLSession
Also, I have background modes enabled for fetch.
The crazy thing is, if I hook up the instruments network monitor, I do get all the updates. And I see that the download keeps going in the background.
Even without the changes mentioned in the documentation indicated above, I still see that the download keeps going in the background with the monitor open.
But it seems that the network monitor keeps the app alive somehow, because if I don't open it, then I get zero updates.
To be clear, I'm not even thinking about downloads starting or finishing in the background, and waking the app or anything of that. I just want to start a download, go to the background and have the download keep downloading stuff and notifying me (which AFAIK is done in a separate process, and I can confirm from the network monitor it is).
An example:
open the app
start a download
go to background
no updates are shown
open the instruments network monitor and connect to the app running in the device
suddenly start getting updates
I'm running out of ideas. Nothing makes sense anymore, short of a bug in the framework.
Any sort of idea will be greatly appreciated, no matter how simple it may appear.
Thanks in advance!
PS: when going to settings>storage I sometimes see that the file size grows while in the background, which would mean that the download is continuing even if I don't see updates from the delegate callbacks. At some points I saw the file size unchanged over a period of background time, but that might have been an unrelated thing (I hope).
I have a group email app where customers create emails in a standard iOS compose window. If they write a long email, then switch apps to do a memory intensive task, iOS may close the compose window, losing the contents of their email.
Is there a way to prevent the window being closed? or a way to ensure iOS saves the email to drafts before closing it?
I am wondering if I am not retaining a link that I should be, perhaps?
Can anyone else confirm whether they see the same problem?
The best way to do this is to understand the App Life Cycle on iOS.
When the App is running in background, the method applicationWillTerminate will be called, this is one of your options to save the content of the email. But this method is not called every time, it is only called when your app isn't suspended or when the user reboots his device.
One solution is to save this data inside the method applicationDidEnterBackground, it is called as soon as your app starts to run in background. And reload the data inside application:didFinishLaunchingWithOptions, this allows you to perform any final initialization before your app is displayed to the user.
Is there a way to prevent the window being closed? or a way to ensure iOS saves the email to drafts before closing it?
There's nothing you can do to prevent the window from being closed, because iOS is killing the app. What you can do is to save the email at some point before that happens. Since the user obviously can't modify the email while the app is in the background, saving the message when the app goes into the background would be a good choice. That way, you'll have the data saved if iOS does end up killing the app, and you can check to see if there's a saved message that needs to be restored when the app launches.
If you take that approach, though, you'll also have to figure out a way to help the user get back to their saved message, which means that you also need to keep track of how they got there in the first place so you can recreate that state. If it's just a simple message, maybe all you need to do is to open a message editor view and set it up with the saved message. In general, though, this can be a thorny problem. Luckily, Apple has provided a nice solution...
The View Controller Programming Guide for iOS has a section called Preserving and Restoring State, which explains how you can set your app up to automatically save and restore its state. With a relatively small amount of work, you can set your app up so that the user will never even notice that the app has restarted -- if they launch it after iOS has killed it, the app will recreate the view controllers so that it looks like the app was running the whole time, even if the device was shut down in the interim.
I have an iOS Today Widget that makes an expensive API call (expensive as in the more it is called, the more I pay money). If I implement widgetPerformUpdateWithCompletionHandler in my widget, then the widget can be updated in the background several times a day without the user ever looking at their Notification Center.
In an app, there is a key-value-pair in the options dictionary of application:didFinishLaunchingWithOptions that tells you if the app is launching the background or not, but there isn't anything similar in a widget that I can find. There is also the call to get the applicationState in UIApplication, which also isn't available in a widget.
So, is there any reliable way in my widget to know that the system is updating my widget in the background and the user isn't looking at their Notification Center to save myself from unnecessary API calls? I'm fine with the content not being completely up to date when the user does look at the widget because I can update it pretty quickly after it loads.
I've been trying to find a hacky solution like something different with the view or window that is different when the widget is being updated in the background, but haven't found anything yet. I've noticed the occasionally when the widget is initialized in the background that the window frame has a height of zero, but that doesn't seem to always be the case.
I'm also aware that if I don't implement widgetPerformUpdateWithCompletionHandler, then my widget isn't updated in the background which is a possible solution, but I'm looking for a way that I can have my cake and eat it too.
If anyone has any other ideas, I'm all ears. Thanks.
If you just plan on debugging and understand how often it is being called, you could use some logging on the device (possibly even trigger some kind of analytics event informing every time widgetPerformUpdateWithCompletionHandler is called, in order to mediate whether that is happening too often).
An example of an active solution to decrease the number of requests is to timegate the requests where, if widgetPerformUpdateWithCompletionHandler runs more than once every x minutes/hours/etc you would not call the API but simply call the completionBlock with no new data.
A final example with even more rigorous limit on the API calls could be to avoid them at all on the Today's extension (just like you said). This means the API calls would only be done when the actual app is launched, and the response persisted (you can have a shared container between the app and the Today's extension - just a folder or even something more complex like a sqlite store for Core Data) and always retrieve the data from the shared container to update the Today's extension UI.
I filed an Apple Developer Technical Support ticket on this. They responded and told me that this was not possible that that I would need to file an enhancement request for this. I filed rdar://27434852.
widgetPerformUpdateWithCompletionHandler is actually pretty unreliable in iOS 9. If you just kick off your network call in the background from viewDidLoad, it will only be called when your today widget comes on screen.
I'm making a simple app with a Today Widget extension that logs events.
The user can tap a button in the app or the related Today Widget to log an event. These events are saved with Core Data any time the button is pressed either place.
Whenever a new event is logged in the app, I run a function called updateLocalNotificationsFromCoreData(). It handles the setup of UILocalNotifications based on the most recent event in Core Data after clearing the appropriate existing notifications.
However, when a new event is logged from the Today Widget, I can't use this function because I need to register the Local Notification with UIApplication.sharedApplication().scheduleLocalNotification(), and UIApplication is not available in the Today Widget extension.
I realize I'll probably need do something unconventional or hacky to get this working, so I'm trying to evaluate possible approaches and come up with a relatively robust solution.
Basically, I want to find a way I can call my
updateLocalNotificationsFromCoreData() function right away any time a new event is logged.
If I can't do it every time an event is logged, an alternative would be to trigger the updateLocalNotificationsFromCoreData() function periodically (somewhat frequently) another way. Here are some solutions I was thinking about using, but I don't like any of them:
Do it in AppDelegate when the app is launched (or another state change)
One approach I'm thinking about is running my updateLocalNotificationsFromCoreData()function in AppDelegate somewhere, like didFinishLaunchingWithOptions.
The downside is that it would require the user to open the app periodically. If the user didn't open it much the notification behavior would be inconsistent. I'd prefer a solution where a user could interact with only the Today Widget and reliably get Local Notifications without ever opening the app.
Sync the events to a server and use Push Notifications
I've thought about syncing the data in Core Data to a server, then setting up Push Notifications to the user's phone based on that.
I don't like this, because I want the user to still be able to get notifications without an Internet connection. It also introduces a lot of extra overhead of syncing the data with a server.
Ping a server, and send a content-available Push Notification
When someone logs an event with the widget, I could ping a server. That server could send back a silent content-available push notification to trigger the app to run updateLocalNotificationsFromCoreData() in the background.
I found a similar question (Scheduling local notification from within a Today extension) where one answer proposes a similar solution. Unlike the previous solution, an Internet connection is not needed to receive the notifications, but an Internet connection would be required to make sure the notifications are up to date when a new event is logged.
Background fetch
I thought about using Background Fetch to fetch something arbitrary from a server, then run the updateLocalNotificationsFromCoreData(). This would be a way to trigger the update in the background, although it seems silly to fetch data if that data isn't being used, and seems like something for which an app could be rejected. There also seems to be a risk of the system not calling the background update regularly if the user doesn't open the app much and mostly uses the Today Widget.
Use background location updates
This seems like the dumbest approach, but I thought I would mention it anyway since I thought about it. I could use one of the low accuracy background location update modes to trigger updateLocalNotificationsFromCoreData().
It would require the user to allow location in the background, which would be hard to explain. And, it would require the user to at least move around a few blocks to trigger the function, which could provide an inconsistent user experience. Also, it would increase power consumption of the app for a silly reason.
I'd really appreciate fresh ideas about how I might be able to reliably schedule local notifications when Core Data changes on a device that doesn't have an Internet connection!
Or, if that doesn't seem possible, I'd appreciated feedback on which approach seems to make the most sense.
EDIT: I came up with a new solution. It's not ideal, but I think it's better than these other approaches I was considering. When someone taps the button to log the event, I launch the full app. It's annoying because I have all the data I need at that point to give the user feedback and log the event within the Today Widget without launching the app, but by launching the app I have the opportunity to check and schedule local notifications.
Also, in iOS 9 the annoyance on the user is slightly minimized because the system-wide "back" button will appear and let the user go back to the previous app easily once my app has launched from the Today Widget.
In the future I may try a solution where one of the server-based approaches above is used when an Internet connection is available, and I would then fall back to this system of opening the app only when the network connection is not available and I need to schedule the local notifications within the app.
i have database in my app and i want to delete all information from database when user force quit from app. I looked this question Which Event When i close app in iOS? , but when the user click home button, app has force quit in applicationWillTerminate.I don't want to close my app. I just want to catch close event in my app.
Sorry for my bad english.
Thanks for advice and interest.
the OBJC runtime will shut down without any final notification
BUT
you can write a posix signal handler to get the signal. but note that since the runtime is already shutting down it is unsafe to do much work here.
see e.g.:
http://chaosinmotion.com/blog/?p=423
You can't. The last notification you get that you can be sure of is a didEnterBackground when you get switched to the background. After that, you will likely be killed silently, either from memory pressure or from the user force-quitting you.