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.
Related
I'm trying to decide which way to implement a "quiet hours" feature in my app to allow users to specify times in which push notifications should be silent. I see two options:
1) Server-side. Their settings are sent to the server which sends notifications with different properties (or perhaps not at all) during quiet hours.
2) Client-side. The app receives all notifications via silent push, the app then processes each notification and only notifies the user as appropriate.
I see problems / limitations with each method.
For #1, the implementation becomes more complex (especially if I want to add additional notification filters based on alert type, etc), and the issue of which timezone the client is in would be very hard to resolve (especially as the client moves from one timezone to another). I certainly don't want to be tracking their position and updating their current timezone on the server.
For #2 I have read a number of comments in various places that the silent push that goes only to the app is not as reliable as normal push notifications that directly notify the user and are not processed through the app. I would prefer to implement quiet hours in this way, but I am very concerned about a reduction in the reliability of the notifications coming through. I have also read that the app will NOT be started in the background if the user has force-quit it. Is that still the case?
I have two questions. First, how have others handled this concept of quiet hours? Second, is the silent push as unreliable as I have heard in the real-world, or has this gotten better (or worse) with the latest versions of iOS? I know there are factors, such as how much power the app consumes while processing these notifications. On average my app would only receive a few silent notifications a day, and processing would be very fast.
Not sure this is really an answer, but too much for a comment!
Is your app likely to be used in different time zones?
Or are your users all based in one country?
This could mean handling client side is going to be a lot simpler.
Also remember that there is no guaranteed delivery time of a push, its normally pretty instant, but not always, so although you might of sent it with 5 minutes to spare before a quiet hour, it might arrive after the quiet hour has actually started.
I am not sure how to best implement keeping our server informed that our iPhone application is currently running (even when in the background). There are a few different options but there is some concern as to what is allowed by the Apple approval process as well as what is the most reliable. The application does have the ability to play music in the background, if that factors into what is approved by Apple.
The first option, is to continually send some sort of heartbeat to the server at a set interval through a simple GET/POST; however, the concern is whether or not this is allowed as a background task. In a very roundabout way it can be argued that it is necessary for the playback but I'm not so sure whether or not that is acceptable. If the server does not hear from them in a set amount of time it will assume the app is no longer running.
The second option involves using a presence channel socket connection and have the server just handle when users enter and leave that channel. With this option the main concern is how reliable is a socket connection like this while an app is in the background. Similarly, whether or not this is allowed by Apple. In this case when the app dies, connection closes and server knows app is not running.
Third option can be used in tandem with either of the other options but to use some sort of APNS push to query the phone as to whether or not it has died and have it respond with some data to let us know; however, this seems somewhat counterintuitive as the push itself wakes the app up.
Any other suggestions or input are also welcome.
Not sure if this should be a comment or answer, but let me put my 2 cents here.
Firstly, Can you please elaborate your needs further, because in case you are playing an Audio in background with AVPlayer/AVPlayerItem you would hand over your content URL to iOS and it will make the calls as and when necessary to keep the playback running, you dont need to know about apps' state.
Let me assume, for whatever reasons you want to achieve what the question asks:
There are 3 states your app can be in when it is "Not Running"
i. Suspended State: your app is not killed but its not receiving any CPU time to execute your code.
ii. Killed by OS: Your app can be terminated by iOS to free up the memory or any other resources.
iii. Force Killed by User: If user swipes up your app from app switcher it gets force killed.
Now when your app is Not Running, you CAN NOT query it, but you can move it to Running State. You can achieve this transition by using following methods (Not exhaustive list, but mentions common ways)
i. Background Fetch : You can configure your app to be invoked periodically, so that it can synchronise with the server and updates its state.
ii. Push Notifications (APNS) : You can ping the app from server so that iOS invokes it for some short period of time (few seconds) to update its state.
iii. VOIP Pushes: If your App is VOIP app you can use PushKit to send Silent Pushes which will launch even the Force-Killed Apps, the above two methods does not transition the app to Running state if it was force killed by user
The above point can be helpful in devising overall strategy but does not answer the question, "How to keep syncing the RUNNING state"
i. When your app is Running(Forground/Background), you can do almost anything that is publicly documented, you can keep calling a URL every minute or every 5 seconds, you need to worry about UX on the device rather than approval process, (People will delete app if they see your app in top battery drainers in the settings section)
ii. For making an HTTP call while your app is in background, you can look at Background URL Session, which off loads the HTTP calls to another process so that the call completes even if app gets killed.
iii. For the socket based approach please refer this technical note. The main issue is that you do not/can not know when your app moves from Running to Not Running State.
iv. As you mentioned that your app uses background audio, it will be always be in Running state if the user plays an audio and puts app in background, in such case you can use Periodic Observer to do some Heartbeat call periodically when the content is being played out.
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?
My iOS app (which targets iOS 8.1+) use location services to determine if a user has entered a particular region during an event. Ideally I would like to enable the geofencing a little before the event and turn it off a little after the event completes. The problem is there is no guarantee the app is running an hour before the event so I turn on geofencing at the point the user registers for the event. This is not the best approach as it means the geofencing is on for much longer than it needs to be.
As far as I can tell, there is no way to "wake up" the app in the background at a scheduled time in iOS. I could use the push notification meant for updating content, but It's not clear to me if Apple would reject such a misuse of that notification.
Any suggestions?
I've been looking into this myself.
If you can arrange a push notification from your backend ("Silent push notification", aka "content-available"), it seems to be a good option. In real-world situations, this seems to give you the best control over the timing. Unfortunately, it won't work if the person doesn't have connectivity. Also, unfortunately, you need a backend that can queue events at a time (not just in response to an input.) If you have such a backend already, and your app is only useful to the user when they have network coverage anyway, this is probably the best option. It seems this an appropriate use of the technology, so Apple should approve.
Another option I'm trying is to use background fetch. You specify a "minimum interval" to avoid too much fetching. Try 50% of the remaining time-to-event as a minimum. Every time the app wakes up (whether in the foreground because the user opened it, or in the background because background-fetch opens it) you can calculate the time-to-next-event, update the fetch interval, or start the region monitoring. You are supposed to use "background fetch" to fetch information from a server, but there doesn't seem to be any requirement to poll a server, you could poll your internal data instead. I haven't fully tested this yet but it seems promising.
You can use significant location change monitoring, which I've read will wake up your app briefly every 15 minutes or less, and you can use the time/location information to decide whether to turn on the geofence. I think this would work well in combination with the above "background fetch": Many hours or days before the event you rely on background fetch, which you then use to turn on significant location change monitoring a few hours before the event. (There's speculation that geofencing is actually more battery efficient than significant change monitoring, but you could choose to assume that other apps on the user's device will already by watching for significant changes, in which case the marginal cost of your app adding itself to the list should be minimal.)
Putting them all together, you could create a sequence of
background fetch -> significant location monitoring -> geofencing
as the time gets closer.
There is also the CLVisit monitoring functionality, it's not understood very well, but supposedly uses less power and is called less frequently than significant location change monitoring. If the background fetch or silent remote notifications aren't working to wake up your app, give this a try, and please report back!
You can't (yet) do a silent content-available local notification (AFAICT). However, perhaps you can schedule up a local notification "Your event starts tomorrow" or something that convinces the user to click the option that starts the geofence. Here's a tutorial on it http://www.appcoda.com/local-notifications-ios8/, the response of action can be UIUserNotificationActivationMode.Background so your geofence can come on (if the user responds to the notification) without bringing the app to the foreground.
It's been 5 to 6 weeks since you asked, do you have your own answer already? Please let me know.
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.)