In ios, if I authorize or reject Location Services when prompted, there is a delegate method that gets called immediately:
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status;
I'm wondering if a similar method exists for accepting or rejecting Push Notifications. I'm aware of how to prompt, as well as how to test for status, but not how to do something immediately after a user accepts or rejects the notification.
I would like to prompt the user for Push Notification, and based on their response do a certain action, such as redirect the ViewController one way or another.
I've done a great deal of research on this and - unfortunately - the status of that accept/decline option appears to be entirely opaque.
You can determine that the user doesn't have push notifications enabled (using UIApplication's isRegisteredForRemoteNotifications), but not why it isn't enabled (ie. determine whether it's a "never prompted" or "prompted and then declined or later disabled" state).
I strongly suspect that this was a conscious design decision by Apple to make it more difficult for developers to hound users who've opted out. There are legitimate reasons to have this information, though, so I hope in the future they reconsider.
I hope this helps.
You can not do that but you can check that every time the app gets into foreground. This would solve your case when you can take action at the moment the user opens the app.
If you want to do that on background (in case you want to report your server that user has been disabled notification for example) you can always run some background task (like "Background fetch") to check the status.
Related
Is it possible to check permission status while app is closed on iOS? My use case is I want to send out a notification at periodic intervals if the app does not have the “Always” location turned on.
Follow this Using Background Tasks to Update Your App.
You can do something when app is wakened by system to run in the background.
But if the user explicitly denies the AlwaysAuthorization permission, you should not ask the user periodically. It is very bad UX.
AppleStore reviewers may reject your app also.
I think you should find a suitable way to ask the user or only show a warning popup when the user opens app and use the function that requires AlwaysAuthorization. Or ask the user to grant this permission on the first app runs.
Changes in authorization state are typically detected using the locationManagerDidChangeAuthorization event in CLLocationManagerDelegate. However, when the app is closed, the user's status cannot be detected. You can use this method to detect the change of authorization status when the user is using the app.
For more details, you can refer to the following docs:
locationManagerDidChangeAuthorization
I need to notify user when a certain condition is met but that condition might or might not meet in months. I need to run condition check in background (even when app terminates) so that I could detect condition is met (even if it happens after 3 months). If condition is met then I need to send notification only to a single user (not all users).
I am not sure what is the best way of doing it. Local Notification or Push Notification? I can not schedule a local notification in advance because I don’t know when it will meet the condition. I think Push notification is not needed because I am sending only one notification to only one user in several days/months.
I also need to constantly run this check in background. I know it can be run infinitely in background by using location update (significant monitoring or background navigation). But my condition checking code doesn’t actually require location updates. As far as I understand, Apple allows only location update or network related task in background (for few minutes). That's why I am thinking of putting my code in background location update code.
In my opinion , I should use local notification and put my code in background location update code so that I could check constantly if certain condition is met. This background check will schedule local notification and show it to the user who is using that device. I don’t think it is possible to schedule a push notification by code running in background.
In summary, I have following 3 questions
Should I put my code in background location update? If not, what is the right approach of running my code infinitely in background without location update?
Will Apple reject application if I put my code in background location update while location update code doesn’t actually send/receive current location?
What kind of notification should I use in this kind of situation where I send notification to a single user after months? Would you use Local Notification? or Push Notification.
Please reply. Any help is truly appreciated.
Thanks in advance.
This is a bit of a tricky problem unfortunately.
Apple won't allow you to create long-running operations in the background. As you mentioned, you can add code in the background with location updates or audio, but neither of those are very good solutions since (1) Apple will likely reject you from the app store and (2) the user will probably close the app if they notice a big locations banner at the top of their phone (or a weird background audio signal), and closing the app will kill your operation. For any truly long-running tasks it's probably best to set up a server and run a cron job or equivalent long-running operation. It's the only way you can know that the task will continue running.
Sorry, I was just answering one at a time, but as I mentioned above, yes, they'll probably reject your code for that. As a rule of thumb: if you think the Apple-created code you're using wasn't meant for what you're using it for, Apple will probably reject your app.
It sounds like you should use a remote notification. If you do use a remote notification, you'll probably want some sort of backend anyway. You could use a local notification to notify a user after a few months, but you would need to know the exact time to send it up front, which it doesn't sound like you would.
In summary: Try to build a simple BE. Maybe use Firebase Functions or something, and also build an APNS system to send pushes. In the app, tell the server to start processing the information and send the push back when it's done. The situation sounds like a perfect use case for server-side logic.
Hope that helps!
Requirement - I am building a hyperlocal app which will provide offers to user based on his location. When in app I can get his current location and show offers accordingly but what I need now is to send push notification to user based on his location. So I want to find out user's location and send offers based on his location.
I have read Apple doc for Significant-Change Location Service but then this answer is saying that it won't work once app is killed.
I have also read about Tracking the User’s Location but that didn't work for me properly. I was not getting more than 5 updates in background.
My current code in viewDidLoad -
if (self.locationManager == nil)
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.delegate = self;
self.locationManager.allowsBackgroundLocationUpdates = true;
self.locationManager.pausesLocationUpdatesAutomatically = false;
if ([CLLocationManager authorizationStatus] != AVAuthorizationStatusAuthorized) {
[self.locationManager requestAlwaysAuthorization];
}
}
[self.locationManager startUpdatingLocation];
And my delegate method looks like this -
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
if (UIApplication.sharedApplication.applicationState == UIApplicationStateActive) {
// Get updated data according to location
} else {
// Send location to server
}
}
My apps capabilities And my plist -
Please suggest some appropriate way, I can live with accuracy of around 1km.
Another approaches -
Can I get user's location in "Background Mode- Background Fetch"'s fetchNewDataWithCompletionHandler: ?
Can I get user's location using Silent Push notification's application:didReceiveRemoteNotification:fetchCompletionHandler:? ): Not possible according to this answer
So, your question is basically "How can I get around Apple's specifically designed user interaction for people wanting to make my app shut up?"
The answer to that is "Not if you want to stay within the rules for the AppStore".
Listen, if the user decides to terminate your app (i.e. they swipe it up and out of the task manager), the entire point of this design is for your app to stop do anything. Apple designed this so that people can quickly turn off exactly the kind of behavior you seem to want to implement. I don't quite get why you would want to circumvent that. I agree that this interaction is a bit obscure perhaps (after all, users can also allow/disallow an app's right to receive location updates in the background in the Settings app as well), but that's the interaction iOS defines.
If I understand you correctly, you succeeded in properly setting up the background location modes, so your app can receive the location updates even if it is not in the foreground (i.e. in background or suspended, in the latter situation iOS wakes it up briefly so you can process location updates and e.g. send a local notification to inform the user). That's as good as it gets.
Oh, and don't fear a device reboot. Yes, after the reboot your app is technically not running, but since the user didn't explicitly kill it the last time, iOS treats it like it was in suspended mode, IIRC, so you will still get significant location updates and can react properly.
(In a more general way: people often seem to think the actual app process state reflects the app state as it is defined in the documentation and/or that whether the app is shown in the task manager is linked to that. Both isn't entirely true.)
Edit after your comment asking me specifically about background fetch:
Sorry, that was perhaps not entirely clear. I didn't answer on this sub-question specifically, because after the user quits your app intentionally, you should not, as explained, "cheat" on their intention. Silent push notifications won't work because of this, yes.
I don't know whether the background fetch will be suppressed in a similar way (could be, but I haven't tried it), but I think that won't help you either, even if it were still working (which I doubt, Apple's probably going to be hard on this). I have also never tried to (re)start location updates in this method, so I can't say whether that even works (once the completion handler is called the system will likely suspend your app again at least, and I am not sure that this "resets" the "user killed the app flag" that the system seems to use for deciding which app to wake up and deliver location updates to).
application:performFetchWithCompletionHandler: (as it is fully called) will be called by the OS based on heuristics, it tries to be "clever" on this. Since the method is meant to fetch some data from a backend that doesn't provide push notifications, the times it is called at all can be severely limited, as is explained in the documentation. The actual mechanism that decides when the OS calls is a black box and it is a gamble to try to trick it into getting called when you need it. Could be very likely that this happens hours later. Think of the following scenario:
Your app runs fine in the background location modes (I understood you correctly in that you successfully set that up? see here and here)
The user manually kills your app. For the sake of this argument let's assume that doesn't keep the system from later restarting it to give it a background fetch opportunity
Since other apps are running on the system and the user only has an edge connection at the moment, the OS decides it is a bad time to initiate a background fetch (I just assume here that those factors play a role, as said it's a blackbox, but those appear reasonable to me). Your user walks around some more, bypassing several locations you would be interested in.
Two hours later, the user is by now in a completely different area, your app is started again by the OS and gets a application:performFetchWithCompletionHandler: call. You start location updates again (lets assume that even works and the system doesn't immediately terminate the app again, i.e. even after the fake background fetch it delivers location updates in background). You missed several locations, but nevertheless the app now handles new ones. All your logic is basically messed up, because you didn't plan for so many location updates being missing...
(Optional: After a while your user realizes that your app apparently does something, even although they terminated it (for example they notice battery drain). They will delete your app and leave a one-start review...)
(Optional 2, worst-case: Once apple realizes it is possible to re-init background location updates after a user killed an app this way, they simply close the loop-hole in an iOS update and your app is back where we started...)
For the record: I am not defending any design decisions made by apple, heck I know this is confusing to wrap your head around and just as one can make a stand for "preserve battery and user intent under all circumstances" one can make one for better background tracking. I am merely pointing out that they're in control here and trying to weasel around any specific interaction paradigms they set on the platform is likely not a good idea.
That all being said, I am afraid the "user terminated the app, now I won't get any location updates" is simply something you have to live with. Why would that even be a problem for you, considering you didn't say anything about background location modes not being enough for you? The only (questionable) scenario I could imagine is a kind of tracker application, maybe given on devices handed out to employees of a delivery service or something. If that is it (and putting aside the ethics behind such stuff, in some countries that is even illegal to do, mind you...), I have to say that iOS is simply not the correct platform for this.
Hi just create a UILocalNotification set it with your details and most important for notification to be triggered when you enter a Region add the region property see docs
Hope it helps
I'm using Plot Projects service to send geofencing notifications to users of iOS and Android application.
I want to use "dwelling" event to trigger specific notifications when user remains at one specific geofence for some extended time. The documentation states that dwelling event can be used on iOS, but has certain specifics:
Please note that due to restrictions in iOS the notification filter for dwelling notifications is called when the user enters the geofence or beacon region and that the returned notifications are only shown when the user remains in the region for the specified amount of time.
By my understanding, this would mean that the Notification filter gets triggered as soon as user enters the geofence, but the notification, if properly filtered, will be displayed after user dwells there. Filtering logic in my case is done on server-side - iOS app sends notification info to server, and then appropriate logic is applied to decide whether to show notification or not.
So, server-side logic for checking whether to show notification or not would be triggered at the time user trips geofence, but the notification would be shown to the user once he dwells there for some time. In my specific case, in order to properly decide whether to show the notification or not, I'd need the check to be done at the time the user really dwells, and not on entering. My understanding is that this cannot be done on iOS (unlike Android).
Am I right to assume this? If not, what would be the way to achieve a dwell-time filtering check, as opposed to enter-time filtering check?
You're correct about the moment when the Notification Filter will trigger on iOS. This is done because of platform limitations. The filter will be called directly when you enter the geofence. When you want filter out messages, that is indeed the time to do so. There is no way to filter at the time of the end of the dwelling period.
This, as mentioned, differs from the behaviour on Android. There it will be called at the end of the dwelling period.
This may be contrary to HIG...it is not standard..but it occurred to me that after a user sends feedback from withinmy app, it might be nice to flash a quick unobtrusive message "Thank you for your feedback" or something. I don't want to hit the user with a full blown alert. But a discreet notification banner along the top might be nice.
Is it possible to do this or is it disallowed?
Thanks for any suggestions.
If this notification is initiated from an action from within your app, an Apple notification may not be necessary. You want to simply show a thank you message, so it doesn't even have to wait for a response from a server, but you may want to check if you have Internet connectivity, just to be able to say that the message couldn't be sent, and offer the option to retry.
These are good options for a Toast-style alert that Android uses and is unobtrusive:
https://www.cocoacontrols.com/controls/toast
https://github.com/scalessec/Toast
You can configure it to slide in from the top or bottom. And, it slides away without user interaction.
Local notification will be received in this case but will not be displayed as you want it. However you can make a custom view similar to iOS view. Also please check https://github.com/OpenFibers/OTNotification
Unless the notification is from other application in background,
your currently active app has every right and responsibility in interacting with user with any types of visuals.
There are no class from iOS SDK to allow you to use the same notification banner used for Push Notification. To achieve the same result while your app is active, you may need to adopt your own solution or a module.