Flutterでプッシュ通知を実装(FCM x AWS Pinpoint)。デバイストークンをpinpointのエンドポイントへ登録する方法

FCM(Firebase Cloud Messaging)とAWS Pinpointを使ってFlutterアプリにプッシュ通知を送る際問題となるのがpinpointのエンドポイントへデバイストークンを登録する事です。現状Flutter AmplifyライブラリーにはデバイストークンをPinpintのエンドポイントへ登録する機能がありません。ここではそれの解決策を記載いたします。

※認証機能としてCognitoを使用

流れ
1. Fluttter Amplify analiticsでユーザ情報をPinpointへ送信
2. AWS Signature Version 4パッケージの導入
3. 2のパッケージを利用してREST通信を行う



# ユーザ情報をPinpointへ送信
AmplifyライブラリーのAnalisticを使用してユーザ情報をPinpointへ送信。
[Amplify Dev Center](https://docs.amplify.aws/lib/analytics/identifyuser/q/platform/flutter/)

```example_IdentifyUser.dart
//例
Future<void> identify User async{
  final location = AnalyticsUserProfileLocation()
    ..city = 'Tokyo'
    ..region = '<YOUR-REGION>'
    ..country = 'JPN';
  final userProfile = AnalyticsUserProfile();
  userProfile.name = "ユーザID";
  userProfile.location = location;

  await Amplify.Analytics.identifyUser(
    userId: userId,
    userProfile: userProfile,
  );
}"
```

# AWS Signature Version 4パッケージの導入
pubspeck.yamlファイルにaws_signature_v4を追加。
[pub.dev](https://pub.dev/packages/aws_signature_v4)

# AWS HTTP GETメソッドを使用してエンドポイントIDを取得
URLにアプリケーションIDとユーザIDを付与。
結果エンドポイントIDを取得出来る。
[AWS エンドポイントIDを取得](https://docs.aws.amazon.com/pinpoint/latest/apireference/apps-application-id-users-user-id.html)
[Amplify Dev Center](https://docs.amplify.aws/lib/analytics/identifyuser/q/platform/flutter/)
[AWS デバイストークンをエンドポイントへ追加](https://docs.aws.amazon.com/pinpoint/latest/apireference/apps-application-id-endpoints-endpoint-id.html)
```
import 'dart:convert';
import 'package:aws_common/aws_common.dart';
import 'package:aws_signature_v4/aws_signature_v4.dart';

// Create the signer instance with credentials from the environment.
const signer = AWSSigV4Signer(
      credentialsProvider: AWSCredentialsProvider(AWSCredentials(
          "ACCESS_KEY", "SECRET_KEY")),
  );

// Create the signing scope and HTTP request
const region = '<YOUR-REGION>';

final request = AWSHttpRequest.get(
    Uri.https('pinpoint.<YOUR-REGION>.amazonaws.com', '/v1/apps/<application-id>/users/<user-id>'),
    headers: {
      AWSHeaders.target: 'AWSCognitoIdentityProviderService.DescribeUserPool',
      AWSHeaders.contentType: 'application/json',
    },
  );

// Sign and get the HTTP request
final signedRequest = await signer.sign(
  request,
  credentialScope: scope,
);
final resp = await signedRequest.send();
final respBody = await resp.decodeBody();
print(respBody);
```

# 上記で得たエンドポイントへデバイストークンを追加
/v1/apps/application-id/endpoints/endpoint-id
```
final uploadRequest = AWSHttpRequest.put(
    Uri.https('pinpoint.<YOUR-REGION>.amazonaws.com', '/v1/apps/<application-id>/endpoints/endpoint-id'),

    headers: const {
    AWSHeaders.target: 'AWSCognitoIdentityProviderService.DescribeUserPool',
    AWSHeaders.contentType: 'application/json',
  },
  body: json.encode({
    //GCM for ANDROID, APNS for iOS
    "ChannelType": <GCM/APNS>,
    "Address": "<YOUR-DEVICE-TOKEN>",
    "Location": {
        "Region": "<YOUR-REGION>",
        "Country": "JPN"
      },
    "OptOut": "NONE",
    "User": {
    "UserId": "string",
    }
  }).codeUnits,
);

// Sign and send the HTTP request
final signedRequest = await signer.sign(
  request,
  credentialScope: scope,
);
final resp = await signedRequest.send();
final respBody = await resp.decodeBody();
print(respBody);```