Handling user notifications on iOS 10 - push-notification

I have troubles determining when the user taps on a user push notification on iOS 10.
So far, I have been using the -[UIApplicationDelegate application:didReceiveRemoteNotification:fetchCompletionHandler:] which is called when
Case 1: the application is active and the push is received
Case 2: when the user launched the app after taping a received notification
This method comments explicitly say
Note that this behavior is in contrast to application:didReceiveRemoteNotification:, which is not called in those cases, and which will not be invoked if this method is implemented.
All this work as expected.
Now iOS 10 deprecated this delegate method and introduced the UserNotification framework which I cannot use because I'm still targeting iOS 8 and 9.
When my app is running on iOS 10 and a push is received while the app is active (Case 1), the -[AppDelegate application:didReceiveRemoteNotification:fetchCompletionHandler:] is called correctly.
Again on iOS 10, when the user starts the app by tapping a notification (Case 2) this method is not called.
I realise that when I implement the older -[UIApplicationDelegate application:didReceiveRemoteNotification:] it is the one that gets called in the Case 2
On iOS 8 and 9, in the Case 2 it is the -[AppDelegate application:didReceiveRemoteNotification:fetchCompletionHandler:] method is called.
Does it mean that I have to update my application and implement the older delegate just for iOS 10?
So the question is, what is the proper implementation of handling the user interaction of a received push on iOS 10 without using the UserNotification framework.
cheers,
Jan

Swift code for iOS 10:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.currentNotificationCenter()
center.delegate = self
}
// ...
return true
}
#available(iOS 10.0, *)
func userNotificationCenter(center: UNUserNotificationCenter, didReceiveNotificationResponse response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void) {
print(response.notification.request.content.userInfo)
}
#available(iOS 10.0, *)
func userNotificationCenter(center: UNUserNotificationCenter, willPresentNotification notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) {
print(notification.request.content.userInfo)
}

We were facing the same problem here and we were only able to solve this problem on iOS 10 GM release by using the code on the answer given here: https://forums.developer.apple.com/thread/54332
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
if (version.majorVersion == 10 && version.minorVersion == 0) {
[self application: application
didReceiveRemoteNotification: userInfo
fetchCompletionHandler: ^(UIBackgroundFetchResult result) {
}];
}
With this fix our code started working again both on iOS 9 and 10.
We also had to change the way we handle application state behavior (UIApplicationStateActive, UIApplicationStateInactive and UIApplicationStateBackground) on push notifications, as it seems it also changed on iOS 10
EDIT:
It seems that application state behavior is back to normal on latest iOS 10 versions.

This has been fixed in iOS 10.1 Beta 1 !!
The -[UIApplicationDelegate application:didReceiveRemoteNotification:fetchCompletionHandler:] is correctly called when the user taps on a notification.

Related

How do I update Xcode codes I can use iOS 14 functions?

I was watching a tutorial on how to fetch user location in swift and I had a problem here:
class teste: CLLocationManager, CLLocationManagerDelegate{
#Published var lctionManager = CLLocationManager()
func locationManagerDidChangeAuthorization (_ manager: CLLocationManagerDelegate){
switch manager.authorizationStatus {
case .authorizedWhenInUse:
print("authorized")
case .denied:
print("denied")
default:
print("unkown")
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error){
print(error.localizedDescription)
}
}
The error was a in locationManagerDiChangeAuthorization (Instance method 'locationManagerDidChangeAuthorization' nearly matches optional requirement 'locationManagerDidChangeAuthorizantion' of protocol 'locationManagerDelegate') and in manager.authorizationStatus( Value of type 'CLLocationManagerDelegate' has no member 'authoizationStatus')
After some research, I found out that these are iOS 14 only, and my code may be written in iOS13 (actually, for some codes, I have to add #available(iOS 14.0, *) to make them work, but this time it didnt seem it work).
But, as a beginner, I don't know how to update my code (searched for some stuff but nothing caught my eyes). How do I update my code? Would it interfere in anything? Is it necessary or its better to write something to integrate both iOS 14 and 13?
Project -> Info -> iOS Deployment Target
here you can change deployment target to iOS 14.

UIImagePickerController memory leak issue

In my application, I am using UIImagePickerController to take the photos, videos, choosing images from gallery and saving them in application document directory. If we launch camera and take picture/videos, app starts terminating without any crash log. For every launch of camera in the application, the RAM consuption is increased and after some time app gets terminated saying "Application terminated due to memory issue". I have observed this memory leak in XCode(10.1) and Instrument tool.
func takePhoto() {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera) {
self.mediaType = .Photo
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerController.SourceType.camera
imagePicker.allowsEditing = false
imagePicker.hidesBarsOnTap = true
imagePicker.isNavigationBarHidden = true;
self.present(imagePicker, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
// Local variable inserted by Swift 4.2 migrator.
let info = convertFromUIImagePickerControllerInfoKeyDictionary(info)
if let image = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.originalImage)] {
//Writing the image to document directory
}
picker.dismiss(animated: true, completion: nil)
}
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertFromUIImagePickerControllerInfoKeyDictionary(_ input: [UIImagePickerController.InfoKey: Any]) -> [String: Any] {
return Dictionary(uniqueKeysWithValues: input.map {key, value in (key.rawValue, value)})
}
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertFromUIImagePickerControllerInfoKey(_ input: UIImagePickerController.InfoKey) -> String {
return input.rawValue
}
XCode 10.1
Swift 4.2
iOS version - 10.2.1
Devices RAM - 1GB/2GB
Devices - iPad Pro, iPad Mini
Memoy - 16GB, 64GB, 32GB
Could you please help on this and suggest a better solution
Thanks,
I am having the same issue and landed here. Did you solve the issue yet?
someone seems to have this long time ago. I tried and it seems to help:
App Terminated due to Memory Pressure when using camera in iOS 7

Bluemix push notification displayed in phone OS, when clicked, won't launch the app

I'm developing an App using Bluemix push notification. When the app is at foreground or background, didReceiveRemoteNotification() with completion handler is called and all is fine.
But when the app is not launched, and notification is sent by another device. the phone does display the push notification in the system notifications when you swipe down from the top, but clicking the notification won’t launch the app. It just dismisses the notification. This is the same for Android and IOS.
How can I launch the app by clicking the notification?
Thanks and Best Regards,
Jen
For iOS you need to make sure you are also registering the application to the APNs service successfully. Once this is completed you will be able to open the application by clicking on the push notification that is received.
Objective-c:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0){
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:categories]];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
else{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert)];
}
return YES;
}
Swift:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let notificationTypes: UIUserNotificationType = UIUserNotificationType.Badge | UIUserNotificationType.Alert | UIUserNotificationType.Sound
let notificationSettings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: categories)
application.registerUserNotificationSettings(notificationSettings)
application.registerForRemoteNotifications()
}
You can see more information regarding Push registration here:
Enabling iOS applications to receive push notifications
I would also recommend looking at our Bluemix Push Sample:
BMS iOS helloPush Sample
For Android you must ensure you have the following in your AndroidManifest.xml, within the desired Activity you'd like to start when your app launches after clicking the notification:
<!--Notification Intent -->
<intent-filter>
<action android:name="<Your_Android_Package_Name.IBMPushNotification"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
Don't forget to use your package name in place of Your_Android_Package_Name
See the helloPush example for more details.

ngCordova/Ionic Push Notifications when application is in the background

I'm currently building an android application using ionic/ngcordova. I'm at the point of implementing push notifications. I've implemented push notifications as a service which is injected at app.run(function(){..}) stage. The registration part works and I receive a callback containing the regid. Also, when the application is in the active state, the event is raised and the notification is received.
The problem I'm having is that when the application goes into the background, the notifications are not received at all. I would expect that a local notification would be raised when the app isn't running or something similar, but absolutely nothing happens, which is weird.
I've trawled the web for the last couple of days looking for a solution but I've been unable to find anything which kind of indicates to me that it should just work.
The following is my notificationService.js inside my app
app.factory('notificationService', ['$cordovaPush', function($cordovaPush){
var dataFactory = {};
//
// When the device is ready and this service has been plumbed in...
document.addEventListener("deviceready", function(){
console.log("initializing push notifications...");
_register();
}, false);
//
// Registers the device for push notifications...
var _register = function(){
var config = {};
if ( device.platform == 'android' || device.platform == 'Android' || device.platform == "amazon-fireos" ){
// TODO: centralise this value as it can change...
config = {
senderID: "448168747432",
ecb: "onNotificationGCM"
};
}else {
// iOS
config = {
"badge":"true",
"sound":"true",
"alert":"true"
};
// Can add the following property to the config object to raise a callback with the information if need be...
// "ecb": "onNotificationRegisterAPN"
}
$cordovaPush.register(config).then(function(result){
//
// Typically returns "ok" for android and devicetoken for iOS
console.log(result);
});
};
window.onNotificationGCM = function(result){
console.log(result);
/*
I get called when the app is in the foreground, but nothing happens when the app is in the background.
*/
};
dataFactory.register = _register;
return dataFactory;
}]);
If it helps, I'm using PushSharp via a .net application in order to deliver the notifications. Any help would be greatly appreciated.
UPDATE: I'm using the following frameworks/libs:
Ionic Framework 1.2.14-beta6
Cordova 4.2.0
PushPlugin
For anyone else who's been pulling their hair out for a couple of days like I have, the solution was really simple...I was missing two properties in my Pushsharp QueueNotification request. So using the example given on the PushSharp github repo here: https://github.com/Redth/PushSharp#sample-code
push.QueueNotification(new GcmNotification().ForDeviceRegistrationId("DEVICE-REGISTRATION-ID-HERE").WithJson("{\"alert\":\"Hello World!\",\"badge\":7,\"sound\":\"sound.caf\"}"));
Needs to be updated to add the missing properties:
push.QueueNotification(new GcmNotification().ForDeviceRegistrationId("DEVICE REGISTRATION ID HERE")
.WithJson(#"{""alert"":""This is the future"",""badge"":7,""sound"":""sound.caf"",""title"":""Status Bar title"",""message"":""Some text you want to display to the user""}"));
Otherwise if your app happens to be developed using Cordova and its not currently in the foreground, nothing, repeat nothing will happen.
Tip my hat to gdelavald with his comment on PushPlugin for pointing me in the right direction here:
https://github.com/phonegap-build/PushPlugin/issues/212

PushSharp notification error

I keep getting this error when using PushSharp:
Waiting for Queue to Finish...
Failure: Apple -> Exception of type 'PushSharp.Apple.NotificationFailureException' was thrown. -> {"aps":{"alert":"Alert Text From .NET!","badge":7,"sound":"default"}}
Queue Finished, press return to exit...
Any thoughts?
I use the DeviceToken as the long UID shown in iTunes when you pluging your phone. The certificate was exported (Sandbox) as per instruction on PushSharp Wiki.
What you are using is not the device token. The device token is 32 bytes (which can also be represented as a string of 64 HEX characters). Your iOS application gets it from Apple when it registers for push notifications.
- (void)applicationDidFinishLaunching:(UIApplication *)app {
// other setup tasks here....
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
}
// Delegation methods
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
const void *devTokenBytes = [devToken bytes];
self.registered = YES;
[self sendProviderDeviceToken:devTokenBytes]; // custom method
}

Resources