📱

【Capacitor入門】Webエンジニアでもモバイルアプリを作りたい!

2024/04/30に公開

Webエンジニアのわでぃんです。
個人開発で、Capacitor(キャパシター)を使ってアプリを作り完全に理解した(?)ので紹介します。
Capacitorの記事はちらほら見かけますが、入門系の記事がなかったためまとめています。

この記事を見ることで、Capacitorでできることを知り、最低限の機能のアプリを作ることができます。
実際にReactプロジェクトをモバイルアプリ化し、シミュレータで起動するまでを行います。
*今回は、App Store ConnectやGoogle Play Console、リリース周りは触れません🙅‍♂️

Capacitorとは?

ひとことで言うと、Web技術でモバイルアプリを作るためのライブラリです。
例えば、ReactやVue、AngularなどのJavaScriptのライブラリ・フレームワークを使ったプロジェクトで、Capacitorを導入することで、iOS、Android、Webを横断してアプリを作ることができます。いわゆるクロスプラットフォームと言うやつですね。

なぜこれが可能かというと、Capacitorは「WebView」を使って表示させているからです。
さらに、認証・カメラ・位置情報など、ネイティブ機能にアクセスするためのプラグインが豊富に提供されているので、それらを使うことでネイティブの機能を実装することができます。

実装の仕方はプロジェクトによって異なりますが、iOS、Android、Webの条件分岐をすることで、1つのコードベースで3つのプラットフォームに対応することができます。素晴らしい!!
https://capacitorjs.jp/

余談

Capacitorの公式ドキュメントを見ていると、「Ionic」や「Cordova」などのワードが出てきます。
Ionicとは、ネイティブアプリのようなUIを提供するフレームワークです。PWAアプリなどでよく使われています。IonicチームがCapacitorの開発を行っています。また、CordovaはCapacitorの前身となるライブラリです。

記事を書くまでの経緯

私はフロントエンドを得意とするWebエンジニアです。
作りたいサービス(後述します)があったのですが、それを実現するためにはモバイルアプリにすることが必須でした。しかし、モバイルアプリの知識は全くありません。

そこで、ReactNativeやFlutterを学習することも考えましたが、他に学習したい分野があり、このアプリのためにキャッチアップするのは大変そうだったので断念しました🫠 (React -> ReactNative意外と大変)
そうなるとPWAが残るのですが、これも問題があります。PWAはまだ一般ユーザー(特にiPhone)に馴染みがなく、ダウンロード数が伸びないのではという懸念がありました。PWAはまだ時期尚早な感じがしますね、、、

そこで、Web技術でモバイルアプリを作れないか?と考えたところ、Capacitorが見つかりました。
Capacitorを使用して、実際にリリースまですることができ非常に満足しています。

ターゲット

以下に1つでも該当する人は、この記事を読むメリットがあると思います。

  • 最近聞くようになったCapacitorについてキャッチアップしたい人
  • Webエンジニアだけどモバイルアプリを作りたい人
  • 自社サービス・または受託案件(小・中規模)で、もっとスピーディにMVPを出したい人
  • クロスプラットフォームでWebとモバイルアプリを横断して開発したい人

本記事の流れ

前置きが長くなりましたが、本記事の流れを以下に示します。

ReactでCapacitorを導入して簡単なアプリを作ります。
アプリの中身は、カウントアップするだけのシンプルなものです。というかviteの初期画面をそのまま使います...😇

ドキュメント眺めてても微妙にわかりにくいので、ハンズオン形式で進めていきましょう!

実際、自分が作成したアプリではFirebaseを使用して認証・DBを使っていますが今回は、主にCapacitorのセットアップ周りを重点的に解説しています。
(認証周りなどで詰まったところや、細かいTipsは個人ブログなどでまとめる予定です)

ちなみに今回の記事と同じ内容のリポジトリを作成していますので、そちらも参考にしてください。
https://github.com/wadeen/learn-capacitor

実装編

早速、実装していきましょう!
モバイルアプリを作成するには、いくつか準備が必要です。

前提

モバイルアプリを作るためには以下が必須です。

  • iOS向け
    • 実装時:Xcodeのインストール
    • リリースする場合:Apple Developerの登録。年間99米ドル('24/04/30時点)
  • Android向け
    • 実装時:Android Studioのインストール
    • リリースする場合:Google Play Consoleの登録。登録時のみ25米ドル('24/04/30時点)
    • 近年ハードル爆上がり中...

開発時は、VSCodeなどのエディタでOKです。

本記事の内容までであれば課金は不要です。
Xcodeや、Android Studioのやシミュレータなどを使えば、とりあえず課金しなくてもアプリ自体の作成できるので、作りたいアプリが決まってから課金するでいいと思います。

インストールしていない方はこのタイミングでしてください!

1. Reactプロジェクトの構築

まずは、Reactプロジェクトを作成します。
今回は、Vite + React(TS)を使用しますが、ここは使い慣れているフレームワークを使用してください。
例えば、Reactでファイルベースルーティングがよければ、Next.jsを使ったり、generoutedなどを使うといいでしょう。
余談ですが、Next.jsでは「Static Export」というモードがあり、build時に全てのページを生成(SG)することができます(Node.jsが動かないので一部制限されます)。App Routerでも問題ありません。

ではやっていきましょう!まずは、適当にリポジトリを作ってください。
そこでReact(TS)プロジェクトを構築します。CLIでぽちぽちしてください。

npm create vite@latest

Vite + Reactのローカルサーバーを起動した時の初期画面(カウントアップできるUIがある)

ローカルサーバーを立ち上げて、この画面が立ち上がればOKです。

2. Capacitorの導入

ここからが本題です。
Capacitorを導入していきましょう!

今回は先にReactプロジェクトを作成しているため以下の記事に従って進めます。
https://capacitorjs.com/solution/react

npm install @capacitor/core @capacitor/cli

次に以下のコマンドを実行しますが、nameidは任意の値になります。

npx cap init [name] [id] --Web-dir=build

[name]の部分はアプリ名です。今回は「CountUp」というアプリ名にしましょう。
[id]の部分は、アプリのIDです。この形式は、「com.example.myapp」という形式になります。
example.comというドメインを持っていれば逆ドメイン形式で入力すればいいでしょう。myappの部分はアプリ名が入ります。
ここでは、com.test.countupとします。

npx cap init CountUp com.test.countUp --Web-dir=build

実行して、capacitor.config.tsファイルが生成できればOKです。
このconfigファイルに、アプリの設定などを記述していきます。

WebDirは、buildしたファイルが入っているディレクトリを指定します。
Vite + Reactの場合は、buildではなくdistになります。
Next.jsのStatic Exportでは、outになります。ここは環境に合わせて書き換えてください。

// ...
const config: CapacitorConfig = {
  appId: 'com.test.countup',
  appName: 'CountUp',
  WebDir: 'dist', // build -> dist
};
// ...

ビルドしてみましょう。
Capacitorは、ビルドしたファイルをネイティブプロジェクトにコピーする仕組みになっています。
そのため、先にローカル環境でビルドが必要になります。

npm run build

次に、iOSとAndroidのプラットフォームを追加します。

npm i @capacitor/ios @capacitor/android
npx cap add android
npx cap add ios

実行すると、ルート直下にios/と、android/ディレクトリが生成されます。

これだけで、Capacitorの最低限の設定は完了です🎉
本当にモバイルアプリとして動作するか確認してみましょう。

3. シミュレータで動作確認

下記のコマンドを実行して、iOSのシミュレータを立ち上げます。

npx cap open ios

Xcodeのスクリーンショット。左上に右向きの三角ボタンがある
Xcodeが開いたら、一番上のAppらへんをクリックすると、シミュレータが選択できます。
もし、シミュレータが入っていない場合は、確認したいOSと機種を選択して追加できます。
(Manage Run Destinations... > Simulatorsクリック > 左下の+ボタンを押して機種とOSをインストール)

*iPhoneを持っている場合は、実機で動作確認することも可能です。

Xcodeが立ち上がったら、「▶︎」のRunボタンを押してビルドしてください。

シミュレータが起動して、アプリが表示されれば成功です ✅
iPhoneのシミュレータが起動しており、アプリが開いているgif画像

どうでしょうか、めちゃくちゃ簡単にWeb技術でモバイルアプリが作れました!!
ビルドしてコマンド1つ実行するだけで、Capacitorがいい感じにモバイルアプリを作ってくれます。
あとは、要件に合わせて機能を追加していくだけです。これだけ簡単だと、導入したくなりませんか?(圧)

もちろん、要件に応じて複雑な処理が入っていきます。
ここまでは、公式ドキュメントをなぞっただけですので、ここからはもっと深ぼっていきましょう!!

2回目以降

npx cap add iosなどは最初のみ実行する必要があり、通常は以下のように実行します。

npm run build
npx cap copy ios
npx cap open ios (or) npx cap run ios

先述のように、buildしてコピーして、シミュレータを立ち上げる流れです。

npx cap open iosは、Xcodeが立ち上がります。
npx cap run iosは、シミュレータが直接立ち上がります。

この辺は、package.jsonにscriptを追加しておくといいでしょう。
*キャッシュが残ってしまう場合は、Macだと⌘⇧Kでクリアできます(Product > Clean Build Folder...)。

4. プラグインの導入

さて、Reactプロジェクトをモバイルアプリ化することができました。
次に、ネイティブ機能を使うためのプラグインを導入していきましょう。

Capacitorのプラグインには以下のようなものがあります。

あくまで一部のみ紹介しましたが、他にもたくさんのプラグインがあります。
これらを使うことによって、簡単にネイティブの機能を使うことができます。

試しに、①ネットワークの状況を取得 ②アプリ内ブラウザを開く プラグインを導入してみましょう。

npm install @capacitor/network @capacitor/browser

src/App.tsxの適当な位置に以下のコードを追加します。

src/App.tsx
import { Browser } from '@capacitor/browser';
import { Network } from '@capacitor/network';

// ①ネットワークの状況を取得 -> ネットワーク接続が切れた場合にアラートを表示
  useEffect(() => {
    Network.addListener("networkStatusChange", (status) => {
      if (status.connected) return;
      alert("ネットワークに接続されていません!!");
    });
    return () => Network.removeAllListeners();
  }, []);
// ...

// ②アプリ内ブラウザを開く -> Capacitorの公式ページをアプリ内ブラウザで開く
  <button onClick={async() => await Browser.open({url:"https://capacitorjs.com/"})}>Go To Capacitor docs</button>
// ...

見ていただくとわかる通り、値を渡したりイベントを取得するだけで、ネイティブの機能を使うことができます。
ネイティブの機能を使うと聞くと大変に思えますが、プラグインを使うことで簡単に実装できます。

プラグインを追加した場合は、iOS/Android側にも追加する必要があります。
以下のコマンドを実行することで、ネイティブプロジェクトにもプラグインが追加されます。

npx cap sync

2回目以降
npx cap copy ios

上記でcopyしていましたが、npx cap synccopyを内包しています。
そのため、package.jsonのscriptで、buildsyncを同時に実行すると楽です!

package.json
"scripts": {
// ...
  "build": "tsc && vite build && npx cap sync",
// ...
},

5. プラットフォームごとの分岐処理

プラグインも、豊富で色々できることがわかりました。
最後に、各プラットフォーム(iOS/Android/Web)での切り替え方法や、切り替える事例などを見ていきましょう。

以下のようにすることで、条件分岐をすることができます。
まず、すでにインストール済みの@capacitor/coreからプラットフォームを取得します。
constants.tsなどの定数ファイルに定義しておくと便利です。

src/constants.ts
import { Capacitor } from '@capacitor/core';

export const IS_NATIVE_PLATFORM = Capacitor.isNativePlatform();
export const IS_ANDROID = Capacitor.getPlatform() === 'android';
export const IS_IOS = Capacitor.getPlatform() === 'ios';

これらの条件分岐はどういったところで使うのか見ていきましょう。

例1. Apple認証

先ほど、プラグインの導入のセクションでも紹介した、Apple認証のプラグインを使う場合です。
このプラグインは、iOSのみで使うことができます。

そうすると、Androidユーザーには表示させたくありません。
そこで、IS_IOSのときだけAppleログインボタンを表示させることができます。

{
  IS_IOS && (
    <Button type='button' onClick={(e) => {}}>
      Appleログイン
    </Button>
  );
}

例2. Firebase

Firebaseでは、モバイルとWebでは仕様が異なります。
例えば、Firebase Analyticsでは初期化する際に、Webとネイティブで分岐する必要があります。
READMEを見ていただくとわかると思いますが、Webだけ、両方OKなどがありますね。

// Webで実行するとエラーになるので、ネイティブのみで実行する
if (IS_NATIVE_PLATFORM) {
  FirebaseAnalytics.getAppInstanceId();
}

また、Firebaseの認証も同様です。
通常、lib/client.tsのようなファイルを定義して以下のように書くでしょう。

src/lib/firebase/client.ts
import { getAuth } from 'firebase/auth';
// ...
export const auth = getAuth(app);

しかし、WebブラウザとモバイルアプリのWebViewでは、初期化の仕方が異なります。

src/lib/firebase/client.ts
import {
  getAuth,
  indexedDBLocalPersistence,
  initializeAuth,
} from 'firebase/auth';
// ...
export const auth = (() => {
  if (IS_NATIVE_PLATFORM) {
    return initializeAuth(app, {
      persistence: indexedDBLocalPersistence,
    });
  } else {
    return getAuth(app);
  }
})();

上記のようにすると、Webブラウザなのかモバイルアプリなのかによって、初期化の仕方を変えることができます。

また、サードパーティ製のGoogle認証ライブラリを使う場合なども同様です。
Capacitorでうまくいかない場合は、ドキュメントやIssueを確認してみてください!

src/lib/firebase/client.ts
import { GoogleAuth } from '@codetrix-studio/capacitor-google-auth';
// ...
if (!IS_NATIVE_PLATFORM) {
  GoogleAuth.initialize({
    clientId: process.env.REACT_APP_GOOGLE_CLIENT_ID,
    scopes: ['email'],
    grantOfflineAccess: true,
  });
}

他にも、プッシュ通知や、広告などもプラットフォームごとに分岐することがあります。
アプリの要件に合わせて、事前に設計・ルールを決めておくといいでしょう。

Tips

Capacitorは、だんだん注目されている技術です。
しかし、まだ情報が少ないため色々調査するのが大変でした。

アプリ開発をする上で、参考になった情報や記事などを貼っていきます。

こんなのも役に立ったなどあればコメントください!追加していきます🙋

宣伝

Capacitorを採用して、バーを簡単に検索できる「BarSpot」というアプリをリリースしました🍷
現在は、ベータ版として店舗数・エリアが限られて限られていますが今後アップデートで拡大していく予定です。
行きたいバーを事前に見つけたり、現在地から近いバーを探したり、ユーザー同士がコミュニケーションできるようなアプリです。よければ使ってみてください🍷
https://barspot.app

今後、さまざまな機能追加なども行なっていく予定です!

まとめ

いかがだったでしょうか。
今回は、入門編の記事だったので、どういったことができるかの全体像と、基本的な使い方をご紹介しました。
Webエンジニアが、Capacitorでアプリを作るときに難しいと思うところは、大体XcodeやAndroid Studioの設定などの気がします。
これらは、iOS/Androidエンジニアが出している記事を読むとわかりやすいです。

Capacitorは、スピーディにクロスプラットフォーム対応できる素晴らしいライブラリで、今後もっと伸びていくと思います!
ぜひ、使ってみてください👍

Discussion