LoginSignup
1
1

More than 5 years have passed since last update.

[AWS]LambdaVPCでScalaからAWS SNSを使ってiOSにJSON形式で通知してみた。

Last updated at Posted at 2016-07-07

[AWS]LambdaVPCでScalaからAWS SNSを使ってiOSにJSON形式で通知してみた。

前提

SNSのTopicが設定済み
VPCのセキュリティグループが設定済み
NATGatewayを設定したsubnetが2つある! ←重要

ソースコードの作成

この辺参考に作成してください。
Amazon LambdaでScala

build.sbt

今回イベント駆動にはしていないので、依存関係から
aws-lambda-java-events
は除きました。また、SNSを使うので

"com.amazonaws" % "aws-java-sdk-sns" % "1.10.54",

を追加しました。
また、SNS通知メッセージをJSON形式にしたいので
"com.typesafe.play" %% "play-json" % "2.3.10",

を追加しています。

sample

コードはこんな感じです。(ただしサンプル用に作ったので動作未確認)
実行する関数のinputパラメータはjavaのMap型にする必要がある。
CredentialsProviderはEnvironmentVariableCredentialsProviderを指定すればいい感じに権限を取得してくれる。


package qr.test

import com.amazonaws.auth._
import com.amazonaws.regions.{ Region, Regions }
import com.amazonaws.services.lambda.runtime.Context
import com.amazonaws.services.sns._
import com.amazonaws.services.sns.model._

import play.api.libs.json._

case class PublishMsg(
  default: String,
  APNS: String,
  APNS_SANDBOX: String)
case class APNSMsgBody(
  aps: APS,
  title2: String,
  options: String)
case class APS(
  content-available: Int,
  sound: String,
  alert: Alert)
case class Alert(
  title: String,
  body: String)

object Notify {
  def notify(input: java.util.Map[String, Object], context: Context): String = {
    val credential: AWSCredentialsProvider = getCredentials
    val topicArn = "arn:aws:sns:ap-northeast-1:xxxxxxxxxxx:test"
    val m = APNSMsgBody(APS(1, "default", Alert("title", "body")), "title2", "options")
    val APNSStr = Json.toJson(m).toString
    val msg = Json.toJson(PublishMsg("title", APNSStr, APNSStr)).toString
    println("msg:" + msg)
    val publishRequest = new PublishRequest(topicArn, msg)
    publishRequest.setMessageStructure("json")
    getSNSClient.publish(publishRequest).getMessageId
  }
  implicit def convertMsgBody: Writes[APNSMsgBody] = Json.writes[APNSMsgBody]
  implicit def convertAlert: Writes[Alert] = Json.writes[Alert]
  implicit def convertAPS: Writes[APS] = Json.writes[APS]
  implicit def convertPublishMsg: Writes[PublishMsg] = Json.writes[PublishMsg]

def getSNSClient = {
    val cli = new AmazonSNSClient(getCredentials)
    cli.setRegion(Region.getRegion(Regions.AP_NORTHEAST_1))
    cli
  }
  def getCredentials: AWSCredentialsProvider = {
    new EnvironmentVariableCredentialsProvider
  }
}

messageの内容はこんな感じになります。

{
    "default": "title",
    "APNS": "{\"aps\":{\"content-available\":1,\"sound\":\"default\",\"alert\":{\"title\":\"title\",\"body\":\"body\"}},\"title2\":\"title2\",\"options\":\"options\"}",
    "APNS_SANDBOX": "{\"aps\":{\"content-available\":1,\"sound\":\"default\",\"alert\":{\"title\":\"title\",\"body\":\"body\"}},\"title2\":\"title2\",\"options\":\"options\"}"
}

jar作成

activator assemblyでjarファイル作成

Lambdaの設定

「Select blueprint」「Configure triggers」は無視

Configure Function

Nameは適宜
RuntimeにJava8を選択
Code entry typeはzip or jar fileを選択
Function packageからファイルを選択し、upload
Handlerは上記の場合であれば qr.test.Notify::notify
roleはVPCのデフォルトにSNS Publishのみ許可したものを作成して選択。
メモリは大きめにしておいた方がコンパイルが早い。1024以上はあまり恩恵がなさそうに感じた。
コンパイルに10~30秒ほどかかるのでTimeoutはそのくらいで設定
VPCを選び、NATGateway設定済みのサブネットを二つ選択する。
NATGatewayが設定されていないと、SNSのAPIを叩けないのでtimeoutエラーとなるので注意!
http://stackoverflow.com/questions/36167836/java-myhandler-s3-put-client-timeout-in-lambda
セキュリティグループは443か80が全オープンであれば問題ないはず…。(未確認)

確認

確認して問題なさそうなら作成。

テストを実行したら通知される。

SNS Java SDK利用時のエラー


TopicArn (Service: AmazonSNS; Status Code: 400; Error Code: InvalidParameter; Request ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) (AmazonHttpClient.java:1369)

snsClientに対してはRegionの設定が必要なようです。


def getSNSClient = {
    val cli = new AmazonSNSClient(getCredentials)
    cli.setRegion(Region.getRegion(Regions.AP_NORTHEAST_1))
    cli
}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1