初心者がiOSのプッシュ通知を実装できた話（何からしたらいいんだろうを解決）

# はじめに
プッシュ通知の実装にあたり、どこから手をつけていいか全く見当もつかなかった。色々と調べていくと、iOSアプリ側のコード、AWS SNSの設定、DynamoDBの設定など、複数が関わるため非常に複雑だった。なんとか実装できたので記録として残す。ここでは、具体的なコードではなく、実装の手順や流れについて書く。

# 使ったもの
今回は諸事情によりAWS SDKを使えず、API Gateway経由でLambdaを実行し、プッシュ通知を実装した。
* AWS SNS
* AWS Lambda
* AWS DynamoDB
* AWS API Gateway
* Swift

# 前提
https://kahoo.blog/howto-aws-sns-ios-push-notification/

これを参考にしてAWS SNSでプラットフォームアプリケーションの設定は完了している。

# 最終的に作りたいもの
**アプリ内にあるボタンを押した時に関連する人へプッシュ通知を送るというもの**

# プッシュ通知実装までの過程

### 1. 色々と調べた
最初からサーバーと連携させたプッシュ通知を行うことは不可能だということがわかった。あまりにも色々なものが絡みあっている。ステップバイステップで進める必要がありそうだ。いきなり、全部実装しようとしても壁にぶち当たるだけなので以下の手順で順番に進めていくと良さそうだなと思った。

1. サーバーを使わず通知できるかどうかを試す
2. AWS側にデバイストークンを登録できるか試す
3. swiftからデバイストークンをAWSに登録できるか試す
4. 全てのデバイストークンに対してプッシュ通知を行う
5. DynamoDBと連携して該当の人を探し、その人たちにプッシュ通知を行う

この順番に行うと頭がごっちゃにならず、スイスイと進めることができそうだなと思った（実際できた）。

### 2. アプリ内で完結する通知の実装
まずはアプリ内で完結する通知を実装できるか試した。そんなの簡単じゃねとか思ってるかもしれないが、通知の許可の設定だったり、classの設定だったりと色々ごちゃごちゃしていて大変だった。そんな時に見つけたのがこの動画。

https://www.youtube.com/watch?v=dxe86OWc2mI


指定した時間になったら通知が送られるというもの。ただ、この動画をコピペしたけど何も起きなかった（エラーすら起きなかった）。色々考えてみてわかった遭遇した問題は、通知用のコードは別ファイルで作っているんだけど、最初に読まれるファイルで通知用のファイルを読むように書いていなかった。ただこの問題はChat GPTに聞いたらいい感じのコードを出してくレルのですぐ解決すると思う。

これを実装して、ひとまず通知ができるという状態になった。
大進歩！ 0 → 1 ができたのはでかい！

### 3. デバイストークンを追加
手順
* Swift内でデバイストークンを取得する
* 取得したデバイストークンをAWS SNSに登録する

これらを行うためのコードをChat GPTに頼むとできる。

---
具体的な手順
プッシュ通知を送るにはデバイストークンとやらがいるらしいということがわかった。デバイストークンを取得するコードをswiftでかく。
```swift
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
        let token = tokenParts.joined()
        print("デバイストークン: \(token)")
    }
```

この辺りは Chat GPTに適切に頼んだらきちんと書いてくれる。
デバイストークンが取得できたら、AWS SNSに登録する用のコードを書く。今回はAWS SDKが使えなかったので、swift側からデバイストークンをAWS SNSに登録する。API GatewayでLambdaにPostしてデバイストークンを追加するコードを書いた。

そして、AWS SNSのプラットフォームアプリケーションにデバイストークンが追加され有効という文字が出たら完了。

### 4. ボタンが押されたら全てのデバイストークンへ通知
手順
* Lambdaにプッシュ通知を実行するコードを書く
* APi経由でプッシュ通知ができるか確かめる

これらを行うためのコードをChat GPTに頼むとできる。

---
具体的な手順
Lambdaに書くためのコードをChat GPTに頼むと以下のようなコードを出してくれる。
```python
def lambda_handler(event, context):
    sns_client = boto3.client('sns')

    # プッシュ通知を送信するエンドポイントARN
    endpoint_arn = "適当なARNに変える"

    # メッセージ内容
    message = {
        "default": "デフォルトメッセージ",
        "APNS": json.dumps({
            "aps": {
                "alert": "こんにちは！",
                "sound": "default"
            }
        })
    }

    # SNSにプッシュ通知を送信
    try:
        sns_client.publish(
            TargetArn=endpoint_arn,
            MessageStructure='json',
            Message=json.dumps(message)
        )
        
        return {
            'statusCode': 200,
            'body': json.dumps('通知が送信されました')
        }
    except Exception as e:
        return {
            'statusCode': 500,
            'body': json.dumps(f'エラーが発生しました: {str(e)}')
        }
```
ARNとかを適切に設定するとすぐできるから安心。
次にAPI経由でできるか確認する。
Swift内でButtonを作り、Buttonが押されたらAPIを叩きこのLambdaを実行できるようにする。

### 5. 該当する人へ通知
手順
* DynamoDBに判断で使いたい情報とデバイストークンを入れて、Lambdaで該当するかどうか判断するプログラムを書く
* 該当する人にプッシュ通知を行うコードを書く

これらを行うためのコードをChat GPTに頼むとできる。

---
具体的な手順

該当する人かどうか調べるために、DynamoDBにスクリーニングするための情報とデバイストークンを入れて通知ができるようにする。
APIに対して"code"に"A"という文字のポストがあったときにDynamoDBの"code"に"A"がある人のデバイストークンを返すLambdaを書く。Chat GPTに頼めばすぐ書いてくれる。

それらの該当する人に対してプッシュ通知を送るためのコードを書く。先ほどのLambdaのコードを参照してChat GPTに頼めばすぐ書いてくれる。
以下のようなコード書いてくれる。

```python
def notification(name, code):
    try:
        print(f"Fetching team name for team code: {code}")
        response = team_table.query(
            KeyConditionExpression=Key('code').eq(code)
        )
        if 'Items' not in response or not response['Items']:
            return        
        message = {
            "default": f"message",
            "APNS": json.dumps({
                "aps": {
                    "alert": {
                        "title": "message title",
                        "body": "message"
                    },
                    "sound": "default"
                }
            })
        }
        response = device_table.query(
            KeyConditionExpression=Key('code').eq(code)
        )
        for item in response['Items']:
            endpoint_arn = item['EndpointArn']
            send_notification(endpoint_arn, json.dumps(message))
    
    except Exception as e:
        print(f"Error fetching team name or sending notification: {e}")
        pass
```


# 終わりに
いきなりプッシュ通知を行いたくても何をしていいかわからないと思う。これらの手順に分解していけば理解しながら実装できると思う。
実際にChat GPTにプッシュ通知を実装したいと言っても長いコードを送られるだけでどうやって進めていけばいいかわからず挫折しがちだと思う。
少しずつステップバイステップでChat GPTと並走していくことが大事だと思う。これくらいの粒度に下げればChat GPTも該当部分だけのコードを出してくれてどうしたらいいか教えてくれる。急がば回れ！

```
1. アプリ内で通知の実装
2. Swiftでデバイストークンを取得
3. デバイストークンをAWS SNSに登録
4. AWS Lambdaでプッシュ通知を送信
5. API経由でプッシュ通知をテスト
6. DynamoDBで該当者を判断
7. 該当者にプッシュ通知を送信]
```

# 参考文献
この辺の参考しました。読みながらぜひ悩んでください。

https://kahoo.blog/howto-aws-sns-ios-push-notification/

https://www.unitrust.co.jp/6182

https://qiita.com/InletOrder/items/2cbff7664e49fb93bf39

https://qiita.com/Dai_Kentaro/items/5b17272207c66adcdbe4

https://qiita.com/jollyjoester/items/63991657f0d631383c9b

https://qiita.com/hirai-11/items/049118a63ce0f4a545bd