使用 AWS Pinpoint 通过 Lambda 函数发送通知

Posted

技术标签:

【中文标题】使用 AWS Pinpoint 通过 Lambda 函数发送通知【英文标题】:Send a notification by Lambda function with AWS Pinpoint 【发布时间】:2017-12-29 16:38:30 【问题描述】:

我有一个由MobileHubAPI GatewayLambdaDynamoDB 构建的ios 应用程序。 我注意到MobileHubSNS 功能已被Pinpoint 取代,我想使用这个新服务创建一个通知系统。

当用户通过API Gateway创建新帖子时,会触发一个lambda函数,我想我可以通过Pinpoint向订阅者发送通知。 但是我在Pinpoint的官方网站上找不到任何示例或参考文档。

你有这个场景的任何资源或任何想法吗?非常感谢!

【问题讨论】:

【参考方案1】:

取决于您所说的通知是什么意思,我假设您想向特定用户发送推送通知(Pinpoint 端点)。

Pinpoint 将与用户关联的每个设备存储为“端点”,通常由 AWS 客户端分析库创建(例如放大分析)。

客户

使用放大分析库,我调用updateEndpoint,这样我就可以指定一个可供 Lambda 使用的userId,以及设备令牌并删除optOut,这样用户就可以接收推送通知:

    Address - 用户接受推送通知权限时生成的令牌 (iOS) optOut - NONE 以便他们接收推送通知 userId - 用户的唯一 ID(Cognito 的子

Lambda (node.js)

现在您可以使用userId 和 Pinpoint SDK 发送推送通知。

示例:

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')

对于您的特定场景,我设置了 DynamoDB 流 并在表中的记录发生更改时触发 Lambda。创建 lambda 后,您可能需要手动添加 IAM 权限。

来源

Full list of pinpoint methods you can use in lambda (Node.JS) Update endpoint using Amplify Analytics (JS) Dynamodb streams - 触发 lambda

【讨论】:

你是如何实例化 pinpoint 的?我已遵循所有文档,但被告知 sendUsersMessages 未定义。 sendMessages 工作正常.. 我确实指定了一个 API 版本,并且区域精确定位在:const pinpoint = new AWS.Pinpoint( apiVersion: '2016-12-01', region: process.env.PINPOINT_REGION ); process.env 常量列在 lambda 代码下方的“环境变量”部分中 在您的 Lambda 函数中,您是否需要提供 AWS 凭证或 IAM 角色?当我尝试运行您列出的代码时,根本没有任何反应 @Attaque 取决于您的实施方式,具体而言,我创建了一个移动目标完全访问策略,以允许发送消息,以及流 iam 角色。 "Version": "2012-10-17", "Statement": [ "Effect": "Allow", "Action": [ "mobiletargeting:*" ], "Resource": "*" ] 【参考方案2】:

我在让 lambda 函数正常工作时遇到了很多困难,所以请将此答案视为对 Dylan w 答案的补充。

客户

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 函数

'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)
    );

  );

;

请注意,对 pinpoint 的调用包含在一个承诺中。因为pinpoint.sendUserMessages 接受回调,所以会继续执行(Node 的异步性质),这将关闭 lambda 函数,您将不会从回调函数获得任何输出或收到通知,而无需等待函数完成。

【讨论】:

我收到一个:由于配置错误导致执行失败:格式错误的 Lambda 代理响应 Mon Sep 14 08:44:55 UTC 2020:方法完成,状态为:502 你知道如何解决吗?我相信这与 apigateway 响应有关,因为推送通知已发送 我正在使用pinpoint.sendMessages,但它不起作用(没有错误,什么都没有)。我将它包装在return await new Promise(...) 中,现在消息发送,因为函数正在等待它。感谢您的提示!【参考方案3】:

最后,我得到了一些完美的作品。 答案是您必须使用“targetClient”来更新“didRegisterForRemoteNotificationsWithDeviceToken”函数内的端点。

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

客户端(XCODE)

这是我的 [AppDelegate.swift] 的样子: (重要部分在“didRegisterForRemoteNotificationsWithDeviceToken”函数内)

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)
    

后端(带有 Nodejs 的 Lambda)

这是一个向特定用户发送通知的代码。

'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);
        
    );
;

希望这些对你也有用。

【讨论】:

【参考方案4】:

这当然可以通过 Amazon Pinpoint 实现。您可以找到 javascript SDK 文档here。

Pinpoint 有两种发送模式。

    Direct send - 这实际上与传统上的 SNS 相同。您需要一个设备令牌,您可以使用该令牌直接发送给您的推送提供商。 Segmentation sends - 此模式略有不同,假设您已通过 Mobile SDK 作为应用程序的一部分或通过 S3 导入将所有设备加载到 Pinpoint。这样做的好处是您可以对您的设备进行分段并发送到该分段(例如“Ryans Friends”)。

因此,在您的 Lambda 支持的 API 中,您可以选择直接发送给订阅者(如果您有他们的地址)或可能是整个订阅者段(如果您已将端点加载到 Pinpoint)。

【讨论】:

我应该将 ARN 存储在我的 DynamoDB 表中吗?或者Pinpoint 将帮助我管理 ARN。如果我想向 Ryans Friends 部分发送消息。我怎么能认出这个片段是给 Ryan 这个Cognito 身份的?

以上是关于使用 AWS Pinpoint 通过 Lambda 函数发送通知的主要内容,如果未能解决你的问题,请参考以下文章

通过 AWS Pinpoint 向指定用户发送推送通知

通过AWS Pinpoint将推送通知发送给指定的用户

AWS Pinpoint 终端节点 ID 查找

AWS Pinpoint:活动目标端点为 Nul

使用 Expo 更新 APNS 证书后出现 AWS Pinpoint 错误

在 react-native 中使用 aws pinpoint 推送通知