capacitor-react
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCapacitor 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
前置条件
- Capacitor 6, 7, or 8 app with React.
- Node.js and npm installed.
- React 18 or later.
- For iOS: Xcode installed.
- For Android: Android Studio installed.
- 搭载React的Capacitor 6、7或8应用。
- 已安装Node.js和npm。
- React 18或更高版本。
- 针对iOS:已安装Xcode。
- 针对Android:已安装Android Studio。
Agent Behavior
Agent行为
- Auto-detect before asking. Check the project for dependencies (
package.json,react,react-dom), platforms (@capacitor/core,android/), build tools (ios/,vite.config.ts,next.config.js), and TypeScript usage. Only ask the user when something cannot be detected.webpack.config.js - 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)以及TypeScript使用情况。仅当无法检测到相关信息时再询问用户。webpack.config.js - 分步引导 一次只引导用户完成一个步骤,切勿一次性提出多个不相关的问题。
- 适配项目特性 检测现有代码风格(函数式组件vs类组件、TypeScript vs JavaScript、CSS modules vs styled-components)并生成匹配风格的代码。
Procedures
操作流程
Step 1: Analyze the Project
步骤1:分析项目
Auto-detect the following by reading project files:
- Framework variant: Check if this is a plain React app (Vite/CRA), Next.js, or Remix by examining dependencies and config files (
package.json,vite.config.ts,next.config.js).remix.config.js - Capacitor version: Read version from
@capacitor/core.package.json - React version: Read version from
react.package.json - TypeScript: Check if exists and if
tsconfig.jsonfiles are used..tsx - Platforms: Check which directories exist (,
android/).ios/ - Capacitor config format: Check if the project uses or
capacitor.config.ts.capacitor.config.json - State management: Check for
package.json,redux,@reduxjs/toolkit,zustand,jotai, or similar.@tanstack/react-query - Router: Check for
package.json,react-router-dom, or similar.@tanstack/react-router
通过读取项目文件自动检测以下信息:
- 框架变体 检查依赖和配置文件(
package.json、vite.config.ts、next.config.js),确认是纯React应用(Vite/CRA)、Next.js还是Remix。remix.config.js - 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
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 configIf 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 for detailed patterns on how to use Capacitor plugins in React components and hooks.
references/plugin-usage-patterns.mdKey principles:
- Import plugins directly — Capacitor plugins are imported as ES modules.
- Call plugin methods in event handlers or effects — never at the module top level.
- Use for listeners — register and clean up Capacitor event listeners inside
useEffect.useEffect - Check platform before calling — use or
Capacitor.isNativePlatform()to guard platform-specific calls.Capacitor.getPlatform()
阅读了解在React组件和hooks中使用Capacitor插件的详细模式。
references/plugin-usage-patterns.md核心原则:
- 直接导入插件 —— Capacitor插件以ES模块形式导入。
- 在事件处理函数或effects中调用插件方法 —— 不要在模块顶层调用。
- 使用注册监听器 —— 在
useEffect内部完成Capacitor事件监听器的注册和清理。useEffect - 调用前检查平台 —— 使用或
Capacitor.isNativePlatform()对平台专属调用做防护。Capacitor.getPlatform()
Step 4: Custom Hooks for Native Features
步骤4:封装原生功能的自定义Hooks
Read for reusable custom hook patterns that wrap Capacitor plugins.
references/custom-hooks.mdCustom 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 (or wherever the project keeps hooks).
src/hooks/阅读了解封装Capacitor插件的可复用自定义hook模式。
references/custom-hooks.md自定义hooks封装了原生功能的访问逻辑,提供符合React使用习惯的API。当用户需要在多个组件中访问某个原生功能时,在(或项目存放hooks的目录)中创建对应的自定义hook。
src/hooks/Step 5: State Management with Native Data
步骤5:原生数据的状态管理
When the project uses a state management library, integrate native data as follows:
- 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).
- 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.
- No state library: Use React context or custom hooks with /
useStateto share native data across components.useReducer
Do not recommend adding a state management library unless the user's requirements justify it.
如果项目使用了状态管理库,按以下方式集成原生数据:
- React Query / TanStack Query:使用调用Capacitor插件的查询函数,非常适合从原生API获取的数据(例如设备信息、联系人、文件系统读取内容)。
- Redux / Zustand / Jotai:在Capacitor插件回调中派发action或更新atom。将原生API调用放在action creator或服务模块中,不要放在reducer或store里。
- 无状态管理库:使用React context或结合/
useState的自定义hooks在组件间共享原生数据。useReducer
除非用户需求确有必要,否则不要推荐新增状态管理库。
Step 6: Navigation and Deep Links
步骤6:导航与深度链接
If the project uses or another router:
react-router-dom- Deep links: Register a listener for events from the
appUrlOpenplugin inside a@capacitor/appin the root component or a dedicated hook. Navigate programmatically using the router'suseEffecthook.useNavigate()
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]);
};- Back button handling (Android): Register a listener for the event from the
backButtonplugin to handle Android hardware back button presses.@capacitor/app
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- 深度链接:在根组件的或专用hook中注册
useEffect插件的@capacitor/app事件监听器,使用路由的appUrlOpenhook完成程序式跳转。useNavigate()
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]);
};- 返回按钮处理(Android):注册插件的
@capacitor/app事件监听器,处理Android硬件返回按钮点击事件。backButton
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 or to conditionally render components or apply platform-specific behavior:
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>
);
};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 plugin to respond to app lifecycle events in React:
@capacitor/apptypescript
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.
使用插件在React中响应应用生命周期事件:
@capacitor/apptypescript
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 iosFor development with live reload:
bash
npx cap run android --livereload --external
npx cap run ios --livereload --externalThe flag makes the dev server accessible from the device/emulator. The flag enables automatic reloads when source files change.
--external--livereload完成代码变更后执行以下命令:
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--livereloadError Handling
错误处理
- Plugin not found at runtime: Ensure was run after installing a plugin. Verify the plugin is listed in
npx cap syncdependencies.package.json - : The
Capacitor is not definedpackage must be installed. Run@capacitor/core.npm install @capacitor/core - Native method fails on web: Guard native-only calls with . Many plugins have web implementations, but some (e.g.,
Capacitor.isNativePlatform()with native UI) only work on iOS/Android.@capacitor/camera - Event listener memory leak: Always return a cleanup function from that calls
useEffecton the listener handle. Failing to do so causes duplicate listeners on re-renders.remove() - Stale closure in event listener: If a Capacitor event listener references React state that changes over time, use a to hold the latest value, or add the state variable to the
useRefdependency array and re-register the listener.useEffect - Live reload not connecting: Ensure the device and development machine are on the same network. Check that the flag is used with
--external. Verify no firewall is blocking the dev server port.npx cap run - Build works on web but fails on native: Check for browser-only APIs (,
window.localStorage) used without Capacitor alternatives. Use Capacitor plugins (navigator.geolocation,@capacitor/preferences) instead.@capacitor/geolocation - 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端运行失败:使用对仅原生可用的调用做防护。很多插件提供了Web实现,但部分插件(例如使用原生UI的
Capacitor.isNativePlatform())仅能在iOS/Android上运行。@capacitor/camera - 事件监听器内存泄漏:始终在的清理函数中调用监听器实例的
useEffect方法,否则组件重渲染时会产生重复的监听器。remove() - 事件监听器中的闭包过时:如果Capacitor事件监听器引用了会随时间变化的React状态,使用保存最新值,或将状态变量加入
useRef依赖数组并重新注册监听器。useEffect - 热重载无法连接:确保设备和开发机器在同一网络下,检查命令是否添加了
npx cap run参数,确认没有防火墙拦截开发服务器端口。--external - Web端构建正常但原生端构建失败:检查是否使用了没有Capacitor替代方案的浏览器专属API(、
window.localStorage),改用对应的Capacitor插件(navigator.geolocation、@capacitor/preferences)。@capacitor/geolocation - React严格模式下组件重复挂载:开发环境下React 18严格模式会将组件挂载两次,可能导致Capacitor事件监听器重复注册,需确保清理函数能正确移除监听器——重复挂载的行为正是为了验证清理逻辑是否正常工作。
Related Skills
相关技能
- — Ionic Framework-specific React patterns (IonReactRouter, lifecycle hooks, overlay hooks) for apps using
ionic-react.@ionic/react - — Angular-specific patterns and best practices for Capacitor app development.
capacitor-angular - — Upgrade a Capacitor app to a newer major version.
capacitor-app-upgrades - — Install, configure, and use Capacitor plugins from official and community sources.
capacitor-plugins - — Set up push notifications with Firebase Cloud Messaging in a Capacitor app.
capacitor-push-notifications
- :针对使用
ionic-react的应用,提供Ionic Framework专属的React模式(IonReactRouter、生命周期hooks、弹窗hooks)。@ionic/react - :Capacitor应用开发的Angular专属模式与最佳实践。
capacitor-angular - :将Capacitor应用升级到新的主版本。
capacitor-app-upgrades - :安装、配置和使用官方及社区提供的Capacitor插件。
capacitor-plugins - :在Capacitor应用中配置Firebase Cloud Messaging实现推送通知。
capacitor-push-notifications