Send push notification from iOS using Amazon SNS - ios

I set it up Amazon SNS and iOS App to send Push Notification via SNS Console and receive in iOS. It works properly.
Now, I'm trying to send push notification from a device to another device, but I'm getting the following error:
-[AWSServiceInfo initWithInfoDictionary:checkRegion:] | Couldn't read credentials provider configurations from Info.plist. Please check
your Info.plist if you are providing the SDK configuration values
through Info.plist.
There's my code to send push notification
AWSSNS *publishCall = [AWSSNS defaultSNS];
AWSSNSPublishInput *message = [AWSSNSPublishInput new];
message.subject = #"My First Message";
//This is the ending point
message.targetArn = #"arn:aws:sns:us-west-2:895047407854:endpoint/APNS_SANDBOX/XXXXX/XXXX-XXXX-XXX-XXXX";
message.subject =#"hello";
message.message =#"teste from device";
// message.messageAttributes = messageDict;
//
// message.messageStructure = jsonString;
[publishCall publish:message completionHandler:^(AWSSNSPublishResponse * _Nullable response, NSError * _Nullable error) {
if(error) NSLog(#"%#", [error userInfo]);
if(response) NSLog(#"%#", [response description]);
}];
I don't know what I'm missing.

As per the debug log of AWSInfo.m here you will get this error when you have not configured your defaultCognitoCredentialsProvider
As they will check
_cognitoCredentialsProvider = [AWSInfo defaultAWSInfo].defaultCognitoCredentialsProvider;
if they find _cognitoCredentialsProvider nil then you will get this error.
So configure defaultCognitoCredentialsProvider properly.

Related

AWS iOS SDK, The service configuration is `nil

I need to create a platform endpoint in AWS for SNS push notifications.
In order to register the device to get the push notifications, I need to send the device ID to SNS, Im not using cognito, I want to upload the token using the AWS SDK from the phone:
AWSSNSCreatePlatformEndpointInput
when I try to register with:
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken{
NSLog(#"deviceToken: %#", deviceToken);
/* This is the code to actually register the device with Amazon SNS Mobile Push based on the token received */
NSString * myArn = #"arn:aws:sns:us-east-1:123456789123:app/APNS_SANDBOX/AmazonMobilePushExample";
NSLog( #"Submit the device token [%#] to SNS to receive notifications.", [self deviceTokenAsString:deviceToken] );
AWSSNSCreatePlatformEndpointInput *platformEndpointRequest = [AWSSNSCreatePlatformEndpointInput new];
platformEndpointRequest.customUserData = #"MyUserID;iPhone5";
platformEndpointRequest.token = [self deviceTokenAsString:deviceToken];
platformEndpointRequest.platformApplicationArn = myArn;
//THIS LINE CRASHING
AWSSNS *snsManager = [AWSSNS defaultSNS];
// [snsManager createPlatformEndpoint:platformEndpointRequest];
}
But I get the crash error:
'The service configuration is nil. You need to configure awsconfiguration.json, Info.plist or set defaultServiceConfiguration before using this method.'
So, how to configure either my plist of my method directly with out cognito?
Cheers
What was needed was to set the
AWSServiceManager defaultServiceManager
as Below:
- (void)awsStartWithDeviceToken:(NSData *)deviceToken {
// Set the log level
[AWSLogger defaultLogger].logLevel = AWSLogLevelVerbose;
// Login
AWSStaticCredentialsProvider *credentialsProvider = [[AWSStaticCredentialsProvider alloc]
initWithAccessKey:#"AKIAIxxxYYYA"
secretKey:#"Tx0vhKv1xMaaabbbbccccM5+3R9lEitw2Hzw"];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc]
initWithRegion:AWSRegionAPSoutheast2
credentialsProvider:credentialsProvider];
[AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
// Create SNS Client
AWSSNS *snsManager = [AWSSNS defaultSNS];
/* 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 = [self deviceTokenAsString:deviceToken]; // Device Token No for APNS
platformEndpointRequest.platformApplicationArn = #"arn:aws:sns:ap-southeast-2:86434343191:app/APNS_SANDBOX/ios_lambada";
[snsManager createPlatformEndpoint:platformEndpointRequest completionHandler:^(AWSSNSCreateEndpointResponse * _Nullable response, NSError * _Nullable error) {
NSLog(#"errore : %#", error);
}];
}

Getting error during Login With Amazon in iOS

I have to get the user Amazon Email ID in application, I am using latest Amazon LoginWithAmazon.framework.
I am getting following error during login:
**Error Domain=AMZNLWAErrorDomain Code=8 "(null)" UserInfo={AMZNLWAErrorNonLocalizedDescription=Not authorized for requested operation}**
I have done iOS API key generation with the help of below link:
https://developer.amazon.com/docs/login-with-amazon/register-ios.html
My code snippet for Objective-C code to get EmailID through profile scope:
AMZNAuthorizeRequest *request = [[AMZNAuthorizeRequest alloc] init];
request.scopes = [NSArray arrayWithObjects:
[AMZNProfileScope profile],nil];
request.interactiveStrategy = AMZNInteractiveStrategyAuto;
[[AMZNAuthorizationManager sharedManager] authorize:request
withHandler:^(AMZNAuthorizeResult *result, BOOL
userDidCancel, NSError *error) {
if (error) {
[AmazonHelper showAlert:#"Alert!" message:#"Unable to login amazon. Please try again later."];
} else {
AMZNUser *user = result.user;
//NSString *userID = user.userID;
}
}];
I have also added URL Type with my bundle id and URL schemes to amzn-"my bundle id" along with AppDelegate deeplinking respective delegates. Also in info.plist added my amazon APIKey.
Please help me to figure out this issue as this blocking the app release.
Thanks in advance,

Will iOS Notification Service Extension delete attached file from device?

I got a strange problem. iOS Notification Service Extension will delete the attachment from device.
I use SDWebImage to display and cache image, and I implemented a Notification Service Extension to display a image in the notification alert view.
In my case, the image was already cached locally. Then, I click home button, my app was running in background, app scheduled a local notification with the cached image attach into the notification content.
See the code bellow:
1.Schedule a local notification
+ (void)postLocalNotificationGreaterThanOrEqualToiOS10:(LNotification)module body:(NSDictionary *)body {
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.sound = [UNNotificationSound defaultSound];
content.body = #"body";
content.userInfo = #{};
//get the image in device to attach into notification
NSError *error;
NSString* imgURL = [body valueForKey:kLocalNotification_Image];
NSString *filePath = [[SDImageCache sharedImageCache] defaultCachePathForKey:imgURL];
NSURL *url = [NSURL URLWithString:[#"file://" stringByAppendingString:filePath]];
UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:#"Image" URL:url options:nil error:&error];
if (attachment) {
content.attachments = #[attachment];
}
UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1 repeats:NO];
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:#"FiveSecond"
content:content trigger:trigger];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(#"error: %#", error.localizedDescription);
}
}];
}
2.Notification Service Extension (In Fact, for local notification, only didReceiveNotificationRequest:withContentHandler: was called and did nothing.)
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
NSDictionary *aps = [self.bestAttemptContent.userInfo objectForKey:#"aps"];
if (aps) {
....//For remote notification, modify the notification content here
}
else {
//For local notification, do nothing
}
self.contentHandler(self.bestAttemptContent);
}
- (void)serviceExtensionTimeWillExpire {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
self.contentHandler(self.bestAttemptContent);
}
- (NSString *)downloadImageWithURL:(NSString *)imageURLString imageName:(NSString *)imageName {
....//code will not execute for local notification
}
I found that, the image I attached into the local notification will be deleted from device. I mean, after I click the notification alert to launch app from background to foreground, I try to display the image, unfortunately, SDWebImageCache did not find the cache from neither disk nor memory.
I read the preference of iOS API, and didn't find that the attachment will be deleted. Does anybody know where could I find any clue of this issue? Maybe I just ignored something important refer to Notification Service Extension.
Now, I made a work around to fix this issue temporarily, while scheduling local notification, copy the cached image and save as another name, then attach it into local notification. Even Notification Service Extension will delete the attachment, it will just deleted the copy file, and the app will find the image from cache.
But, I really wanna know why this problem happened. Thanks in advance.
Just found in documentation
UNNotificationAttachment:
The system validates the content of attached files before scheduling
the corresponding notification request. If an attached file is
corrupted, invalid, or of an unsupported file type, the notification
request is not scheduled for delivery. Once validated, attached files
are moved into the attachment data store so that they can be accessed
by the appropriate processes. Attachments located inside an app’s
bundle are copied instead of moved.

How to launch the app when I get Remote message from pusher in background state

This is my code for getting a remote message from the pusher.
self.pusher = [PTPusher pusherWithKey:#"pusherKey" delegate:self encrypted:YES cluster:#"ap2"];
PTPusherChannel *channel = [self.pusher subscribeToChannelNamed:#"my-channel"];
[channel bindToEventNamed:#"my-event" handleWithBlock:^(PTPusherEvent *channelEvent) {
NSString *message = [channelEvent.data objectForKey:#"message"];
}];
[self.pusher connect];
No, it is not possible to launch app automatically when in the background.
Performing some short task is available but not launch app.

Firebase Google Cloud messaging from device to device

I couldn't understand how can i send message from iOS device to another iOS device, and trying to understand the difference between
Firebase Notifications and Google Cloud Messaging.
Firebase Notifications say's from the server you can send a message to devices.
Google Cloud Messaging: it sends messages from server to devices(downstream) or device to server(upstream) !!
Example of upstream:
[[FIRMessaging message]sendMessage:(nonnull NSDictionary *)message
to:(nonnull NSString *)receiver
withMessageID:(nonnull NSString *)messageID
timeToLive:(int64_t)ttl;
What about if i need to send a push message from device to device ! Does it means after the device sends a messages to server, i have to program the firebase server to send push to client ? its really confusing !
No you cannot do this on iOS using firebase, what you should do is call a service on your firebase which will send a notification to the other device. APNS and GCM are a little different in terms of the server setup.
For GCM you just need the API key to be added in the POST call you make to https://android.googleapis.com/gcm/send which can be done anywhere server, mobile device, etc. All you need is the target devices device token and the API key.
APNS works differently you need attach the server SSL cert that you create on the Apple developer portal to authenticate yourself and send a push notification to a device. I am not sure how you could achieve this on an iOS device.
This thread clarifies the real difference between GCM and Firebase,
Real-time Push notifications with Firebase
https://firebase.google.com/support/faq/#gcm-not
Firebase and GCM are different but they can be used to achieve the same goals. Hope it helps you.
I don't think Firebase is currently equipped to handle this scenario. You need some sever side code to handle it. Either you could get hosting and make like a php endpoint what can used to incorporate the
[[FIRMessaging message]sendMessage:(nonnull NSDictionary *)message
to:(nonnull NSString *)receiver
withMessageID:(nonnull NSString *)messageID
timeToLive:(int64_t)ttl;
code and make it work, OR you need to find another service that can serve as the backend.
https://techcrunch.com/2016/02/02/batch-now-integrates-with-firebase-to-create-a-parse-alternative/
This Batch.com company seems to be the best solution that I have found so far. I have been able to have a users device send a json payload to an endpoint on their server that then sends Customized push notifications to specific targeted devices. It seems like Batch is specifically a Push Notification company, and it seems like the free basic plan is good enough to handle what you will need, silimar to how Parse worked.
Here is the actual code I wrote for sending the push notifications Objective C. (There is also a Swift 2 and Swift 3 example you can download from Batch.com)
NSURL *theURL = [NSURL URLWithString:[NSString stringWithFormat:#"https://api.batch.com/1.1/(your API code here)/transactional/send"]];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:theURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30.0f];
[theRequest setValue:#"(your other API key here" forHTTPHeaderField:#"X-Authorization"];
NSDictionary *messageDict = [[NSDictionary alloc]initWithObjectsAndKeys:#"Hey This is a Push!", #"title", #"But it's a friendly push. Like the kind of push friends do to each other.",#"body", nil];
NSArray *recipientsArray = [[NSArray alloc]initWithArray:someMutableArrayThatHasUsersFirebaseTokens];
NSDictionary *recipientsDict = [[NSDictionary alloc]initWithObjectsAndKeys:recipientsArray, #"custom_ids", nil];
NSDictionary *gistDict = #{#"group_id":#"just some name you make up for this pushes category that doesn't matter",#"recipients":recipientsDict,#"message":messageDict, #"sandbox":#YES};
NSError *jsonError;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:gistDict options:NSJSONWritingPrettyPrinted error:&jsonError];
[theRequest setHTTPMethod:#"POST"];
[theRequest setHTTPBody:jsonData];
NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:theRequest queue:queue1 completionHandler:^(NSURLResponse *response, NSData *POSTReply, NSError *error){
if ([POSTReply length] >0 && error == nil){
dispatch_async(dispatch_get_main_queue(), ^{
NSString *theReply = [[NSString alloc] initWithBytes:[POSTReply bytes] length:[POSTReply length] encoding:NSASCIIStringEncoding];
NSLog(#"BATCH PUSH FINISHED:::%#", theReply);
});
}else {
NSLog(#"BATCH PUSH ERROR!!!:::%#", error);
}
}];
Batch was pretty easy to install with Cocoa Pods.
I also used this code to get it working:
In app delegate:
#import Batch
In didFinishLaunching:
[Batch startWithAPIKey:#"(your api key)"]; // dev
[BatchPush registerForRemoteNotifications];
then later in app delegate:
- (void)tokenRefreshNotification:(NSNotification *)notification {
// Note that this callback will be fired everytime a new token is generated, including the first
// time. So if you need to retrieve the token as soon as it is available this is where that
// should be done.
NSString *refreshedToken = [[FIRInstanceID instanceID] token];
NSLog(#"InstanceID token: %#", refreshedToken);
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:refreshedToken forKey:#"pushKey"];
[defaults synchronize];
BatchUserDataEditor *editor = [BatchUser editor];
[editor setIdentifier:refreshedToken]; // Set to `nil` if you want to remove the identifier.
[editor save];
[self connectToFcm];
}
So thats how you do it, besides the setup and installation stuff which is all explained on the Batch.com website.
Once you get your token from firebase, you basically register it on Batch with
BatchUserDataEditor *editor = [BatchUser editor];
[editor setIdentifier:refreshedToken];
[editor save];
in App Delegate. Then when you want your users device1 to send a Push to another device2, assuming you have sent device1's custom id to device2 somehow, you can use that custom id to send the push notification payload to Batch.com's API, and Batch will handle the server side stuff to Apple APN and your Push notifications appear on device2.

Resources