Azure Chen
Azure Chen

Reputation: 879

Send a notification by Lambda function with AWS Pinpoint

I have an iOS app with a backend build by MobileHub with API Gateway, Lambda, and DynamoDB. I noticed that the SNS function of MobileHub has been replaced by Pinpoint, and I would like to create a notification system using this new service.

When a user creates a new post through API Gateway, a lambda function will be triggered and I suppose I can send a notification to the subscribers by Pinpoint. But I cannot find any example or reference doc in the official website of Pinpoint.

Do you have any resource for this scenario or any idea? Thank you very much!

Upvotes: 7

Views: 8268

Answers (4)

Kazuya Fujimoto
Kazuya Fujimoto

Reputation: 93

Finally, I've got something that perfectly works. The answer is that you have to use "targetClient" to update endpoint inside "didRegisterForRemoteNotificationsWithDeviceToken" function.

let client = self.pinpoint!.targetingClient
let profile = client.currentEndpointProfile()
print("EndpointId = \(profile.endpointId)")
profile.user?.userId = <YOUR_CUSTOM_ID>
client.update(profile)

Client Side(XCODE)

Here is my [AppDelegate.swift] looks like: (Important part is inside "didRegisterForRemoteNotificationsWithDeviceToken" function)

import UserNotifications
import AWSPinpoint
class AppDelegate: UIResponder, UIApplicationDelegate {
    var pinpoint: AWSPinpoint?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        // Instantiate Pinpoint
        let pinpointConfiguration = AWSPinpointConfiguration.defaultPinpointConfiguration(launchOptions: launchOptions)
        // Set debug mode to use APNS sandbox, make sure to toggle for your production app
        pinpointConfiguration.debug = true
        self.pinpoint = AWSPinpoint(configuration: pinpointConfiguration)

        // Present the user with a request to authorize push notifications
        self.registerForPushNotifications()

        return true
    }
    func registerForPushNotifications() {
        UNUserNotificationCenter.current()
            .requestAuthorization(options: [.alert, .sound, .badge]) { [weak self] granted, _ in
                print("Permission granted: \(granted)")
                guard granted else { return }

                // Only get the notification settings if user has granted permissions
                self?.getNotificationSettings()
            }
    }
    func getNotificationSettings() {
        UNUserNotificationCenter.current().getNotificationSettings { settings in
            print("Notification settings: \(settings)")
            guard settings.authorizationStatus == .authorized else { return }

            DispatchQueue.main.async {
                // Register with Apple Push Notification service
                UIApplication.shared.registerForRemoteNotifications()
            }
        }
    }
    func application(_: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        print("DidRegisterForRemoteNotificationsWithDeviceToken: Start")
        let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
        let token = tokenParts.joined()
        print("Device Token: \(token)")
        // Register the device token with Pinpoint as the endpoint for this user
        self.pinpoint!.notificationManager.interceptDidRegisterForRemoteNotifications(withDeviceToken: deviceToken)

        //set custom userId and update endpoint
        let client = self.pinpoint!.targetingClient
        let profile = client.currentEndpointProfile()
        print("EndpointId = \(profile.endpointId)")
        profile.user?.userId = <YOUR_CUSTOM_ID>
        client.update(profile)
    }
    func application(_: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Failed to register: \(error)")
    }
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        print("didReceiveRemoteNotification:\(userInfo)")
        // Pass this remote notification event to pinpoint SDK to keep track of notifications produced by AWS Pinpoint campaigns.
        self.pinpoint!.notificationManager.interceptDidReceiveRemoteNotification(userInfo)
    }
}

Backend (Lambda with Nodejs)

And here is a code to send a notification to specific user.

'use strict';
const AWS = require('aws-sdk');
const pinpoint = new AWS.Pinpoint({region: 'us-west-2'});


exports.handler = (event, context, callback) => {
    
    const done = (err, data) => {
        if(err){
            console.log('ERROR:', err);
            const response = {
                statusCode: 400,
                body: JSON.stringify(err)
            };
            callback(response);
        }else{
            console.log('SUCCESS:', data);
            const response = {
                statusCode: 200,
                body: JSON.stringify(data)
            };
            callback(null, response);
        }
    };
    
    
    let users = {};
    users[<YOUR_CUSTOM_ID>] = {};
    const params = {
        ApplicationId: PINPOINT_PROJECT_ID, 
        SendUsersMessageRequest: {
            Users: users,
            MessageConfiguration: {
                APNSMessage: {
                    Action: 'OPEN_APP',
                    Title: "Hi, I am AWS Pinpoint.",
                    SilentPush: false,
                    Body: "You've got a nice message."
                }
            }
        }
    };
    pinpoint.sendUsersMessages(params, (err, data)=>{
        if(err){
            done(err);
        }else{
            done(null, data);
        }
    });
};

Hope those work for you too.

Upvotes: 1

Nicolai Lissau
Nicolai Lissau

Reputation: 8332

I was struggling a lot getting a lambda function working, so please see this answer as an addition to the answer from Dylan w.

Client

import PushNotification from '@aws-amplify/pushnotification';
import Analytics from '@aws-amplify/analytics';

PushNotification.onRegister((token) => {

    Analytics.updateEndpoint({
        address: token,
        channelType: 'APNS',
        optOut: 'NONE',
        // Customized userId
        userId: "e236e3ea-bas9-4eae-967e-0eb9bcaca26d" // Example
    })

});

Lambda function

'use strict';

const AWS = require('aws-sdk');

exports.handler = async (event, context) => {

  var pinpoint = new AWS.Pinpoint();

  const sendMessagesParams = {
    ApplicationId: <YOUR_APPLICATION_ID>, // Find it in Pinpoint->All projects
    SendUsersMessageRequest: {
        Users:{<USER_ID>:{}}, // The same userId as set on the client. This way you can "follow" people if they switch device
        MessageConfiguration:{
          APNSMessage:{
            Action:"OPEN_APP",
            Title:"Message received",
            Body:"You have a new message"
        }
      }
    }
  };

  return await new Promise( (resolve, reject) => {

    pinpoint.sendUsersMessages(sendMessagesParams, (sendMessagesErr, sendMessagesData) => {
      if(sendMessagesErr) reject(sendMessagesErr)
      if(sendMessagesData) resolve(sendMessagesData)
    });

  });

};

Note that the call to pinpoint is wrapped in a promise. Because pinpoint.sendUserMessages accepts a callback, the execution is continued (async nature of Node), which will shut down the lambda function and you will get no output from the callback function or receive a notification, without awaiting the function to finish.

Upvotes: 3

Dylan w
Dylan w

Reputation: 2906

Depends what you mean by notification, I assume you would like to send a push notification to a particular user (Pinpoint endpoint).

Pinpoint stores each device associated with a user as an "endpoint", generally created by the AWS client side analytics library (e.g. amplify analytics).

The client

With the amplify analytics library, I call updateEndpoint so I can specify a userId that is available to Lambda, as well as the device token and remove optOut so user can receive the push notification:

  1. Address - The token generated from user accepting push notification permission (iOS)
  2. optOut - NONE so they can receive push notifications
  3. userId - unique id for user (Cognito's sub)

Lambda (node.js)

Now you can send a push notification, using the userId and the Pinpoint SDK.

Example:

const sendMessagesParams = {
    ApplicationId: process.env.PINPOINT_APP_ID,
    SendUsersMessageRequest: {
        Users: {
            [receiverUserId]: {}
        },
        MessageConfiguration: {
            APNSMessage: {
                Action: 'OPEN_APP',
                Title: 'Message received',
                SilentPush: false,
                Body: `You have a new message`
            },
            GCMMessage: {
                Action: 'OPEN_APP',
                Title: 'Message received',
                SilentPush: false,
                Body: `You have a new message`
            }
        }
    }
};

console.log('sendMessagesParams', JSON.stringify(sendMessagesParams));

pinpoint.sendUsersMessages(sendMessagesParams, (sendMessagesErr, sendMessagesData) => console.log('push sent')

For your particular scenario, I set up a DynamoDB stream and trigger a Lambda when a record changes within the table. You may need to add the IAM permissions manually once the lambda is created.

Sources

Upvotes: 8

Cheruvian
Cheruvian

Reputation: 5877

This is certainly possible with Amazon Pinpoint. You can find the Javascript SDK documentation here.

There are 2 modes of sending with Pinpoint.

  1. Direct send - This is effectively the same as what SNS has traditionally been. You need a device token and you can send directly to your push provider using that token.
  2. Segmentation sends - This mode is slightly different and assumes that you have loaded all your devices into Pinpoint via the Mobile SDK as part of your app, or via an S3 Import. The benefit here is that you can segment your devices and send to that segment (e.g. 'Ryans Friends').

So in your Lambda backed API you can choose to either send directly to subscribers (if you have their addresses) or potentially an entire segment of subscribers (if you have loaded your endpoints into Pinpoint).

Upvotes: 0

Related Questions