【個人開発】Next.jsで作ったアプリにPWA導入してみた

# はじめに
Next.jsを使ったアプリケーションを個人開発しました。
スマートフォンで操作することを前提に開発をしたので、よりアプリケーションの使いやすさを考え、PWA(Progressive Web App)技術を導入しようと考えました。

また、Next.js15とTypescriptを用いたPWA導入がまとまった記事をなかなか見つけられなかったので、今回は備忘録も兼ねてその実装手順を残していこうと思います。

PWA導入をした個人開発アプリは[こちら](https://wan-care.vercel.app/)です。
![wancare_top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1693405/8f0dd794-4305-47aa-891a-7764d7e80c6e.png)

## 環境
- React ver.18.3.1
- Next.js ver.15.3.0
- typescript ver.5.8.3
- macOS Sequonia15.4

## PWA(Propgressive Web App)とは？
一言でいうとWebサイトをネイティブアプリのように利用できる仕組みのことです。

端末にアプリケーションをインストールすることができ、ユーザーからするとネイティブアプリのような操作でアプリ使用ができるようになります。

また、Next.jsは標準機能としてPWAを利用できるようで以下のリファレンスにも詳しく設定解説が記載されています。

端末へのアプリインストール以外にも、プッシュ通知を設定できたり、オフライン使用ができるようにできたりもするみたいです。

https://nextjs.org/docs/app/building-your-application/configuring/progressive-web-apps

:::note warn
今回取り扱う内容としては、`端末へのアプリケーションインストールの設定`のみとなるので、予めご認識お願いします。
:::

## 導入手順
既にNext.jsでアプリケーションを作成されている前提で設定をしていきます。

### 1. Web app Manifestを作成
はじめにWeb app Manifestを作成してPWAに関する設定を記載します。

#### Web app Manifestとは？
Web app Manifestとは、Webアプリケーションに関するメタデータを提供するファイルのこと。
このファイルは主に、PWAを構築する際に使用され、アプリのアイコンや名前、表示モードなどの情報をブラウザに伝える役割を担います。

https://developer.mozilla.org/ja/docs/Web/Progressive_web_apps/Manifest

appディレクトリ内にmanifest.tsファイルを作成します。

```ts: manifest.ts
import type { MetadataRoute } from 'next'
 
export default function manifest(): MetadataRoute.Manifest {
  return {
    name: 'Test Next.js App', //アプリケーション名
    short_name: 'Test Next.js', //アプリケーション名(短縮版)
    description: 'This is a test app', // アプリケーションの説明文
    start_url: '/',  // アプリ起動時に開くパス
    display: 'standalone', // アプリケーションの表示モードを指定する
    background_color: '#ffffff',　// コンテンツ表示されるまでの背景色
    theme_color: '#000000',       // ブラウザのアドレスバーやステータスバーの色
    icons: [　                    // ホーム画面に表示させるicon画像
      {
        src: '/icon-192x192.png',
        sizes: '192x192',
        type: 'image/png',
      },
      {
        src: '/icon-512x512.png',
        sizes: '512x512',
        type: 'image/png',
      },
    ],
  }
}
```
手動で記載をしても良いですし、もしくは以下のようなアプリケーションでファイル作成すると便利です。

https://progressier.com/pwa-manifest-generator

### 2. 画像の設定
ホーム画面のアイコン画像やfaviconの設定をします。
以下のサイトでアイコンに使用したい画像を登録しましょう。

https://realfavicongenerator.net/

画像作成ができたら、zipファイルがダウンロードできるようになります。
以下のように展開ができたら画像の準備は完了です。
![スクリーンショット 2025-04-17 0.20.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1693405/0f6c8e3f-c2da-4828-8df7-d381e12554f3.png)

アプリ内で使用するファイル名を以下のように修正しておきましょう。
(※manifest.tsファイルに記載する名前と、ファイル名が一致していればOKなので任意の名前に変えても大丈夫です）

- favicon.ico →`そのまま使用`
- apple-touch-icon.png→`apple-icon.png`
- web-app-manifest-192x192.png → `icon-192x192.png`
- web-app-manifest-512x512.png → `icon-512x512.png`
- 
### 3. 画像フォルダの移動
`favicon.icon`と`apple-icon.png`はappディレクトリに配置、
`icon-192x192.png`と`icon-512x512.png`はpublicディレクトリに配置します。

以下のような構成になっていればOKです。

```
/(ルートディレクトリ) 
└ public
   └ icon-192x192.png
   └ icon-512x512.png
└ src
   └ app
      └ favicon.ico
      └ apple-icon.png
      └ manifest.js
```

### 4. デプロイをする
私の場合はVercelでデプロイをしているので、変更履歴をpushして反映をさせました。

## 導入確認方法
### Google Chromeの場合
1. Google Chromeでアプリケーションを開き、Chromeの3点リーダーをクリック。
1. 「キャスト、保存、共有」を選択し、「ページをアプリとしてインストール」をクリック。
![スクリーンショット 2025-04-17 0.38.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1693405/9e7d5720-4368-42ec-929c-cd50b494ce44.png)

以下のようにアプリケーションアイコンがデスクトップ上に表示されれば、導入成功です。
![スクリーンショット 2025-04-16 23.02.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1693405/6064d6ca-3d84-4b94-a8c5-d695b15709e0.png)

### iphoneの場合
1. Safariでアプリケーションを開き、画面下部の「共有」をクリック。
2. 「ホーム画面に追加」をクリックして、保存する。

<table>
  <tr>
    <td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1693405/9d86a5a2-79a5-45f5-a7a3-1f949b04420f.jpeg" width="300"></td>
    <td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1693405/37c88cdf-1887-4297-b3ac-80e07a99cdb7.png" width="300"></td>
  </tr>
</table>

上記の設定をすると、アプリのアイコンがホーム画面に追加され、クリックするだけでアプリ起動ができる、かつネイティブアプリのようなUIになります。

## 最後に
今回はアプリケーションをホーム画面にインストールする実装のみをまとめてみました。
今後プッシュ通知機能も追加していきたいので、また導入後にアウトプットしたいと思います。