プッシュ通知の実装 その①【flutter × firebase cloud functions × typescript】

functionsの設定〜flutter側でのFCMトークンの取得、プッシュ通知を実際に送信するまでをまとめていきます。
幾多と類似記事は出ていますが、自分にとっての備忘録の位置付けなので、細かいことは気にしません🙆‍♂️笑

なお今回は、functionsの初期設定〜サンプル関数のデプロイまで。

# 目次
・プロジェクトにfunctionsを導入
・ローカルでサンプル関数を立ち上げる
・firebaseにサンプル関数をデプロイする
・最後に

# 前提条件
・firebaseにプロジェクトが登録されている
・firebaseの課金プランを「Blaze（従量課金）」に変更している
・functionsはtypescriptで実装

# プロジェクトにfunctionsを導入
まずはfirebseを導入して初期設定を行なっていきます💪
functions用のリポジトリを作成して、firebaseをインストールしましょう！

```
npm install --save firebase
```

続いて、firebase-toolsをインストール。
```
npm install --save firebsae-tools
```

上記２点をインストールしたら、一旦firebaseにログインしておきます！
```
firebase login
```

続いて、プロジェクトを初期化します。
何点か質問されるので、ご自身の環境に合わせて回答してください🙆‍♂️
以下は例です！

```
firebase init

・Which Firebase features do you want to set up for this directory? Press Space to select features, then Enter to confirm your choices. 
→ Functions: Configure a Cloud Functions directory and its files

・Please select an option: (Use arrow keys)
→ Use an existing project 

・Select a default Firebase project for this directory: 
→ firebaseに登録しているアプリを選択

・What language would you like to use to write Cloud Functions? 
→ typescript

・Do you want to use ESLint to catch probable bugs and enforce style?
→ 　n

・Do you want to install dependencies with npm now?
n
　
Firebase initialization complete!
```

Firebase initialization complete!が表示されたら初期化はOKです🙆‍♂️


# ローカルでサンプル関数を立ち上げる

初期設定が終わったので、```src/index.ts```に記述されているサンプル関数をローカルで立ち上げてみます。

まずは、helloWorld関数のコメントアウトを外してください。
```index.ts
import * as functions from "firebase-functions";

// // Start writing Firebase Functions
// // https://firebase.google.com/docs/functions/typescript
//
export const helloWorld = functions.https.onRequest((request, response) => {
  functions.logger.info("Hello logs!", {structuredData: true});
  response.send("Hello from Firebase!");
});
```

※もし```import * as functions from "firebase-functions";```の読み込みに失敗していたら、```npm install```してみてください。

そして、functionsディレクトリに移動してからローカル環境を立ち上げます。
```
npm run serve
```

そうすると以下のようにローカルホストが立ち上がります。
```
> functions@ serve /Users/<ユーザー名>/projects/sample_functions/functions
> npm run build && firebase emulators:start --only functions


> functions@ build /Users/<ユーザー名>/projects/sample_functions/functions
> tsc

i  emulators: Starting emulators: functions
⚠  functions: The following emulators are not running, calls to these services from the Functions emulator will affect production: auth, firestore, database, hosting, pubsub, storage
⚠  Your requested "node" version "14" doesn't match your global version "12"
i  ui: Emulator UI logging to ui-debug.log
i  functions: Watching "/Users/<ユーザー名>/projects/sample_functions/functions" for Cloud Functions...
✔  functions[us-central1-helloWorld]: http function initialized (http://localhost:5001/<プロジェクト名>/us-central1/helloWorld).

┌─────────────────────────────────────────────────────────────┐
│ ✔  All emulators ready! It is now safe to connect your app. │
│ i  View Emulator UI at http://localhost:4000                │
└─────────────────────────────────────────────────────────────┘

┌───────────┬────────────────┬─────────────────────────────────┐
│ Emulator  │ Host:Port      │ View in Emulator UI             │
├───────────┼────────────────┼─────────────────────────────────┤
│ Functions │ localhost:5001 │ http://localhost:4000/functions │
└───────────┴────────────────┴─────────────────────────────────┘
  Emulator Hub running at localhost:4400
  Other reserved ports: 4500

Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.
 
^C 
i  emulators: Received SIGINT (Ctrl-C) for the first time. Starting a clean shutdown.
i  emulators: Please wait for a clean shutdown or send the SIGINT (Ctrl-C) signal again to stop right now.
i  emulators: Shutting down emulators.
i  ui: Stopping Emulator UI
⚠  Emulator UI has exited upon receiving signal: SIGINT
i  functions: Stopping Functions Emulator
i  hub: Stopping emulator hub
i  logging: Stopping Logging Emulator
```

※このとき、typescript系のエラーが出た場合は、typescriptのバージョンが足りない可能性があります。
実際に僕もグローバルにインストールしていたバージョンだと足りなかったので、ローカルにtypescript@4.3.1をインストールしました。

では、実際にURLを叩いてみましょう！
http://localhost:5001/<プロジェクト名>/us-central1/helloWorld

![スクリーンショット 2022-11-10 23.20.12（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587091/d9e2a706-e9e8-4e9a-45e9-f97e6b06d011.png)
これが表示されていれば、サンプル関数のテストはバッチリです👍

# firebaseにサンプル関数をデプロイする
では、この記事の最終目的であるデプロイ作業を行います。

先ほどと同じくfunctionsディレクトリで以下のコマンドを叩きます。
```
npm run deploy
```
すると、下記のようにログが吐かれると思います。
```
npm run deploy

> functions@ deploy /Users/<ユーザー名>/projects/sample_functions/functions
> firebase deploy --only functions


=== Deploying to '<プロジェクト名>'...

i  deploying functions
Running command: npm --prefix "$RESOURCE_DIR" run build

> functions@ build /Users/<ユーザー名>/projects/sample_functions/functions
> tsc

✔  functions: Finished running predeploy script.
⚠  functions: package.json indicates an outdated version of firebase-functions.
Please upgrade using npm install --save firebase-functions@latest in your functions directory.
⚠  functions: Please note that there will be breaking changes when you upgrade.
i  functions: ensuring required API cloudfunctions.googleapis.com is enabled...
i  functions: ensuring required API cloudbuild.googleapis.com is enabled...
✔  functions: required API cloudbuild.googleapis.com is enabled
✔  functions: required API cloudfunctions.googleapis.com is enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (28.9 KB) for uploading
✔  functions: functions folder uploaded successfully

...省略

? Would you like to proceed with deletion? Selecting no will continue the rest of the deployments. Yes
i  functions: creating Node.js 14 function helloWorld(us-central1)...
✔  functions[helloWorld(us-central1)]: Successful create operation. 
i  functions: deleting function dynamicOGTag(us-central1)...
i  functions: deleting function server(us-central1)...
✔  functions[server(us-central1)]: Successful delete operation. 
✔  functions[dynamicOGTag(us-central1)]: Successful delete operation. 
i  functions: cleaning up build files...
Function URL (helloWorld(us-central1)): https://us-central1-<プロジェクト名>.cloudfunctions.net/helloWorld

✔  Deploy complete!
```
✔  Deploy complete!が表示されればデプロイ成功です！

firebaseのfunctionsを見てみてください、先ほどデプロイしたfunctionsが追加され、URLが発行されているはずです。

発行されているURLを叩き、Hello from Firebase!が表示されていれば、サンプル関数のデプロイ成功です！

# 最後に
今回はサンプル関数のデプロイまででしたので、次回は実際にflutter側の設定を行なって、Androidにプッシュ通知を送るところまでの記事を出したいと思います。

Cloud Schedulerを使った定期配信も利用しているので、その辺りも別途で記事出したいところ。

初歩的な内容にはなりますが、今後も備忘録ついでに色々発信していきたいと思います！