capacitor-react について
ReactでCapacitorアプリを開発するためのスキルです。プロジェクトの分析やネイティブ機能の統合に加え、フック、状態管理、ルーティング、ライフサイクルの実装方法を案内します。
主な機能
- 01プロジェクト設定の自動検出
- 02ReactでのCapacitorプラグイン利用
- 03ネイティブ機能をカスタムフック化
- 04ディープリンクとライフサイクルの処理
- 05プラットフォーム別の描画と呼び出し
活用シーン
- 01既存のReactアプリへのCapacitor導入
- 02コンポーネントからの安全なネイティブプラグイン利用
- 03アプリ復帰やAndroidの戻るボタンへの対応
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ capawesome-team/ skills --skill capacitor-reactインストール後、Claude Code で/capacitor-reactを入力して読み込まれたか確認します。
同梱ファイルreferences/custom-hooks.mdreferences/plugin-usage-patterns.md
詳細
Capacitor React
React で Capacitor アプリを開発するための、プロジェクト構成、フック、状態管理、ネイティブデバイス機能にアクセスする React 固有のパターンです。
前提条件
- React を使用する Capacitor 6、7、または 8 のアプリ。
- Node.js と npm がインストールされていること。
- React 18 以降。
- iOS の場合:Xcode がインストールされていること。
- Android の場合:Android Studio がインストールされていること。
エージェントの動作
- 質問する前に自動検出します。 プロジェクトの
package.jsonにある依存関係(react、react-dom、@capacitor/core)、プラットフォーム(android/、ios/)、ビルドツール(vite.config.ts、next.config.js、webpack.config.js)、TypeScript の使用状況を確認します。検出できない場合にのみユーザーに質問してください。 - 手順を追って案内します。 一度に 1 つずつ、ユーザーに手順を説明します。関連のない複数の質問を一度に提示しないでください。
- プロジェクトに合わせます。 既存のコードスタイル(関数コンポーネントかクラスコンポーネントか、TypeScript か JavaScript か、CSS Modules か styled-components か)を検出し、それに合ったコードを生成します。
手順
ステップ 1:プロジェクトを分析する
プロジェクトファイルを読み取り、次の項目を自動検出します。
- フレームワークの種類:
package.jsonの依存関係と設定ファイル(vite.config.ts、next.config.js、remix.config.js)を調べて、通常の React アプリ(Vite/CRA)、Next.js、Remix のいずれかを確認します。 - Capacitor のバージョン:
package.jsonから@capacitor/coreのバージョンを読み取ります。 - React のバージョン:
package.jsonからreactのバージョンを読み取ります。 - TypeScript:
tsconfig.jsonが存在するか、.tsxファイルが使用されているかを確認します。 - プラットフォーム:どのディレクトリ(
android/、ios/)が存在するかを確認します。 - Capacitor の設定形式:プロジェクトが
capacitor.config.tsとcapacitor.config.jsonのどちらを使用しているかを確認します。 - 状態管理:
package.jsonでredux、@reduxjs/toolkit、zustand、jotai、@tanstack/react-queryなどが使用されているかを確認します。 - ルーター:
package.jsonでreact-router-dom、@tanstack/react-routerなどが使用されているかを確認します。
ステップ 2:プロジェクト構成
標準的な Capacitor React プロジェクトは、次の構成に従います。
project-root/
├── android/ # Android native project (generated by Capacitor)
├── ios/ # iOS native project (generated by Capacitor)
├── public/
├── src/
│ ├── components/ # Reusable UI components
│ ├── hooks/ # Custom React hooks (including native feature hooks)
│ ├── pages/ # Page/route components
│ ├── services/ # Service modules for Capacitor plugin calls
│ ├── App.tsx # Root component
│ └── main.tsx # Entry point
├── capacitor.config.ts # Capacitor configuration
├── package.json
├── tsconfig.json
└── vite.config.ts # Or other bundler config
プロジェクトがこの構成に従っていない場合は、実際のディレクトリ構成に合わせてすべての案内を調整します。ユーザーから明示的に依頼されない限り、プロジェクトを再構成しないでください。
ステップ 3:React で Capacitor プラグインを使用する
React コンポーネントやフックで Capacitor プラグインを使用する詳細なパターンについては、references/plugin-usage-patterns.md を読んでください。
主な原則:
- プラグインを直接インポートする — Capacitor プラグインは ES モジュールとしてインポートします。
- イベントハンドラーまたはエフェクト内でプラグインのメソッドを呼び出す — モジュールのトップレベルでは呼び出さないでください。
- リスナーには
useEffectを使用する —useEffect内で Capacitor のイベントリスナーを登録し、クリーンアップします。 - 呼び出す前にプラットフォームを確認する — プラットフォーム固有の呼び出しを保護するには、
Capacitor.isNativePlatform()またはCapacitor.getPlatform()を使用します。
ステップ 4:ネイティブ機能用のカスタムフック
Capacitor プラグインをラップする再利用可能なカスタムフックのパターンについては、references/custom-hooks.md を読んでください。
カスタムフックはネイティブ機能へのアクセスをカプセル化し、React の慣習に沿った API を提供します。ユーザーが複数のコンポーネントからネイティブ機能にアクセスする必要がある場合は、src/hooks/(またはプロジェクトでフックを管理している場所)にカスタムフックを作成してください。
ステップ 5:ネイティブデータを使った状態管理
プロジェクトで状態管理ライブラリを使用している場合は、次のようにネイティブデータを統合します。
- React Query / TanStack Query:Capacitor プラグインを呼び出すクエリ関数を使用します。これは、ネイティブ API から取得するデータ(デバイス情報、連絡先、ファイルシステムの読み取りなど)に適しています。
- Redux / Zustand / Jotai:Capacitor プラグインのコールバックからアクションをディスパッチするか、アトムを更新します。ネイティブ API の呼び出しはアクションクリエーターまたはサービスモジュールに置き、リデューサーやストアには置かないでください。
- 状態管理ライブラリを使用していない場合:React コンテキスト、または
useState/useReducerを使ったカスタムフックで、コンポーネント間のネイティブデータ共有を行います。
ユーザーの要件で必要とされない限り、状態管理ライブラリの追加を推奨しないでください。
ステップ 6:ナビゲーションとディープリンク
プロジェクトで react-router-dom や別のルーターを使用している場合:
- ディープリンク:ルートコンポーネント内の
useEffect、または専用のフックで、@capacitor/appプラグインのappUrlOpenイベントを監視するリスナーを登録します。ルーターのuseNavigate()フックを使ってプログラムから遷移します。
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { App, URLOpenListenerEvent } from '@capacitor/app';
const useDeepLinks = () => {
const navigate = useNavigate();
useEffect(() => {
const listener = App.addListener('appUrlOpen', (event: URLOpenListenerEvent) => {
const path = new URL(event.url).pathname;
navigate(path);
});
return () => {
listener.then(handle => handle.remove());
};
}, [navigate]);
};
- 戻るボタンの処理(Android):Android のハードウェア戻るボタンの押下を処理するため、
@capacitor/appプラグインのbackButtonイベントを監視するリスナーを登録します。
import { useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { App } from '@capacitor/app';
const useBackButton = () => {
const navigate = useNavigate();
const location = useLocation();
useEffect(() => {
const listener = App.addListener('backButton', ({ canGoBack }) => {
if (canGoBack) {
navigate(-1);
} else {
App.exitApp();
}
});
return () => {
listener.then(handle => handle.remove());
};
}, [navigate, location]);
};
ステップ 7:プラットフォーム固有のレンダリング
Capacitor.getPlatform() または Capacitor.isNativePlatform() を使用して、コンポーネントのレンダリングやプラットフォーム固有の動作を条件分岐します。
import { Capacitor } from '@capacitor/core';
const MyComponent: React.FC = () => {
const platform = Capacitor.getPlatform(); // 'ios' | 'android' | 'web'
const isNative = Capacitor.isNativePlatform();
return (
<div>
{platform === 'ios' && <IOSSpecificComponent />}
{platform === 'android' && <AndroidSpecificComponent />}
{!isNative && <WebFallbackComponent />}
</div>
);
};
プラットフォームの判定を再利用する場合は、ユーティリティまたはフックを作成します。
import { Capacitor } from '@capacitor/core';
export const usePlatform = () => {
return {
platform: Capacitor.getPlatform(),
isNative: Capacitor.isNativePlatform(),
isIOS: Capacitor.getPlatform() === 'ios',
isAndroid: Capacitor.getPlatform() === 'android',
isWeb: Capacitor.getPlatform() === 'web',
};
};
ステップ 8:ライフサイクルとアプリの状態
@capacitor/app プラグインを使用して、React でアプリのライフサイクルイベントに対応します。
import { useEffect } from 'react';
import { App } from '@capacitor/app';
const useAppState = (onResume?: () => void, onPause?: () => void) => {
useEffect(() => {
const resumeListener = App.addListener('resume', () => {
onResume?.();
});
const pauseListener = App.addListener('pause', () => {
onPause?.();
});
return () => {
resumeListener.then(handle => handle.remove());
pauseListener.then(handle => handle.remove());
};
}, [onResume, onPause]);
};
これを使って、アプリがフォアグラウンドに戻ったときにデータを更新したり、メディアを一時停止したり、アプリがバックグラウンドに移行するときに状態を保存したりできます。
ステップ 9:ビルドと実行
変更を実装した後:
npm run build
npx cap sync
npx cap run android
npx cap run ios
ライブリロードを使って開発する場合:
npx cap run android --livereload --external
npx cap run ios --livereload --external
--external フラグを指定すると、デバイスまたはエミュレーターから開発サーバーにアクセスできるようになります。--livereload フラグを指定すると、ソースファイルの変更時に自動で再読み込みされます。
エラー処理
- 実行時にプラグインが見つからない:プラグインのインストール後に
npx cap syncを実行したことを確認します。プラグインがpackage.jsonの依存関係に記載されていることを確認します。 Capacitor is not defined:@capacitor/coreパッケージをインストールする必要があります。npm install @capacitor/coreを実行します。- ネイティブメソッドが Web で失敗する:ネイティブ専用の呼び出しは
Capacitor.isNativePlatform()でガードします。多くのプラグインには Web 用の実装がありますが、一部(例:ネイティブ UI を使う@capacitor/camera)は iOS/Android でのみ動作します。 - イベントリスナーによるメモリリーク:必ず
useEffectからクリーンアップ関数を返し、その中でリスナーハンドルのremove()を呼び出します。これを怠ると、再レンダリングのたびにリスナーが重複して登録されます。 - イベントリスナー内の古いクロージャー:Capacitor のイベントリスナーが時間とともに変化する React の状態を参照する場合は、
useRefを使って最新の値を保持するか、状態変数をuseEffectの依存配列に追加してリスナーを登録し直します。 - ライブリロードが接続されない:デバイスと開発マシンが同じネットワーク上にあることを確認します。
npx cap runで--externalフラグが使われていることを確認します。ファイアウォールが開発サーバーのポートをブロックしていないか確認します。 - Web ではビルドできるがネイティブでは失敗する:Capacitor の代替手段を使わずに、ブラウザー専用 API(
window.localStorage、navigator.geolocation)を使用していないか確認します。代わりに Capacitor プラグイン(@capacitor/preferences、@capacitor/geolocation)を使用します。 - React の Strict Mode による二重マウント:開発環境では、React 18 の Strict Mode によってコンポーネントが 2 回マウントされます。これにより、Capacitor のイベントリスナーが重複することがあります。クリーンアップ関数でリスナーが正しく削除されることを確認してください。二重マウントの動作によって、クリーンアップが正しく機能するか検証できます。
関連スキル
ionic-react—@ionic/reactを使うアプリ向けの Ionic Framework 固有の React パターン(IonReactRouter、ライフサイクルフック、オーバーレイフック)。capacitor-angular— Capacitor アプリ開発における Angular 固有のパターンとベストプラクティス。capacitor-app-upgrades— Capacitor アプリを新しいメジャーバージョンにアップグレードします。capacitor-plugins— 公式およびコミュニティのソースから Capacitor プラグインをインストール、設定、使用します。capacitor-push-notifications— Capacitor アプリで Firebase Cloud Messaging を使ったプッシュ通知を設定します。