美文网首页
使用AWS的SNS(Simple Notification Se

使用AWS的SNS(Simple Notification Se

作者: and2long | 来源:发表于2018-01-06 14:46 被阅读0次

    使用场景:

    在自有用户体系中,实现用户A给用户B发送消息,通知事务的处理结果。

    举个例子:添加好友。
    用户A发送好友请求给用户B,用户B收到请求后处理并将处理结果发送给用户A。

    需求分析

    1. 选择一个消息推送平台:
      国内推送平台:极光、个推等,国外有GCM(Google Cloud Message)。
    2. 在自己的服务器上开发一个API。
      服务器接受用户A的请求消息,并通过推送平台将消息传递给用户B。 同理,用户B将处理结果发送给用户A。

    通过上面的分析,我们结合服务器实现了功能需求。

    但是,如果没有后台开发人员怎么办???

    文章标题说的就是这个问题的解决方案。
    AWS是亚马逊的云开发平台,类似国内的阿里云。SNS则是其中的一项服务,使应用程序、用户、终端设备能够通过云端即时发送或者接受消息。
    我们不需要再开发一个API处理用户之间的消息传递,因为SNS已经全部做好了。我们需要做的便是选择一个推送平台、定义自己的消息格式,调用相关的SDK方法即可。

    实现步骤(Android+GCM)

    这里默认你已经有了AWS开发者账号。

    1. 创建平台应用程序,得到ARN。

    • 进入SNS控制面板(控制台首页搜索SNS即可找到),依次点击“应用程序”-->“创建平台应用程序”


      创建平台应用程序
    • 应用程序名称:填写项目名称即可。
    • 推送通知平台:根据自己的需求进行选择,这里我选择GCM,通过谷歌推送来实现。
    • API密钥:在相应的推送平台注册应用后得到。
    • 获取GCM平台下API密钥
      a. 建议通过Firebase集成GCM,集成完好后,我们进入Google Cloud Platform,


      Google Cloud Platform

      b. 先选择通过Firebase创建的项目,然后在左侧菜单栏选择“API和服务”-->“凭据”。
      c. 复制红框内名称为“Server Key”的密钥(Firebase默认创建的3个密钥,分别作用于Browser、Server、Android)。
      因为我们想让AWS来处理消息传递,AWS属于Server一类。
      将获得的密钥粘贴到“创建应用平台程序”窗口的“API密钥”一栏,点击右下角“创建平台应用程序”,稍后界面显示如下:


      得到ARN

    2. 将设备终端注册到ARN(代码实现),得到终端节点。
    实现原理:集成GCM后,会有一个服务专门获取或更新token,我们只需要将这个token注册到ARN下即可。

    //注册arn
    private void sendRegistrationToServer(String token) {
            // Implement this method to send token to your app server.
            // 创建平台终端节点和管理设备令牌
            client.setRegion(Region.getRegion(Regions.AP_NORTHEAST_1));
            //retrieveEndpointArn方法是将保存在sp中的endpointArn取出,自己实现一下。
            String endpointArn = retrieveEndpointArn();
            boolean updateNeeded = false;
            boolean createNeeded = ("".equals(endpointArn));
            if (createNeeded) {
                // No platform endpoint ARN is stored; need to call createEndpoint.
                endpointArn = createEndpoint(token);
                createNeeded = false;
            }
            System.out.println("Retrieving platform endpoint data...");
            // Look up the platform endpoint and make sure the data in it is current, even if
            // it was just created.
            try {
                GetEndpointAttributesRequest geaReq =
                        new GetEndpointAttributesRequest()
                                .withEndpointArn(endpointArn);
                GetEndpointAttributesResult geaRes =
                        client.getEndpointAttributes(geaReq);
                updateNeeded = !geaRes.getAttributes().get("Token").equals(token)
                        || !geaRes.getAttributes().get("Enabled").equalsIgnoreCase("true");
            } catch (NotFoundException nfe) {
                // We had a stored ARN, but the platform endpoint associated with it
                // disappeared. Recreate it.
                createNeeded = true;
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            if (createNeeded) {
                createEndpoint(token);
            }
            System.out.println("updateNeeded = " + updateNeeded);
            if (updateNeeded) {
                // The platform endpoint is out of sync with the current data;
                // update the token and enable it.
                System.out.println("Updating platform endpoint " + endpointArn);
                Map attribs = new HashMap();
                attribs.put("Token", token);
                attribs.put("Enabled", "true");
                SetEndpointAttributesRequest saeReq =
                        new SetEndpointAttributesRequest()
                                .withEndpointArn(endpointArn)
                                .withAttributes(attribs);
                client.setEndpointAttributes(saeReq);
            }
        }
        /**
         * @return never null
         */
        private String createEndpoint(String token) {
            String endpointArn = null;
            try {
                System.out.println("Creating platform endpoint with token " + token);
                //创建endpointArn
                String arn = "自己的arn";
                CreatePlatformEndpointRequest cpeReq =
                        new CreatePlatformEndpointRequest()
                                .withPlatformApplicationArn(arn)
                                .withToken(token);
                CreatePlatformEndpointResult cpeRes = client
                        .createPlatformEndpoint(cpeReq);
                endpointArn = cpeRes.getEndpointArn();
                //订阅主题
    //String topic = "自己的主题";
    // SubscribeRequest request = new SubscribeRequest()
    // .withTopicArn(topic)
    // .withProtocol("application")
    // .withEndpoint(endpointArn);
    // SubscribeResult subscribeResult = client.subscribe(request);
    // Log.i(TAG, "subscribeResult: " + subscribeResult.getSubscriptionArn());
            } catch (InvalidParameterException ipe) {
                String message = ipe.getErrorMessage();
                System.out.println("Exception message: " + message);
                Pattern p = Pattern.compile(".*Endpoint (arn:aws:sns[^ ]+) already exists with the same token.*");
                Matcher m = p.matcher(message);
                if (m.matches()) {
                    // The platform endpoint already exists for this token, but with
                    // additional custom data that
                    // createEndpoint doesn't want to overwrite. Just use the
                    // existing platform endpoint.
                    endpointArn = m.group(1);
                } else {
                    // Rethrow the exception, the input is actually bad.
                    throw ipe;
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            //将endpointArn保存在sp中,自己实现一下。
            storeEndpointArn(endpointArn);
            return endpointArn;
        }
    
    

    完成以上步骤后,在程序启动后,便可以得到如下图所示内容。


    终端节点
    • 令牌:GCM下发的token
    • 终端节点 ARN:SNS为每一个终端生成的唯一标识。

    3. 推送消息到某一个终端节点。
    在SNS控制台中,选择一个终端节点,点击“发布到终端节点”,在弹出的界面中,输入消息,点击发送即可。

    4. 终端间互发消息(代码实现)。
    经过以上3个步骤,每个用户启动应用程序后,都会注册到SNS,并生成各自特有的终端节点。
    那么,终端之间发送消息就简单了。
    用户A向用户B发送消息,只需要知道用户B的终端节点号码即可。

        /**
         * 给指定终端发送消息
         *
         * @param endpointArn 对方的终端节点
         * @param targetId 对方的id
         * @param gcmMsg 消息体
         * @return 发送成功后返回该条消息id
         */
        public static Observable<String> sendMsgToDevice(final String endpointArn, final String targetId, final GCMMsg gcmMsg) {
            return Observable.fromCallable(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    String mId = SpUtil.getString(Constants.USER_ID);
                    //发消息
                    AmazonSNSClient client = new AmazonSNSClient(CognitoClientManager.getCredentials());
                    client.setRegion(Region.getRegion(Regions.AP_NORTHEAST_1));
                    PublishRequest request = new PublishRequest();
                    request.setTargetArn(endpointArn);
                    request.setMessageStructure("json");
                    String msg = "{\n" +
                            "\"GCM\": \"{ \\\"data\\\": { " +
                            "\\\"category\\\": \\\"" + gcmMsg.getCategory() + "\\\", " +
                            "\\\"title\\\": \\\"" + gcmMsg.getTitle() + "\\\", " +
                            "\\\"message\\\": \\\"" + gcmMsg.getMessage() + "\\\", " +
                            "\\\"url\\\": \\\"" + gcmMsg.getUrl() + "\\\", " +
                            "\\\"data\\\": \\\"" + gcmMsg.getData() + "\\\" } }\"\n" +
                            "}";
                    request.setMessage(msg);
                    PublishResult result = client.publish(request);
                    Log.i("SNS", "messageId: " + result.getMessageId());
                    return result.getMessageId();
                }
            });
        }
    
    

    至此,终端间互发消息的需求就完成了,全部借助AWS的SNS服务,无需另外开发后台API,自己只需要调用相关的SDK方法即可。

    相关文章

      网友评论

          本文标题:使用AWS的SNS(Simple Notification Se

          本文链接:https://www.haomeiwen.com/subject/ywsynxtx.html