capacitor-best-practices by cap-go/capacitor-skills
npx skills add https://github.com/cap-go/capacitor-skills --skill capacitor-best-practices构建生产就绪的 Capacitor 应用程序的全面指南。
my-app/
├── src/ # Web 应用源代码
├── android/ # Android 原生项目
├── ios/ # iOS 原生项目
├── capacitor.config.ts # Capacitor 配置
├── package.json
└── tsconfig.json
capacitor.config.ts (正确):
import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.company.app',
appName: 'My App',
webDir: 'dist',
server: {
// 仅用于开发环境
...(process.env.NODE_ENV === 'development' && {
url: 'http://localhost:5173',
cleartext: true,
}),
},
plugins: {
SplashScreen: {
launchAutoHide: false,
},
},
};
export default config;
capacitor.config.json (避免):
{
"server": {
"url": "http://localhost:5173",
"cleartext": true
}
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
切勿将开发服务器 URL 提交到生产环境
保持 Capacitor 核心包同步:
bun add @capacitor/core@latest @capacitor/cli@latest
bun add @capacitor/ios@latest @capacitor/android@latest
bunx cap sync
正确:
# 1. 安装包
bun add @capgo/capacitor-native-biometric
# 2. 同步原生项目
bunx cap sync
# 3. 对于 iOS:安装 pods(或使用 SPM)
cd ios/App && pod install && cd ../..
错误:
# 缺少同步步骤
bun add @capgo/capacitor-native-biometric
# 应用崩溃,因为原生代码未链接
正确 - 使用前检查可用性:
import { NativeBiometric, BiometryType } from '@capgo/capacitor-native-biometric';
async function authenticate() {
const { isAvailable, biometryType } = await NativeBiometric.isAvailable();
if (!isAvailable) {
// 回退到密码验证
return authenticateWithPassword();
}
try {
await NativeBiometric.verifyIdentity({
reason: '验证身份以访问您的账户',
title: '生物识别登录',
});
return true;
} catch (error) {
// 用户取消或生物识别失败
return false;
}
}
错误 - 无可用性检查:
// 如果生物识别不可用,将导致崩溃
await NativeBiometric.verifyIdentity({ reason: '登录' });
正确 - 动态导入:
// 仅在需要时加载
async function scanDocument() {
const { DocumentScanner } = await import('@capgo/capacitor-document-scanner');
return DocumentScanner.scanDocument();
}
错误 - 启动时导入所有内容:
// 增加初始包大小
import { DocumentScanner } from '@capgo/capacitor-document-scanner';
import { NativeBiometric } from '@capgo/capacitor-native-biometric';
import { Camera } from '@capacitor/camera';
// ... 还有 20 多个插件
正确 - 使用硬件加速:
<!-- android/app/src/main/AndroidManifest.xml -->
<application
android:hardwareAccelerated="true"
android:largeHeap="true">
<!-- ios/App/App/Info.plist -->
<key>UIViewGroupOpacity</key>
<false/>
正确 - 批量操作:
// 单次调用,批量数据
await Storage.set({
key: 'userData',
value: JSON.stringify({ name, email, preferences }),
});
错误 - 多次桥接调用:
// 每次调用都会跨越 JS-原生桥接
await Storage.set({ key: 'name', value: name });
await Storage.set({ key: 'email', value: email });
await Storage.set({ key: 'preferences', value: JSON.stringify(preferences) });
正确:
import { Camera, CameraResultType } from '@capacitor/camera';
const photo = await Camera.getPhoto({
quality: 80, // 不是 100
width: 1024, // 合理的最大值
resultType: CameraResultType.Uri, // 对于大图像,不使用 Base64
correctOrientation: true,
});
错误:
const photo = await Camera.getPhoto({
quality: 100,
resultType: CameraResultType.Base64, // 内存密集型
// 无大小限制
});
正确 - 对敏感数据使用安全存储:
import { NativeBiometric } from '@capgo/capacitor-native-biometric';
// 安全存储凭据
await NativeBiometric.setCredentials({
username: 'user@example.com',
password: 'secret',
server: 'api.myapp.com',
});
// 通过生物识别验证检索
const credentials = await NativeBiometric.getCredentials({
server: 'api.myapp.com',
});
错误 - 明文存储:
import { Preferences } from '@capacitor/preferences';
// 切勿将敏感数据存储在明文偏好设置中
await Preferences.set({
key: 'password',
value: 'secret', // 以明文存储!
});
对于处理敏感数据的生产应用:
// capacitor.config.ts
const config: CapacitorConfig = {
plugins: {
CapacitorHttp: {
enabled: true,
},
},
server: {
// 在生产环境中禁用明文传输
cleartext: false,
},
};
import { IsRoot } from '@capgo/capacitor-is-root';
async function checkDeviceSecurity() {
const { isRooted } = await IsRoot.isRooted();
if (isRooted) {
// 显示警告或限制功能
showSecurityWarning('设备似乎已 Root/越狱');
}
}
import { AppTrackingTransparency } from '@capgo/capacitor-app-tracking-transparency';
async function requestTracking() {
const { status } = await AppTrackingTransparency.requestPermission();
if (status === 'authorized') {
// 启用分析
}
}
正确:
import { Camera, CameraResultType } from '@capacitor/camera';
async function takePhoto() {
try {
const image = await Camera.getPhoto({
quality: 90,
resultType: CameraResultType.Uri,
});
return image;
} catch (error) {
if (error.message === 'User cancelled photos app') {
// 用户取消,不是错误
return null;
}
if (error.message.includes('permission')) {
// 权限被拒绝
showPermissionDialog();
return null;
}
// 意外错误
console.error('相机错误:', error);
throw error;
}
}
错误:
// 无错误处理
const image = await Camera.getPhoto({ quality: 90 });
import { CapacitorUpdater } from '@capgo/capacitor-updater';
// 通知应用已准备就绪
CapacitorUpdater.notifyAppReady();
// 监听更新
CapacitorUpdater.addListener('updateAvailable', async (update) => {
// 在后台下载
const bundle = await CapacitorUpdater.download({
url: update.url,
version: update.version,
});
// 在下次应用启动时应用
await CapacitorUpdater.set(bundle);
});
正确 - 后台下载,重启时应用:
// 静默下载
const bundle = await CapacitorUpdater.download({ url, version });
// 用户继续使用应用...
// 当他们关闭/重新打开时应用
await CapacitorUpdater.set(bundle);
错误 - 打断用户:
// 不要在用户活跃时强制重新加载
const bundle = await CapacitorUpdater.download({ url, version });
await CapacitorUpdater.reload(); // 打扰用户
现代方法 - 优先使用 SPM 而非 CocoaPods:
# Podfile - 移除插件 pods,改用 SPM
target 'App' do
capacitor_pods
# 插件依赖通过 Xcode 中的 SPM 管理
end
// android/app/build.gradle
android {
defaultConfig {
minSdkVersion 22
targetSdkVersion 34
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
// 用于 Web 测试的模拟
jest.mock('@capgo/capacitor-native-biometric', () => ({
NativeBiometric: {
isAvailable: jest.fn().mockResolvedValue({
isAvailable: true,
biometryType: 'touchId',
}),
verifyIdentity: jest.fn().mockResolvedValue({}),
},
}));
import { Capacitor } from '@capacitor/core';
if (Capacitor.isNativePlatform()) {
// 原生平台特定代码
} else {
// Web 回退
}
// 或检查特定平台
if (Capacitor.getPlatform() === 'ios') {
// iOS 特定代码
}
每周安装量
279
代码仓库
GitHub 星标数
18
首次出现
2026年1月25日
安全审计
安装于
opencode225
codex213
gemini-cli208
github-copilot205
cursor178
kimi-cli172
Comprehensive guidelines for building production-ready Capacitor applications.
my-app/
├── src/ # Web app source
├── android/ # Android native project
├── ios/ # iOS native project
├── capacitor.config.ts # Capacitor configuration
├── package.json
└── tsconfig.json
capacitor.config.ts (CORRECT):
import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.company.app',
appName: 'My App',
webDir: 'dist',
server: {
// Only enable for development
...(process.env.NODE_ENV === 'development' && {
url: 'http://localhost:5173',
cleartext: true,
}),
},
plugins: {
SplashScreen: {
launchAutoHide: false,
},
},
};
export default config;
capacitor.config.json (AVOID):
{
"server": {
"url": "http://localhost:5173",
"cleartext": true
}
}
Never commit development server URLs to production
Keep Capacitor core packages in sync:
bun add @capacitor/core@latest @capacitor/cli@latest
bun add @capacitor/ios@latest @capacitor/android@latest
bunx cap sync
CORRECT :
# 1. Install the package
bun add @capgo/capacitor-native-biometric
# 2. Sync native projects
bunx cap sync
# 3. For iOS: Install pods (or use SPM)
cd ios/App && pod install && cd ../..
INCORRECT :
# Missing sync step
bun add @capgo/capacitor-native-biometric
# App crashes because native code not linked
CORRECT - Check availability before use:
import { NativeBiometric, BiometryType } from '@capgo/capacitor-native-biometric';
async function authenticate() {
const { isAvailable, biometryType } = await NativeBiometric.isAvailable();
if (!isAvailable) {
// Fallback to password
return authenticateWithPassword();
}
try {
await NativeBiometric.verifyIdentity({
reason: 'Authenticate to access your account',
title: 'Biometric Login',
});
return true;
} catch (error) {
// User cancelled or biometric failed
return false;
}
}
INCORRECT - No availability check:
// Will crash if biometrics not available
await NativeBiometric.verifyIdentity({ reason: 'Login' });
CORRECT - Dynamic imports:
// Only load when needed
async function scanDocument() {
const { DocumentScanner } = await import('@capgo/capacitor-document-scanner');
return DocumentScanner.scanDocument();
}
INCORRECT - Import everything at startup:
// Increases initial bundle size
import { DocumentScanner } from '@capgo/capacitor-document-scanner';
import { NativeBiometric } from '@capgo/capacitor-native-biometric';
import { Camera } from '@capacitor/camera';
// ... 20 more plugins
CORRECT - Use hardware acceleration:
<!-- android/app/src/main/AndroidManifest.xml -->
<application
android:hardwareAccelerated="true"
android:largeHeap="true">
<!-- ios/App/App/Info.plist -->
<key>UIViewGroupOpacity</key>
<false/>
CORRECT - Batch operations:
// Single call with batch data
await Storage.set({
key: 'userData',
value: JSON.stringify({ name, email, preferences }),
});
INCORRECT - Multiple bridge calls:
// Each call crosses the JS-native bridge
await Storage.set({ key: 'name', value: name });
await Storage.set({ key: 'email', value: email });
await Storage.set({ key: 'preferences', value: JSON.stringify(preferences) });
CORRECT :
import { Camera, CameraResultType } from '@capacitor/camera';
const photo = await Camera.getPhoto({
quality: 80, // Not 100
width: 1024, // Reasonable max
resultType: CameraResultType.Uri, // Not Base64 for large images
correctOrientation: true,
});
INCORRECT :
const photo = await Camera.getPhoto({
quality: 100,
resultType: CameraResultType.Base64, // Memory intensive
// No size limits
});
CORRECT - Use secure storage for sensitive data:
import { NativeBiometric } from '@capgo/capacitor-native-biometric';
// Store credentials securely
await NativeBiometric.setCredentials({
username: 'user@example.com',
password: 'secret',
server: 'api.myapp.com',
});
// Retrieve with biometric verification
const credentials = await NativeBiometric.getCredentials({
server: 'api.myapp.com',
});
INCORRECT - Plain storage:
import { Preferences } from '@capacitor/preferences';
// NEVER store sensitive data in plain preferences
await Preferences.set({
key: 'password',
value: 'secret', // Stored in plain text!
});
For production apps handling sensitive data:
// capacitor.config.ts
const config: CapacitorConfig = {
plugins: {
CapacitorHttp: {
enabled: true,
},
},
server: {
// Disable cleartext in production
cleartext: false,
},
};
import { IsRoot } from '@capgo/capacitor-is-root';
async function checkDeviceSecurity() {
const { isRooted } = await IsRoot.isRooted();
if (isRooted) {
// Show warning or restrict functionality
showSecurityWarning('Device appears to be rooted/jailbroken');
}
}
import { AppTrackingTransparency } from '@capgo/capacitor-app-tracking-transparency';
async function requestTracking() {
const { status } = await AppTrackingTransparency.requestPermission();
if (status === 'authorized') {
// Enable analytics
}
}
CORRECT :
import { Camera, CameraResultType } from '@capacitor/camera';
async function takePhoto() {
try {
const image = await Camera.getPhoto({
quality: 90,
resultType: CameraResultType.Uri,
});
return image;
} catch (error) {
if (error.message === 'User cancelled photos app') {
// User cancelled, not an error
return null;
}
if (error.message.includes('permission')) {
// Permission denied
showPermissionDialog();
return null;
}
// Unexpected error
console.error('Camera error:', error);
throw error;
}
}
INCORRECT :
// No error handling
const image = await Camera.getPhoto({ quality: 90 });
import { CapacitorUpdater } from '@capgo/capacitor-updater';
// Notify when app is ready
CapacitorUpdater.notifyAppReady();
// Listen for updates
CapacitorUpdater.addListener('updateAvailable', async (update) => {
// Download in background
const bundle = await CapacitorUpdater.download({
url: update.url,
version: update.version,
});
// Apply on next app start
await CapacitorUpdater.set(bundle);
});
CORRECT - Background download, apply on restart:
// Download silently
const bundle = await CapacitorUpdater.download({ url, version });
// User continues using app...
// Apply when they close/reopen
await CapacitorUpdater.set(bundle);
INCORRECT - Interrupt user:
// Don't force reload while user is active
const bundle = await CapacitorUpdater.download({ url, version });
await CapacitorUpdater.reload(); // Disrupts user
Modern approach - prefer SPM over CocoaPods:
# Podfile - Remove plugin pods, use SPM instead
target 'App' do
capacitor_pods
# Plugin dependencies via SPM in Xcode
end
// android/app/build.gradle
android {
defaultConfig {
minSdkVersion 22
targetSdkVersion 34
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
// Mock for web testing
jest.mock('@capgo/capacitor-native-biometric', () => ({
NativeBiometric: {
isAvailable: jest.fn().mockResolvedValue({
isAvailable: true,
biometryType: 'touchId',
}),
verifyIdentity: jest.fn().mockResolvedValue({}),
},
}));
import { Capacitor } from '@capacitor/core';
if (Capacitor.isNativePlatform()) {
// Native-specific code
} else {
// Web fallback
}
// Or check specific platform
if (Capacitor.getPlatform() === 'ios') {
// iOS-specific code
}
Weekly Installs
279
Repository
GitHub Stars
18
First Seen
Jan 25, 2026
Security Audits
Gen Agent Trust HubFailSocketPassSnykPass
Installed on
opencode225
codex213
gemini-cli208
github-copilot205
cursor178
kimi-cli172
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
106,200 周安装
竞争对手研究指南:SEO、内容、反向链接与定价分析工具
231 周安装
Azure 工作负载自动升级评估工具 - 支持 Functions、App Service 计划与 SKU 迁移
231 周安装
Kaizen持续改进方法论:软件开发中的渐进式优化与防错设计实践指南
231 周安装
软件UI/UX设计指南:以用户为中心的设计原则、WCAG可访问性与平台规范
231 周安装
Apify 网络爬虫和自动化平台 - 无需编码抓取亚马逊、谷歌、领英等网站数据
231 周安装
llama.cpp 中文指南:纯 C/C++ LLM 推理,CPU/非 NVIDIA 硬件优化部署
231 周安装