FlutterでAWS API GatewayのWebSocket APIを使ってみたい!という方向けの記事になります。
本記事は実装方法に特化して書いていますので、そもそもWebSoketって?という方は参考記事をご参照ください。
前提
- Flutterの環境構築は済んでおり、基礎は知っている
- AWSアカウント作成済み
構成
手順
大まかな手順としては↓になります。
- Lambdaに関数を作成
- APIGatewayでAPIを作成
- Flutter側の実装
Lambdaに関数を作成
関数の作成
Lambdaのコンソールを開き「関数の作成」を選択します。
各種設定を選択。
「一から作成」を選択。
項目名 | 設定内容 |
---|---|
関数名 | 好きな関数名を入力 |
ランタイム | Node.js 16.x |
アーキテクチャ | x86_64 |
(他の項目は特に設定しなくても問題ありません)
「関数の作成」を押すと、関数が作成されます。
各種処理追加
作成した関数を開き、ディレクトリ構成を以下のようにします。
【】→フォルダ名
- 【関数名】
- 【interface】
- connect.js
- disconnect.js
- sendText.js
- index.js
- 【interface】
index.js
const { connect } = require('./interface/connect');
const { sendText } = require('./interface/sendText');
const { disconnect } = require('./interface/disconnect');
exports.handler = async (event, context) => {
// レスポンスデータ
let response;
// イベントタイプ
let routeKey;
//-------------------------------------
//-- eventTypeからIF毎のロジックに振り分け
//-------------------------------------
routeKey = event.requestContext.routeKey;
switch (routeKey){
case "$connect":
//***************************************************
//** 接続
//***************************************************
response = await connect(event, context);
break;
case "sendText":
//***************************************************
//** 文字送信
//***************************************************
response = await sendText(event, context);
break;
case "$disconnect":
//***************************************************
//** 切断
//***************************************************
response = await disconnect(event, context);
break;
}
return response_final;
};
connect.js
exports.connect = async (event, context, callback) => {
// ***************************************************
// ** 接続時の処理を好きに追加
// ***************************************************
// レスポンスデータの生成
let response = {
"statusCode": event.statusCode,
"headers": event.headers,
"body": context.body,
"isBase64Encoded": false
};
return response;
};
disconnect.js
exports.disconnect = async (event, context, callback) => {
// ***************************************************
// ** 切断時の処理を好きに追加
// ***************************************************
// レスポンスデータの生成
let response = {
"statusCode": event.statusCode,
"headers": event.headers,
"body": context.body,
"isBase64Encoded": false
};
return response;
};
sendText.js
sendText
が呼ばれた時に「送信されてきたdataを、送信者にそのまま送信する」ようにしています。
const { ApiGatewayManagementApiClient, PostToConnectionCommand } = require("@aws-sdk/client-apigatewaymanagementapi");
exports.sendText = async (event, context, callback) => {
// ***************************************************
// ** 実装例)sendText実行時の処理
// ***************************************************
// apigateway client インスタンス取得
const domain = event.requestContext.domainName;
const stage = event.requestContext.stage;
const endpoint = `https://${domain}/${stage}`;
const agmClient = new ApiGatewayManagementApiClient({ endpoint: endpoint });
//----------------------------------------------
//-- clientにdata送信
//----------------------------------------------
// clientに送信するデータ
const body = JSON.parse(event.body);
const sendData = {
text : body.data.text
};
const sendParams = {
Data: Buffer.from(JSON.stringify(sendData))
};
// 送信先のconnectionId
sendParams.ConnectionId = event.requestContext.connectionId;
try {
// クライアントに送信
response = await agmClient.send( new PostToConnectionCommand(sendParams));
// 送信成功時の処理
} catch (error) {
// 送信失敗時の処理
}
// レスポンスデータの生成
response = {
"statusCode": event.statusCode,
"headers": event.headers,
"body": context.body,
"isBase64Encoded": false
};
return response;
};
Deploy
「Deploy」ボタンを押します。
これやらないと反映されないので、お忘れなく。
実行ロールの追加
LambdaからAPIGatewayにアクセスできるように、実行ロールを追加します。
編集内容は以下の公式ドキュメントを参照
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-websocket-control-access-iam.html
APIGatewayでAPIを作成
APIの作成
AWS API Gatewayのコンソールに行き「APIの作成」を選択します。
今回作成するのはWebSocket APIなので「WebSocket API」の「構築」を押します。
APIの詳細を指定する
項目名 | 設定内容 |
---|---|
API名 | 好きなAPI名を入力 |
ルート選択式 | 「request.body.action」を入力 |
ルートを追加
-
$connectルートの追加
$disconnectルートの追加
$defaultルートの追加
を押下。 - 「カスタムルートを追加」を押し、入力欄に「sendText」と入力します。
- 「次へ」ボタンを押下。
統合をアタッチする
すべてのルートに対して同じLambda関数を設定します。
どのルートから呼び出されているかはLambda側で判定するため、同じもので問題ありません。
項目名 | 設定内容 |
---|---|
統合タイプ | Lambda |
AWS リージョン | 使用しているリージョン |
Lambda関数 | 呼び出す関数(先ほど作成したもの) |
ステージの追加
項目名 | 設定内容 |
---|---|
ステージ名 | 好きなステージ名を入力 |
確認して作成
Flutter側の実装
パッケージの追加
dependencies:
flutter:
sdk: flutter
# WebSoket
web_socket_channel: ^2.2.0
接続
接続用のインスタンスの作成
// WebSocketインスタンス
WebSocketChannel? _channel;
使用したい画面のライフサイクルメソッドなどで、以下のメソッドを呼びます。
// WebSocket接続開始
void startConnection(){
_channel = IOWebSocketChannel.connect("wss://xxxxxxxxx");
// 切断時の監視
final subscription = _channel?.stream.listen(null);
subscription?.onDone(() {
// WebSocket切断時の処理
});
}
接続先のURLはAPIGatewayで以下の画面の「WebSocket URL」を使用します。
wssから始まるやつです。
サーバーを監視し、変更があれば取得・表示できるようにします。
ここでは受け取ったdataをTextに変換して表示しておきます。
StreamBuilder(
stream: _channel?.stream,
builder: (context, snapshot) {
return Text(snapshot.hasData
? 'response:${snapshot.data}'
: 'response:');
},
切断
切断する時は以下のメソッドを呼ぶだけです。
void disconnect() async {
await _channel?.sink.close();
}
送信
APIGateway WebSocket APIの場合は、ただデータを送るだけでなく、ルートを指定する必要があります。
以下のfunctionを、ボタン押下時などに呼び出してください。
// 文字送信
void sendTextAction() {
Map data = {
// 送信したいAPIのルート名を指定
"action": "sendText",
// 送信するデータ
"data":
{
"text": "文字送ったよ",
}
};
// 送信処理
_channel?.sink.add(jsonEncode(data));
}
まとめ
今回苦戦したのがAWS周りだったので、Flutterはだいぶ省略してしまいました。お許しください。
どなたかの一助となれば幸いです。
参考記事