KBB KBB - 4 months ago 40
iOS Question

Troubleshooting Azure App Service Push Notfication registration with tags in iOS

I started to use Azure App Service this month, before App Service I was using Azure Mobile Services and the registration device token with tags are pretty simple but in app service I realized that its removed due to security issues so i have to do that with custom API.

I am using custom authentication(not azure authentication service (due to my client doesn't want it)) with my database so that i need to set user id as a tag to send notification to specific user.However i am facing problem that even if the device token registration is OK (i can send push to everyone without tags) the tags are not working, i was following these blog posts

https://blogs.msdn.microsoft.com/writingdata_services/2016/04/14/adding-push-notification-tags-from-a-node-js-backend/

https://blogs.msdn.microsoft.com/writingdata_services/2016/01/22/adding-push-notification-tags-from-an-azure-mobile-apps-client/

My Custom API (updateNotification.js)

var api = {

get: (request,response,next) => {
var push = request.azureMobile.push;
var installationId = request.query.id;

push.getInstallation(installationId, function(error, installation, res){
if (error){
console.log('An error occurred when retrieving installation : ' + error);
response.status(error.statusCode).send(error.detail);
}
else{
// Return an array of current tags.
response.json(installation.tags);
}
});
},

post: (request, response, next) => {
var push = request.azureMobile.push;
var installationId = request.query.id;
var tags = request.query.userID;

var updateOperation = [{
"op": "add",
"path": "/tags",
"value": tags.toString()
}];

push.patchInstallation(installationId, updateOperation, function(error, res){
if(error){
console.log(error)
response.status(error.statusCode).send(error.detail);
}
else{
console.log("Success");
console.log("Tags : " + tags);
response.status(200).send(tags);
}
});
}
};

module.exports = api;


In my AppDelegate.swift class i was doing this

func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let keychain = KeychainSwift()
let id : NSString = keychain.get("userID")! as String
let client = MSClient(applicationURLString: "https://XXXX.XXXX.XXX")
var deviceTokenString = "\(deviceToken)"
deviceTokenString = deviceTokenString.stringByReplacingOccurrencesOfString("<", withString: "")
deviceTokenString = deviceTokenString.stringByReplacingOccurrencesOfString(">", withString: "")
deviceTokenString = deviceTokenString.stringByReplacingOccurrencesOfString(" ", withString: "-")

client.push?.registerDeviceToken(deviceToken, completion: { (error) in
if let err = error {
print("ERROR ", err)
}else{
client.invokeAPI("updateNotification", body: nil, HTTPMethod: "Post", parameters: ["id" : deviceTokenString , "userID" : id], headers: nil) { (result, response, error) in
if response?.statusCode != 200 {
NSLog("ERROR %@", error!)
} else {
print("Tags Successfully Implemented")
}
}
}
})

}


Everything seems fine right now , in my console i can see my userid , my device token and userID is here like this (i am puttin X in the middle of it :D sorry for that)

deviceToken = 22afedf6-a08f1ce9-XXXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXX-db431577-2dfbbee1
user ID = 88d06c97-XXXX-XXXX-XXXX-042215c46575

However when i tried this GET method to see tags of device id,

client.invokeAPI("updateNotification", body: nil, HTTPMethod: "GET", parameters: ["id" : deviceTokenString], headers: nil) { (result, response, error) in
if response?.statusCode != 200 {
NSLog("ERROR %@", error!)
} else {
print(result)
}
}


I am getting this error :


Error Domain=com.Microsoft.MicrosoftAzureMobile.ErrorDomain Code=-1302
"Installation not
found.TrackingId:57239dd3-XXXX-XXXX-XXXX-0bd9579c660e_G1,TimeStamp:7/18/2016
8:22:05 PM"


How do I troubleshoot this error message?

KBB KBB
Answer

OK , after long working hours here is the solution

1.Step

enter image description here

If you can debug the Notification Hub (I am suggesting debug from Visual studio 2015 Express etc.. ), you can see that PNS Identifier(Which is our device token) is all capital with no dashes so that first we need to change the device token code that was in our AppDelegate.swift which is going to be like this

deviceTokenString = deviceTokenString.stringByReplacingOccurrencesOfString("<", withString: "")
deviceTokenString = deviceTokenString.stringByReplacingOccurrencesOfString(">", withString: "")       
deviceTokenString = deviceTokenString.stringByReplacingOccurrencesOfString(" ",withString: "-")
deviceTokenString = deviceTokenString.uppercaseString

//In case of any spaces just guarantee with trim
let trimmedDeviceToken = deviceTokenString.stringByTrimmingCharactersInSet(
    NSCharacterSet.whitespaceAndNewLineCharacterSet()
)

2.Step

InstallationId and Device tokens are totally different things .You are pushing tags to installationId not the device token so that you need to get installationId in your client code.

The problem is in Azure Mobile SDK for IOS you cannot call the installation id with client.installationId (At least i couldnt find the way of getting from MSClient Object)

What i do is , go into the framework and find MSClient.m .And i realize that the installation id is actually stored in NSUserDefaults with key "WindowsAzureMobileServicesInstallationId".So i can reach it from NSUser Defaults with this

let defaults = NSUserDefaults.standartUserDefaults()
let installationID = defaults.stringForKey("WindowsAzureMobileServicesInstallationId")

after these steps you can actually register tags to the installation ids. Here is the result and the full code of application didRegisterForRemoteNotificationsWithDeviceToken method

    func application(application: UIApplication,
                     didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
        let keychain = KeychainSwift()
        let id : NSString = keychain.get("userID")! as String
        let client = MSClient(applicationURLString: "https://XXXX.XXXX.XXX")
        var deviceTokenString = "\(deviceToken)"
        deviceTokenString = deviceTokenString.stringByReplacingOccurrencesOfString("<", withString: "")
        deviceTokenString = deviceTokenString.stringByReplacingOccurrencesOfString(">", withString: "")
        deviceTokenString = deviceTokenString.stringByReplacingOccurrencesOfString(" ", withString: "")
        deviceTokenString = deviceTokenString.uppercaseString

        //In case of any spaces just guarantee with trim
        let trimmedDeviceToken = deviceTokenString.stringByTrimmingCharactersInSet(
            NSCharacterSet.whitespaceAndNewLineCharacterSet()
        )

        let defaults = NSUserDefaults.standartUserDefaults()
        let installationID = defaults.stringForKey("WindowsAzureMobileServicesInstallationId")

        client.push?.registerDeviceToken(deviceToken, completion: { (error) in
            if let err = error {
                print("ERROR ", err)
            }else{
                client.invokeAPI("updateNotification", body: nil, HTTPMethod: "Post", parameters: ["id" : installationID! , "userID" : id], headers: nil) { (result, response, error) in
                    if response?.statusCode != 200 {
                        NSLog("ERROR %@", error!)
                    } else {
                        print("Tags Successfully Implemented")
                    }
                }
            }
        })

    }

enter image description here

After this you can also check the tags by calling GET method of updateNotification with sending installationId that we get from NSUserDefaults