capacitor-react

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Capacitor React

Capacitor React

Develop Capacitor apps with React — project structure, hooks, state management, and React-specific patterns for accessing native device features.
使用React开发Capacitor应用——涵盖项目结构、hooks、状态管理,以及访问原生设备功能的React专属模式。

Prerequisites

前置条件

  1. Capacitor 6, 7, or 8 app with React.
  2. Node.js and npm installed.
  3. React 18 or later.
  4. For iOS: Xcode installed.
  5. For Android: Android Studio installed.
  1. 搭载React的Capacitor 6、7或8应用。
  2. 已安装Node.js和npm。
  3. React 18或更高版本。
  4. 针对iOS:已安装Xcode。
  5. 针对Android:已安装Android Studio。

Agent Behavior

Agent行为

  • Auto-detect before asking. Check the project for
    package.json
    dependencies (
    react
    ,
    react-dom
    ,
    @capacitor/core
    ), platforms (
    android/
    ,
    ios/
    ), build tools (
    vite.config.ts
    ,
    next.config.js
    ,
    webpack.config.js
    ), and TypeScript usage. Only ask the user when something cannot be detected.
  • Guide step-by-step. Walk the user through the process one step at a time. Never present multiple unrelated questions at once.
  • Adapt to the project. Detect the existing code style (functional vs. class components, TypeScript vs. JavaScript, CSS modules vs. styled-components) and generate code that matches.
  • 询问前自动检测 检查项目的
    package.json
    依赖(
    react
    react-dom
    @capacitor/core
    )、平台目录(
    android/
    ios/
    )、构建工具(
    vite.config.ts
    next.config.js
    webpack.config.js
    )以及TypeScript使用情况。仅当无法检测到相关信息时再询问用户。
  • 分步引导 一次只引导用户完成一个步骤,切勿一次性提出多个不相关的问题。
  • 适配项目特性 检测现有代码风格(函数式组件vs类组件、TypeScript vs JavaScript、CSS modules vs styled-components)并生成匹配风格的代码。

Procedures

操作流程

Step 1: Analyze the Project

步骤1:分析项目

Auto-detect the following by reading project files:
  1. Framework variant: Check if this is a plain React app (Vite/CRA), Next.js, or Remix by examining
    package.json
    dependencies and config files (
    vite.config.ts
    ,
    next.config.js
    ,
    remix.config.js
    ).
  2. Capacitor version: Read
    @capacitor/core
    version from
    package.json
    .
  3. React version: Read
    react
    version from
    package.json
    .
  4. TypeScript: Check if
    tsconfig.json
    exists and if
    .tsx
    files are used.
  5. Platforms: Check which directories exist (
    android/
    ,
    ios/
    ).
  6. Capacitor config format: Check if the project uses
    capacitor.config.ts
    or
    capacitor.config.json
    .
  7. State management: Check
    package.json
    for
    redux
    ,
    @reduxjs/toolkit
    ,
    zustand
    ,
    jotai
    ,
    @tanstack/react-query
    , or similar.
  8. Router: Check
    package.json
    for
    react-router-dom
    ,
    @tanstack/react-router
    , or similar.
通过读取项目文件自动检测以下信息:
  1. 框架变体 检查
    package.json
    依赖和配置文件(
    vite.config.ts
    next.config.js
    remix.config.js
    ),确认是纯React应用(Vite/CRA)、Next.js还是Remix。
  2. Capacitor版本 读取
    package.json
    @capacitor/core
    的版本。
  3. React版本 读取
    package.json
    react
    的版本。
  4. TypeScript支持 检查是否存在
    tsconfig.json
    以及是否使用
    .tsx
    文件。
  5. 支持平台 检查存在哪些平台目录(
    android/
    ios/
    )。
  6. Capacitor配置格式 检查项目使用
    capacitor.config.ts
    还是
    capacitor.config.json
  7. 状态管理方案 检查
    package.json
    中是否有
    redux
    @reduxjs/toolkit
    zustand
    jotai
    @tanstack/react-query
    等相关依赖。
  8. 路由方案 检查
    package.json
    中是否有
    react-router-dom
    @tanstack/react-router
    等相关依赖。

Step 2: Project Structure

步骤2:项目结构

A standard Capacitor React project follows this structure:
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
If the project does not follow this structure, adapt all guidance to the project's actual directory layout. Do not restructure the project unless the user explicitly asks.
标准的Capacitor React项目结构如下:
project-root/
├── android/                  # Android原生项目(由Capacitor生成)
├── ios/                      # iOS原生项目(由Capacitor生成)
├── public/
├── src/
│   ├── components/           # 可复用UI组件
│   ├── hooks/                # 自定义React hooks(包括原生功能相关hooks)
│   ├── pages/                # 页面/路由组件
│   ├── services/             # Capacitor插件调用的服务模块
│   ├── App.tsx               # 根组件
│   └── main.tsx              # 入口文件
├── capacitor.config.ts       # Capacitor配置文件
├── package.json
├── tsconfig.json
└── vite.config.ts            # 或其他构建工具配置文件
如果项目不遵循该结构,所有指导需要适配项目实际的目录布局。除非用户明确要求,否则不要重构项目结构。

Step 3: Using Capacitor Plugins in React

步骤3:在React中使用Capacitor插件

Read
references/plugin-usage-patterns.md
for detailed patterns on how to use Capacitor plugins in React components and hooks.
Key principles:
  1. Import plugins directly — Capacitor plugins are imported as ES modules.
  2. Call plugin methods in event handlers or effects — never at the module top level.
  3. Use
    useEffect
    for listeners
    — register and clean up Capacitor event listeners inside
    useEffect
    .
  4. Check platform before calling — use
    Capacitor.isNativePlatform()
    or
    Capacitor.getPlatform()
    to guard platform-specific calls.
阅读
references/plugin-usage-patterns.md
了解在React组件和hooks中使用Capacitor插件的详细模式。
核心原则:
  1. 直接导入插件 —— Capacitor插件以ES模块形式导入。
  2. 在事件处理函数或effects中调用插件方法 —— 不要在模块顶层调用。
  3. 使用
    useEffect
    注册监听器
    —— 在
    useEffect
    内部完成Capacitor事件监听器的注册和清理。
  4. 调用前检查平台 —— 使用
    Capacitor.isNativePlatform()
    Capacitor.getPlatform()
    对平台专属调用做防护。

Step 4: Custom Hooks for Native Features

步骤4:封装原生功能的自定义Hooks

Read
references/custom-hooks.md
for reusable custom hook patterns that wrap Capacitor plugins.
Custom hooks encapsulate native feature access and provide a React-idiomatic API. When the user needs to access a native feature from multiple components, create a custom hook in
src/hooks/
(or wherever the project keeps hooks).
阅读
references/custom-hooks.md
了解封装Capacitor插件的可复用自定义hook模式。
自定义hooks封装了原生功能的访问逻辑,提供符合React使用习惯的API。当用户需要在多个组件中访问某个原生功能时,在
src/hooks/
(或项目存放hooks的目录)中创建对应的自定义hook。

Step 5: State Management with Native Data

步骤5:原生数据的状态管理

When the project uses a state management library, integrate native data as follows:
  1. React Query / TanStack Query: Use query functions that call Capacitor plugins. This works well for data that is fetched from native APIs (e.g., device info, contacts, filesystem reads).
  2. Redux / Zustand / Jotai: Dispatch actions or update atoms from Capacitor plugin callbacks. Keep native API calls in action creators or service modules, not in reducers or stores.
  3. No state library: Use React context or custom hooks with
    useState
    /
    useReducer
    to share native data across components.
Do not recommend adding a state management library unless the user's requirements justify it.
如果项目使用了状态管理库,按以下方式集成原生数据:
  1. React Query / TanStack Query:使用调用Capacitor插件的查询函数,非常适合从原生API获取的数据(例如设备信息、联系人、文件系统读取内容)。
  2. Redux / Zustand / Jotai:在Capacitor插件回调中派发action或更新atom。将原生API调用放在action creator或服务模块中,不要放在reducer或store里。
  3. 无状态管理库:使用React context或结合
    useState
    /
    useReducer
    的自定义hooks在组件间共享原生数据。
除非用户需求确有必要,否则不要推荐新增状态管理库。

Step 6: Navigation and Deep Links

步骤6:导航与深度链接

If the project uses
react-router-dom
or another router:
  1. Deep links: Register a listener for
    appUrlOpen
    events from the
    @capacitor/app
    plugin inside a
    useEffect
    in the root component or a dedicated hook. Navigate programmatically using the router's
    useNavigate()
    hook.
typescript
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]);
};
  1. Back button handling (Android): Register a listener for the
    backButton
    event from the
    @capacitor/app
    plugin to handle Android hardware back button presses.
typescript
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]);
};
如果项目使用
react-router-dom
或其他路由库:
  1. 深度链接:在根组件的
    useEffect
    或专用hook中注册
    @capacitor/app
    插件的
    appUrlOpen
    事件监听器,使用路由的
    useNavigate()
    hook完成程序式跳转。
typescript
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]);
};
  1. 返回按钮处理(Android):注册
    @capacitor/app
    插件的
    backButton
    事件监听器,处理Android硬件返回按钮点击事件。
typescript
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]);
};

Step 7: Platform-Specific Rendering

步骤7:平台专属渲染

Use
Capacitor.getPlatform()
or
Capacitor.isNativePlatform()
to conditionally render components or apply platform-specific behavior:
typescript
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>
  );
};
For reusable platform checks, create a utility or hook:
typescript
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',
  };
};
使用
Capacitor.getPlatform()
Capacitor.isNativePlatform()
条件渲染组件或应用平台专属逻辑:
typescript
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>
  );
};
如果需要复用平台检测逻辑,可以封装成工具函数或hook:
typescript
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',
  };
};

Step 8: Lifecycle and App State

步骤8:生命周期与应用状态

Use the
@capacitor/app
plugin to respond to app lifecycle events in React:
typescript
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]);
};
Use this to refresh data when the app returns to the foreground, pause media, or save state when the app is backgrounded.
使用
@capacitor/app
插件在React中响应应用生命周期事件:
typescript
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]);
};
可使用该hook实现应用回到前台时刷新数据、暂停媒体播放,或应用切后台时保存状态等功能。

Step 9: Build and Run

步骤9:构建与运行

After implementing changes:
bash
npm run build
npx cap sync
npx cap run android
npx cap run ios
For development with live reload:
bash
npx cap run android --livereload --external
npx cap run ios --livereload --external
The
--external
flag makes the dev server accessible from the device/emulator. The
--livereload
flag enables automatic reloads when source files change.
完成代码变更后执行以下命令:
bash
npm run build
npx cap sync
npx cap run android
npx cap run ios
带热重载的开发调试命令:
bash
npx cap run android --livereload --external
npx cap run ios --livereload --external
--external
参数使开发服务器可以被设备/模拟器访问,
--livereload
参数开启源文件变更时自动重载功能。

Error Handling

错误处理

  • Plugin not found at runtime: Ensure
    npx cap sync
    was run after installing a plugin. Verify the plugin is listed in
    package.json
    dependencies.
  • Capacitor is not defined
    : The
    @capacitor/core
    package must be installed. Run
    npm install @capacitor/core
    .
  • Native method fails on web: Guard native-only calls with
    Capacitor.isNativePlatform()
    . Many plugins have web implementations, but some (e.g.,
    @capacitor/camera
    with native UI) only work on iOS/Android.
  • Event listener memory leak: Always return a cleanup function from
    useEffect
    that calls
    remove()
    on the listener handle. Failing to do so causes duplicate listeners on re-renders.
  • Stale closure in event listener: If a Capacitor event listener references React state that changes over time, use a
    useRef
    to hold the latest value, or add the state variable to the
    useEffect
    dependency array and re-register the listener.
  • Live reload not connecting: Ensure the device and development machine are on the same network. Check that the
    --external
    flag is used with
    npx cap run
    . Verify no firewall is blocking the dev server port.
  • Build works on web but fails on native: Check for browser-only APIs (
    window.localStorage
    ,
    navigator.geolocation
    ) used without Capacitor alternatives. Use Capacitor plugins (
    @capacitor/preferences
    ,
    @capacitor/geolocation
    ) instead.
  • React strict mode double-mounting: In development, React 18 strict mode mounts components twice. This can cause duplicate Capacitor event listeners. Ensure cleanup functions properly remove listeners — the double-mount behavior validates that cleanup works correctly.
  • 运行时提示插件未找到:确保安装插件后执行了
    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严格模式下组件重复挂载:开发环境下React 18严格模式会将组件挂载两次,可能导致Capacitor事件监听器重复注册,需确保清理函数能正确移除监听器——重复挂载的行为正是为了验证清理逻辑是否正常工作。

Related Skills

相关技能

  • ionic-react
    — Ionic Framework-specific React patterns (IonReactRouter, lifecycle hooks, overlay hooks) for apps using
    @ionic/react
    .
  • capacitor-angular
    — Angular-specific patterns and best practices for Capacitor app development.
  • capacitor-app-upgrades
    — Upgrade a Capacitor app to a newer major version.
  • capacitor-plugins
    — Install, configure, and use Capacitor plugins from official and community sources.
  • capacitor-push-notifications
    — Set up push notifications with Firebase Cloud Messaging in a Capacitor app.
  • ionic-react
    :针对使用
    @ionic/react
    的应用,提供Ionic Framework专属的React模式(IonReactRouter、生命周期hooks、弹窗hooks)。
  • capacitor-angular
    :Capacitor应用开发的Angular专属模式与最佳实践。
  • capacitor-app-upgrades
    :将Capacitor应用升级到新的主版本。
  • capacitor-plugins
    :安装、配置和使用官方及社区提供的Capacitor插件。
  • capacitor-push-notifications
    :在Capacitor应用中配置Firebase Cloud Messaging实现推送通知。