The app I worked on got an alert from apple wallet: "Some passes are receiving too many updates, which may affect battery life. Automatic updates for *** passes will be disabled. Choose RE-enable if you want automatic updates to continue." I only have 2 passes in the wallet from that app.
Does anyone know what's the reason trigger this alert? If we send 2 push notifications within 5 seconds, will that trigger this kind of alert?
It means pretty much what it says. Apple is respectful of user's battery life and data consumption and recognises that a pass update is a high energy activity that the user has little control over, and so if a pass issuer makes too many updates, then iOS takes action to alert the device owner so they can choose if they would like to continue to receive these updates (at the expense of reduced battery life).
Apple's previous policy was to silently throttle updates, but this led to problems, since users were unaware that they were being throttled and would wonder why their passes were not updating.
Apple recognises that developers may need to push content more frequently, which is why you can disable rate limiting on your device via the developer menu (that appears when you have your iPhone hooked up to Xcode).
Apple doesn't publish the criteria that it uses to throttle, and normally a quick burst of activity (E.g. a one-off burst of 2 or 3 messages in the space of a few minutes) would be tolerated. But if the issuer is sending dozens of messages every few minutes, then you can almost certainly expect they will see this message.
Related
App that I am working on is offering a VPN connection, that can run even when the app is not running at all. This service is paid, but also I would like to offer a free trial limited by session length and maximum data transfered.
The problem I've encoutered, is with monitoring the data trasnfered when the app is in background or not runing at all. So far the best solution I've came up with, would be to periodically run small task that checks if the user is still within the data limit and if not, the VPN will be disconnected and notification shown to the user.
Will silent notification get priority every time it will be required? According to this quote from developer.apple.com, they are low-priority which isn't what I need, but I was unable to find anything else.
Silent notifications are not meant as a way to keep your app awake in the background, nor are they meant for high priority updates. APNs treats silent notifications as low priority and may throttle their delivery altogether if the total number becomes excessive. The actual limits are dynamic and can change based on conditions, but try not to send more than a few notifications per hour.
How can this be done reliably? Is there any other way?
If this is a personal VPN connection (i.e. you're just providing a config to the standard system) and you're not in the flow, then this isn't possible. There is intentionally no "I want my program to run all the time" solution. Even if you come up with one, Apple will probably shut you down.
If you're writing an MDM/supervised VPN connection (i.e. you're providing a ...Flow object of your own), then you're already running all the time and you can just control it as you want. I'm assuming you have the former or you wouldn't be asking.
I believe you're doing this backwards. Monitor the session length on the server, and disconnect there. When you disconnect, send a push notification, which can display a message directly without having to open the app. That is both robust and the intended solution.
Periodically posting a silent notification to wake yourself up will definitely not work because Apple specifically does not want you to do that and they explicitly break it (as they note "silent notifications are not meant as a way to keep your app awake in the background"). It's bad for battery life. This is intended to be solved on your sever, on on the user's device.
I am using transferUserInfo to send stats data to the watch.
When the watch is asleep or idling (showing clock), and the phone app is running, there will be many infos being transferred (triggered by a repeating timer).
How many "userinfo" queues can the app send? Is there a limit?
There is only one queue (provided by the system).
I'm not aware of any limit to the number of transferUserInfo messages that you can add to the queue.
However, you should take two things into account:
While iOS will send messages and be able to drain its queue, those sent (yet unprocessed) messages will be held by watchOS until your app can receive them. At some point, the watch may not be able to hold any more messages for your app.
While I don't know exactly how Apple handles that condition, you should plan that transfers may fail, or worse, be discarded.
Do not design your app around trying to skirt the limits of a particular system, as it will be fragile and break, especially if you don't have a contingency for handling possible situations that may arise.
If you expect to constantly send (a high number of) messages over a (short) period of time, this will definitely not be efficient in terms of memory or energy use.
You should follow Apple's performance tips to create a positive user experience. If it turns out that your app is responsible for poor phone and/or watch battery life, users will stop using it.
Better approaches
Here are a few alternative approaches to avoid chatty communication between the phone and the watch:
Use a different method such as updateApplicationContext so the phone and watch would only have to deal with a single context, instead of a long queue of messages that would have to be individually processed.
Maintain the stats on your phone; avoid transferring the current stats until the watch requests/needs them. (This is an excellent approach for watchOS 3, since your app can be updated in the background, before the user launches it).
Batch your data to send fewer updates over time.
If you're not updating a complication, don't plan to update an inactive app more than once per hour.
If you're updating a complication, definitely don't plan to update more than 4 times per hour (but preferably no more than once per hour).
Again, don't aim for any particular number. The less often you can update, the better, in general.
Whichever methods you choose, make sure your app is robust, and can handle any type of failure, including up to being terminated by the system (such as for excessive memory use, or excessive background CPU use).
For more information
These two watchOS sessions specifically cover when, why, and how to update your watch, and mention scheduling updates around particular usage. E.g., don't update transit information throughout the night, if transit isn't running.
A good introduction explaining when and why to update your watch app is covered in Designing Great Apple Watch Experiences.
For specifics, the Keeping Your Watch App Up to Date session covers everything you need to know to keep your complication, app, and dock snapshot up to date.
Preamble
I wrote a mobile application which should show upcoming events. The app downloads it's data from server. Data is prepared in batches once every 24 hours and it's ready to be fetched after 4 am. This gives me a perfect opportunity to sync it overnight and to make new data immediately available when the user opens the app.
Background fetch
This was my first approach for syncing data with the server. It's advertised as very powerful feature, but using it alone (out of the test environment) is not enough:
There is no way to force background fetches to execute at exact intervals.
I thought that the frequency of background fetch operations could be configured
// Setup background fetch
let timeIntervalEveryHour: NSTimeInterval = 3600
let sharedApp = UIApplication.sharedApplication()
sharedApp.setMinimumBackgroundFetchInterval(timeIntervalEveryHour)
but it's still dynamic and I think it is never for users who did't use app very often.
If 'Background App Refresh' is disabled, which automatically happen if device is in 'Low power mode', background fetch won't be triggered.
Other problems like Data Protection when device is locked and 30 seconds window for completion of all tasks are considered.
Remote (silent) notifications
So I took the next step and configured the server to post silent notifications once the batch is ready just to found that this is also not enough:
If application is force killed by the user or device is rebooted, notification won't be handled.
Rate limits. Delivery will be delayed, this depends on a variety of factors that are not explicitly specified by Apple, but probably - battery life, whether phone is on cellular, etc.
Sometimes silent push notifications are dispatched when application starts, which could lead to race conditions with the check for manual synchronisation. So I'll try to force it by adding "alert" = ""; to payload. (As it is suggested here)
Silent Push notifications could be disabled by the user be setting off 'Background App Refresh' - source
Manual synchronisation
To be sure that data is always up to date, if it's not recently updated, when app comes to foreground user is presented with alert which asks for manual synchronisation. Also it could be started later from settings tab. Unfortunately, according to analytics, most of the fetch requests are made manually.
First run case is also handled.
Next steps
I'm considering using VOIP notification. They should wake the app even if it's force killed. However I'm concerned that that would cause app get rejected.
Questions
Is there something I'm missing? I know that background synchronisation depends on a variety of factors, there could be no internet connection and etc, but is there any way to make it more reliable?
I have to develop an app that has to have an undivided attention of the user. Following things should NOT happen while the user is using the app:
Incoming Phone Call
Device going to sleep
Battery draining
Push notes from other apps
Local Notifications for Calendar Events
Alarms/Reminders
I have to see if all of these are viable to achieve directly or indirectly. Here is my report for all
Incoming call
Can't
Cannot block phone to take calls.
Prevent user from seeing the incoming call screen
Can
Alert user before starting the operation that he should put his phone on Do Not Disturb mode.
Device going to sleep
[UIApplication sharedApplication].idleTimerDisabled = YES;
Battery Draining
Can
Checking the battery status and compare it to minimum required battery so that the operation performs.
If the enough battery is not left, alert the user that he should put the battery on charge.
Monitoring the battery and keeping a check until the operation is complete.
Push Notes from other apps
Can't
Cannot disable push notes form other apps form my app
Can
Can check the status of internet connectivity (wifi, GSM, etc)
Alert the user and tell him to disable all the internet connectivity options
These are my compromises in Can sections. Please help me find a way for 5, 6 points
Also, if you can suggest a better solution (approach) for 1,2,3,4.
Thank you
You are not going to be able to make an app that gets the undivided attention of the user. But, seeing your approach, you obviously know this.
I think your statements are mostly correct. However, there is probably little point in making users put their phone in Do Not Disturb mode, because I think that only has an effect while the device is locked (you can easily test this out). From http://support.apple.com/kb/HT5463:
With Do Not Disturb, you can silence calls, alerts, and notifications
that you get while your device is locked.
Points 5 and 6 are closely related to point 1: there is no stopping them.
I am able to get ram, hard disk and battery info and would like to inform users when free hdd, ram or battery is (let's say) less than 20% even if my app is not running.. Is it possible? Thanks..
No, you can't. You might be able to shoehorn in to the significant location change API, which provides notification when the device changes cell towers, but this will really only work if the user moves on a regular basis (and Apple may well reject your app because you're not actually interested in the user's location).
There may be apps that monitor a network account and send a push notification message when certain thresholds are met, but all the polling and logic for this will occur on a centralised server (e.g. at your ISP) and not on the device. Such app(s) may well provide additional info while they're running—it would be possible, I think, to do this in a manner that appears to the user as though the app is running in the background, when in fact it isn't.
(If you only want this for yourself—i.e. you're a developer running your own code on your own device, and don't need to comply with the App Store guidelines—then you may also be able to use the VoIP background task type. This will get you the heartbeat-style polling you're after, but you will not get in to the App Store using the VoIP background task type for non-VoIP things—just ask the people who made Sparrow.)