Cannot send push notifications from AWS SNS to my iPad - ios

I'm struggle since 2 days to make push notifications from amazon sns to work on my ipad. After nights spending on google and youtube i'm desperated and the amazon documentation isn't really helpful.
What i already did until now :
I got the certificate from apple and successfully uploaded the .p12 file to SNS and created the application platform and set the endpoint.
I set my cognito credentials in the viewcontroller in xcode and add some notification listeners in the appdelegate.
So When i run the app on the iPad, this one successfully display the deviceToken in the xcode promp. So i can enter it in SNS console and configure it.
So i created all required stuffs (certificate, .p12, registering the devicetoken etc.)
Unfortunately, when i'm trying to publish to the endpoint (send a notification to my device), i never received any notifications. I don't really know what's going bad. Yet, when i'm trying to do the same by sending a push to an email, its works perfectly.
I watched tons of tutorial in youtube and followed several docs on the web but it seems to definitely not working.
In Xcode i didn't forget to enter the same bundle ID than in my apple developer account (com.XXX.XXX), so i think my app is well configured.
Amazon docs are not dev friendly, most tutorial on the web are outdated,
Is someone know the perfect procedure to send push notifications from Amazon SNS to an Ipad ?
Thank you.

Last night I have successfully integrated AWS SNS.
Yes, the document on AWS are not well documented.
To integrate SNS you need to configure APNS perfectly. I would like to suggest here to first configure all the necessary credentials to get a notification using APNS.
I am expecting here that the developer knows how to create App ID, .p12, .pem and provisioning profile for APNs. Once you successfully get the notification on your device using APNs then you are ready for SNS in quick time. To test the APNs notification you can use this server "www.pushtry.com".
Once everything is successfully done with APNS then jump into your AWS account >> navigate SNS dashboard >> Create platform application.
After hitting Create Application a form will open to mention your application data and some credential entry of certificate.
Please see the below image to follow the steps.
Password entry is optional as per your .p12 certificate.
On press "Load credential from file", Certificate and Private Key entry should fill automatically.
After hitting "Create Platform Application" navigate into application left pane to see the list of created application.
Now you need to create end point.
see the attached image.
Now fill the End point entry, follow the image below.
Now copy the Endpoint ARN to use into AWS console to push the message on your device. The Endpoint is actually an address of your device like token in APNS for AWS. Be sure you copied endpoint completely.
Now again jump into the "SNS Dashboard" to publish the message.
Now paste your copied "Endpoint ARN" and your text message in this form and hit "Publish Message" as per below image.
Here you are done check your device to get the notification.
=================================================================
Above I have explained to push the notification through AWS SNS console.
Now let me add here code to create Application and Endpoint ARN.
+ (void) initAWSObjectToAccessAccount
{
// Initialize the Amazon Cognito credentials provider.
AWSStaticCredentialsProvider* credentialsProvider = [AWSStaticCredentialsProvider
credentialsWithAccessKey:kAWSAccessKey
secretKey:kAWSSecretKey];
AWSServiceConfiguration* configuration = [AWSServiceConfiguration configurationWithRegion:AWSRegionUSWest2
credentialsProvider:credentialsProvider];
[AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
}
+ (void) createApplicationAndGetAppARN: (void (^) (BOOL isCreated, NSString* appARN))completion
{
[self initAWSObjectToAccessAccount];
NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init];
[myDictionary setObject:kCertificateSecretKey forKey:#"PlatformPrincipal"];
[myDictionary setObject:kCertificatePrivateKey forKey:#"PlatformCredential"];
/* End Amazon SNS Mobile Push self registration */
AWSSNSCreatePlatformApplicationInput* platFormAppInput = [AWSSNSCreatePlatformApplicationInput new];
platFormAppInput.name = #"nFormIOS";
platFormAppInput.platform = #"APNS"; // When Release
//platFormAppInput.platform = #"APNS_SANDBOX"; // When Development phase
platFormAppInput.attributes = myDictionary;
AWSSNS *snsManager = [AWSSNS defaultSNS];
[[[snsManager createPlatformApplication:platFormAppInput] continueWithBlock:^id(BFTask *task) {
if (task.error)
{
completion (NO, nil);
}
else
{
AWSSNSCreatePlatformApplicationResponse* appResponse = task.result;
NSString* applicationARN = appResponse.platformApplicationArn;
completion (YES, applicationARN);
}
return nil;
}] waitUntilFinished];
}
+ (void) createSNSEndPoint:(NSString*)applicationARN
completion:(void (^)(BOOL isSuccess, NSString* endpointARN))completion
{
/* This is the code to actually register the device with Amazon SNS Mobile Push based on the token received. */
AWSSNSCreatePlatformEndpointInput* platformEndpointRequest = [AWSSNSCreatePlatformEndpointInput new];
platformEndpointRequest.customUserData = kUniqueID; // It could be anything.
platformEndpointRequest.token = kDeviceTokenNo; // Device Token No for APNS
platformEndpointRequest.platformApplicationArn = applicationARN;
AWSSNS* snsManager = [AWSSNS defaultSNS];
[[[snsManager createPlatformEndpoint:platformEndpointRequest] continueWithBlock:^id(BFTask *task) {
if (task.error)
{
completion (NO, nil);
}
else
{
AWSSNSCreateEndpointResponse* endPointRes = task.result;
completion (YES, endPointRes.endpointArn);
}
return nil;
}] waitUntilFinished];
}
===========================
kAWSAccessKey
kAWSSecretKey
This you will get when you will create a credential in AWS account.
kCertificateSecretKey
kCertificatePrivateKey
To get these two follow the steps.
/* STEP 1: Retrieve the SSL certificate (.cer file)
STEP 2: use the following command to convert it into .pem
openssl x509 -in aps.cer -inform DER -out myapnsappcert.pem
STEP 3: Open the file in NotePad. Copy the portion bounded as follows:
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
STEP 4: Use it as NSString replacing the special characters (newlines) with escape sequences (\n). It would now resemble this:
-----BEGIN CERTIFICATE-----\nMIIGKTCCBRGgAwIBAgIILZH6mrSmUj8wDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV\n......\n----END CERTIFICATE-----
STEP 5: Save the .cer file as .p12
STEP 6: Use the following command to get the Private Key:
openssl pkcs12 -in CertificatesSNS.p12 -out myapnsappp
rivatekey.pem -nodes -clcerts
STEP 7: Open the file in NotePad. Copy the portion bounded as follows:
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
STEP 8: Repeat Step 4 for this too.
STEP 9: Use the Value retrieved in step4 as "PlatformPrincipal"
STEP 10: Use the Value retrieved in step5 as "PlatformCredential" */

Related

How to send push certificate to APNS while calling their APIs?

Have been stuck for sending push notification using apns push certificate from my server app (Spring Boot Application). Apple discussed here on an overview of how we can send push with certificate but there is no technical detail about TLS communication (specially, on how I can send my push certificate to APNS and proceed API calls).
Anyone have any reference or article?
Since you mentioned your working on a Spring Boot application I'm assuming you're using Java and Maven.
Our back ends are also written in Java and I recently updated our push notification code by implementing Pushy. It's much much easier to use a library that's battle tested and regularly updated than to write your own. I use pushy to send around 100k push notifications a day on a fairly weak server and have never had any issues with it.
It was fairly simple to implement. Their README is very useful but the summary is add pushy as a dependency in your pom.xml file:
<dependency>
<groupId>com.eatthepath</groupId>
<artifactId>pushy</artifactId>
<version>0.13.11</version>
</dependency>
Here's a simple example for your use-case using stolen code from the README, I did add the comment though:
// Add these lines as class properties
// This creates the object that handles the sending of the push notifications.
// Use ApnsClientBuilder.PRODUCTION_APNS_HOST to send pushes to App Store apps
final ApnsClient apnsClient = new ApnsClientBuilder()
.setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST)
.setClientCredentials(new File("/path/to/certificate.p12"), "p12-file-password")
.build();
// The push notification
final SimpleApnsPushNotification pushNotification;
// In some method:
// Creating the object that builds the APNs payload
final ApnsPayloadBuilder payloadBuilder = new ApnsPayloadBuilder();
// setting the text of the push
payloadBuilder.setAlertBody("Example!");
// Builds the anps payload for the push notification
final String payload = payloadBuilder.build();
// The push token of the device you're sending the push to
final String token = TokenUtil.sanitizeTokenString("<efc7492 bdbd8209>");
// Creating the push notification object using the push token, your app's bundle ID, and the APNs payload
pushNotification = new SimpleApnsPushNotification(token, "com.example.myApp", payload);
try {
// Asking the APNs client to send the notification
// and creating the future that will return the status
// of the push after it's sent.
// (It's a long line, sorry)
final PushNotificationFuture<SimpleApnsPushNotification, PushNotificationResponse<SimpleApnsPushNotification>> sendNotificationFuture = apnsClient.sendNotification(pushNotification);
// getting the response from APNs
final PushNotificationResponse<SimpleApnsPushNotification> pushNotificationResponse = sendNotificationFuture.get();
if (pushNotificationResponse.isAccepted()) {
System.out.println("Push notification accepted by APNs gateway.");
} else {
System.out.println("Notification rejected by the APNs gateway: " +
pushNotificationResponse.getRejectionReason());
if (pushNotificationResponse.getTokenInvalidationTimestamp() != null) {
System.out.println("\t…and the token is invalid as of " +
pushNotificationResponse.getTokenInvalidationTimestamp());
}
}
} catch (final ExecutionException e) {
System.err.println("Failed to send push notification.");
e.printStackTrace();
}

Push notifications won't work in TestFlight, but do work from Xcode

I'm trying to set-up push notifications for my app.
I'm so far that, when the app is installed through Xcode (in development mode basically), I can successfully receive push notifications. However, as soon as I install the app from TestFlight and try to use the new device token, the APN answers with BadDeviceToken.
I did do my own research, but all the questions on this seem to be outdated: While these used *.pem and *.p12 certificates, I'm using a *.p8 certificate. As far as I understood, p8 certificates are for both development and production, so I don't see the problem here?
I'm using the edamov\pushok library from Github with this code:
<?php
require '../../vendor/autoload.php';
use Pushok\AuthProvider;
use Pushok\Client;
use Pushok\Notification;
use Pushok\Payload;
use Pushok\Payload\Alert;
$options = [
'key_id' => 'xxx', // The Key ID obtained from Apple developer account
'team_id' => 'xxx', // The Team ID obtained from Apple developer account
'app_bundle_id' => 'xxx', // The bundle ID for app obtained from Apple developer account
'private_key_path' => 'xxx (p8 certificate path)', // Path to private key
'private_key_secret' => null // Private key secret
];
$authProvider = AuthProvider\Token::create($options);
$alert = Alert::create()->setTitle('Hello!');
$alert = $alert->setBody('First push notification');
$payload = Payload::create()->setAlert($alert);
//set notification sound to default
$payload->setSound('default');
//add custom value to your notification, needs to be customized
$payload->setCustomValue('key', 'value');
$deviceTokens = ['xxx (device token from TestFlight installation)'];
$notifications = [];
foreach ($deviceTokens as $deviceToken) {
$notifications[] = new Notification($payload,$deviceToken);
}
$client = new Client($authProvider, $production = false);
$client->addNotifications($notifications);
$responses = $client->push(); // returns an array of ApnsResponseInterface (one Response per Notification)
foreach ($responses as $response) {
echo($response->getApnsId());
echo($response->getStatusCode());
echo($response->getReasonPhrase());
echo($response->getErrorReason());
echo($response->getErrorDescription());
}
So how can I setup the APN with a p8 certificate for production mode? Do I need to create a production certificate and somehow include it somewhere?
While trying to send push if app installed through Testflight did you keep the Sandbox enable or not?

Which npm module should be used to send push notification to Apple(iphone) in node js and why and how can we achieve this?

I want to send push-notifications to iphone by using node.js server-side language
I found npm two modules for doing that
https://www.npmjs.com/package/apns
var apns = require("apns"), options, connection, notification;
options = {
keyFile : "conf/key.pem",
certFile : "conf/cert.pem",
debug : true
};
connection = new apns.Connection(options);
I have only single pem file but they are asking about two pem files key.pem and cert.pem
https://www.npmjs.com/package/apn
var options = {
token: {
key: "path/to/key.p8",
keyId: "T0K3NK3Y1D",
teamId: "T34M1D"
},
production: false
};
var apnProvider = new apn.Provider(options);
In this, they are asking about key, keyId. teamId. But how can I get this ?
Which npm module should I used for sending Apple push notifications ?
I have pem file and bundle id of my app. Are they sufficient to send push notifications to Apple user or not ?
Also can't figure out which npm module is best suited for sending the same ?
Any suggestions are always welcome regarding this.
Thanks for the help
You have too many subquestions in that question which point to the same question of which npm module to use for sending iOS notifications from node server.
I used APN module from here and it works seamlessly-
https://www.npmjs.com/package/apn
Apple guide on how APN works-
https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1
Details on how to create key and certificate files-
https://quickblox.com/developers/How_to_create_APNS_certificates
Hope that helps!

Azure Push Notification Error from IOS Xcode

I feel I am the first one in the universe trying to get iOS swift working with Azure, not much help out there.
I followed this Create an iOS app
and then Add Push Notifications to your iOS App. I am supposed to be able to do a successful push notification from iPhone, but I get this error. btw: I can get my C# code to trigger in visual studio in my pc (using this tutorial), so the request seems to be working, but the response sucks. Any one knows how to fix it!!
Error registering for notifications: Optional("Error Domain=com.Microsoft.MicrosoftAzureMobile.ErrorDomain Code=-1302 \"{\"message\":\"An error has occurred.\"}\" UserInfo={com.Microsoft.MicrosoftAzureMobile.ErrorRequestKey=<NSMutableURLRequest: 0x14cebf780> { URL: http://<mysite>.azurewebsites.net/push/installations/1E32E9B5-E976-4CCD-BD61-D026D3F4FF1C }, com.Microsoft.MicrosoftAzureMobile.ErrorResponseKey=<NSHTTPURLResponse: 0x14cec54b0> { URL: http://<mysite>.azurewebsites.net/push/installations/1E32E9B5-E976-4CCD-BD61-D026D3F4FF1C } { status code: 500, headers {\n \"Content-Length\" = 36;\n \"Content-Type\" = \"application/json; charset=utf-8\";\n Date = \"Wed, 11 May 2016 21:39:39 GMT\";\n Server = \"Microsoft-IIS/8.0\";\n \"Set-Cookie\" = \"ARRAffinity=8d79cd782ff16b44f7f280b76e2bc5564d86e0d1b228227b8e0033f4bb1c4582;Path=/;Domain=<mysite>.azurewebsites.net\";\n \"X-Powered-By\" = \"ASP.NET\";\n} }, NSLocalizedDescription={\"message\":\"An error has occurred.\"}}")
UPDATE #1
The only url I have is the one per the tutorial. The rest of the code is identical to the ones I mentioned in the links (I copied it character by character):
class ClientManager {
static let sharedClient = MSClient(applicationURLString: "http://<mysite>.azurewebsites.net")
}
UPDATE #2
#Pau Senabre I am working with swift not Objective-C per my question (see my tags under question), so I don't have an .m file per your step #1. I also don't have the logErrorIfNotNil you mentioned. My method (which is generated by Azure before modifications) looks like this:
#IBAction func addItem(sender : AnyObject) {
self.performSegueWithIdentifier("addItem", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!)
{
if segue.identifier == "addItem" {
let todoController = segue.destinationViewController as! ToDoItemViewController
todoController.delegate = self
}
}
UPDATE #3
#Pau Senabre My goal is to do mobile apps/services, not mobile engagement. See the difference here. btw: I had followed the azure engagement example when I started playing with it and had worked for me. But my need now is web/mobile apps. So, does what you suggested still apply for my need?
Could you please post some code? I think you may be using a wrong URL in a certain place.
To UPDATE #2
Check the following link:
https://github.com/Azure/azure-content/blob/master/articles/mobile-engagement/mobile-engagement-ios-swift-get-started.md
In section Modify your Application Delegate make sure you create a reach module and your existing Engagement initialization has all the init Values.
EngagementAgent.init("Endpoint={YOUR_APP_COLLECTION.DOMAIN};SdkKey={YOUR_SDK_KEY};AppId={YOUR_APPID}", modulesArray:[reach])
The error Code provided Error Domain=com.Microsoft.MicrosoftAzureMobile.ErrorDomain Code=-1302 matches to a bad request. If you are entering some data, make beforehand a Data Input Validation:
1 In the TodoService.m file, locate the addItem method search for the [self logErrorIfNotNil:error]; line of code. Beneath that line of code, replace the remainder of the completion block with the following code that checks to see if there was an error in the request and if that error code was –1302, indicating a bad request:
BOOL badRequest = ((error) && (error.code == -1302));
// detect text validation error from service.
if (!badRequest) // The service responded appropriately
{
NSUInteger index = [itemscount];
[(NSMutableArray *)itemsinsertObject:result atIndex:index];
// Let the caller know that we finished
completion(index);
}
2 Build and run; you can see in the Xcode output window that the bad request error from the service was handled:
2012-10-23 22:01:32.169 Quickstart[5932:11303] ERROR Error Domain=com.Microsoft.WindowsAzureMobileServices.ErrorDomain Code=-1302 “Text length must be under 10″ UserInfo=0x7193850 {NSLocalizedDescription=Text length must be under 10, com.Microsoft.WindowsAzureMobileServices.ErrorResponseKey=, com.Microsoft.WindowsAzureMobileServices.ErrorRequestKey=https://task.azure-mobile.net/tables/TodoItem>}
3 Finally, in the TodoService.m file, locate the logErrorIfNotNil method, which handles the logging of errors to the output window. Inside the if code block, just below the line NSLog(#”ERROR %#”, error); add the following if block:
// added to display description of bad request
if (error.code == -1302){
UIAlertView *av =
[[UIAlertView alloc]
initWithTitle:#”Request Failed”
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#”OK”
otherButtonTitles:nil
];
[av show];
}
Aditionally, review the following steps in the Azure Setup, maybe you are missing something at some point:
https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-ios-get-started-push/
1 Create a Notification Hub
This creates a new notification hub and connects it to your mobile app. If you have an existing notification hub, you can choose to connect it to your Mobile App backend instead of creating a new one.
2 Register app for push notifications
Register an App ID for your app. Create an explicit App ID (not a wildcard App ID) and for Bundle ID, use the exact Bundle ID that is in your Xcode quickstart project. It is also crucial that you check the Push Notifications option.
Next, configuring push notifications. You may create either a "Development" or "Distribution" SSL certificate (remember to select the corresponding option in the Azure portal later.)
3 Configure Azure to send push notifications
In the Azure portal, click Browse All > App Services > your Mobile App backend > Settings > Mobile > Push > Apple Push Notification Services > Upload Certificate. Upload the .p12 file, selecting the correct Mode (corresponding to whether the client SSL certificate you generated earlier was Development or Distribution.)
4 Update server project to send push notifications
Replace the PostTodoItem method with the following code:
public async Task<IHttpActionResult> PostTodoItem(TodoItem item)
{
TodoItem current = await InsertAsync(item);
// Get the settings for the server project.
HttpConfiguration config = this.Configuration;
MobileAppSettingsDictionary settings =
this.Configuration.GetMobileAppSettingsProvider().GetMobileAppSettings();
// Get the Notification Hubs credentials for the Mobile App.
string notificationHubName = settings.NotificationHubName;
string notificationHubConnection = settings
.Connections[MobileAppSettingsKeys.NotificationHubConnectionString].ConnectionString;
// Create a new Notification Hub client.
NotificationHubClient hub = NotificationHubClient
.CreateClientFromConnectionString(notificationHubConnection, notificationHubName);
// iOS payload
var appleNotificationPayload = "{\"aps\":{\"alert\":\"" + item.Text + "\"}}";
try
{
// Send the push notification and log the results.
var result = await hub.SendAppleNativeNotificationAsync(appleNotificationPayload);
// Write the success result to the logs.
config.Services.GetTraceWriter().Info(result.State.ToString());
}
catch (System.Exception ex)
{
// Write the failure result to the logs.
config.Services.GetTraceWriter()
.Error(ex.Message, null, "Push.SendAsync Error");
}
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
this is the proper answer from another question I had earlier, which fixes both: Registration and Receiving push notifications. I said this in here:
I finally have been able to receive notifications last night. I went ahead and redid an entire walk-through of all apple-side installation steps using this tutorial: Sending push notifications to iOS with Azure Notification Hubs then the azure-side of things using this: Create an iOS app and Add Push Notifications to your iOS App. That took care of the registering the app of the device successfully, which I was able to verify using the note of AdrianHall in this thread. But that wasn't enough. The Azure tutorials fell short detailing the steps needed in Xcode, which I found here: [How To] Setup Remote Push Notification in iOS - Swift 2.0 Code I didn't have to setup any "push notification" in Xcode or anything like that.
I hope this detailed answer will save you many hours of digging through.

certificate at provider for push notification in iOS

I need to implement iOS push notification in my app. I ve been trying this for a while and have done the iOS side code changes required. I'm able to get the device token from APNS. But im stuck with the provider side implementation.
I'm using a java provider and using JAVAPNS library to implement the provider side logic. What puzzles me is the certificate installation and stuff required at the provider.
My provider runs on unix/windows machine and I am not sure how to proceed with the SSL certificate installation here.
I have obtained SSL certificate for push notification from the apple developer site. But how do I proceed with the p12 file?
I do not find many explanations on this on the net though there are a great deal of discussions and tutorial about the iOS side implementation of push notification.
The SSL certificate is used to establish the socket connection to gateway.push.apple.com from your server side code. Here is some Ruby code as an example:
APN_SSL_KEY_FILE = 'lib/SSLCert_Private_Key.pem'
APN_SSL_HOST = 'gateway.push.apple.com'
APN_SSL_PORT = 2195
APN_SSL_PASSWORD = '<password>'
def configure_apn_cert
##apn_cert = File.read(File.join(RAILS_ROOT, APN_SSL_KEY_FILE))
##apn_context = OpenSSL::SSL::SSLContext.new
##apn_context.key = OpenSSL::PKey::RSA.new(##apn_cert, APN_SSL_PASSWORD)
##apn_context.cert = OpenSSL::X509::Certificate.new(##apn_cert)
end
def create_and_configure_apn_server
configure_apn_cert if not ##apn_cert
puts "APN Service: Configuring APN SOCKET and SSL connection"
#apn_socket = TCPSocket.new(APN_SSL_HOST, APN_SSL_PORT)
#apn_ssl = OpenSSL::SSL::SSLSocket.new(#apn_socket, ##apn_context)
#apn_ssl.sync = true
#apn_ssl.connect
#apn_is_active = false; # reopen the TCP/SSL sockets for now
end
You get a .pem file with:
$ openssl pkcs12 -in myfile.p12 -out myfile.pem
If you're using JavaPNS, it's as simple as :
import javapns.Push;
public class PushTest {
public static void main(String[] args) {
Push.alert("Hello World!", "keystore.p12", "keystore_password", false, "Your token");
}
}

Resources