Token导航 LogoToken导航TokenDH.com
开发操作浏览器github未标认证来源可访问许可证需确认审计通过

capacitor-angularcapacitor Angular 命令行

Agent Skill

capacitor-angular 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

2,154

周安装

88

GitHub Stars

19

下载量

697
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:capacitor-angular(capacitor Angular 命令行)
来源仓库:https://github.com/capawesome-team/skills
仓库路径:skills/capacitor-angular
安装命令:
npx skills add https://github.com/capawesome-team/skills --skill capacitor-angular
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/capawesome-team/skills --skill capacitor-angular

简介

capacitor-angular 提供 Angular 与 Capacitor 集成的特定模式和最佳实践。

  • 适用于 Codex、Claude、Cursor、Gemini CLI 中检索项目结构、NgZone 集成和插件使用。
  • 支持 Angular 16+ 和 Capacitor 6/7/8,包含服务生命周期和异步处理。
  • 安装前需确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。
  • 适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

SKILL.md

Capacitor with Angular

Angular-specific patterns and best practices for Capacitor app development — project structure, services, lifecycle hooks, NgZone integration, and plugin usage.

Prerequisites

  1. Capacitor 6, 7, or 8 app with Angular 16+.
  2. Node.js and npm installed.
  3. Angular CLI installed (npm install -g @angular/cli).
  4. For iOS: Xcode installed.
  5. For Android: Android Studio installed.

Agent Behavior

  • Auto-detect before asking. Check the project for angular.json, package.json, capacitor.config.ts or capacitor.config.json, and existing directory structure. Only ask the user when something cannot be detected.
  • Guide step-by-step. Walk the user through the process one step at a time.
  • Adapt to project style. Detect whether the project uses standalone components or NgModule-based architecture and adapt code examples accordingly.

Procedures

Step 1: Analyze the Project

Auto-detect the following by reading project files:

  1. Angular version: Read @angular/core version from package.json.
  2. Capacitor version: Read @capacitor/core version from package.json. If not present, Capacitor has not been added yet — proceed to Step 2.
  3. Architecture style: Check src/main.ts for bootstrapApplication (standalone) vs. platformBrowserDynamic().bootstrapModule (NgModule). Check angular.json for further confirmation.
  4. Platforms: Check which directories exist (android/, ios/).
  5. Capacitor config format: Check for capacitor.config.ts (TypeScript) or capacitor.config.json (JSON).
  6. Build output directory: Read outputPath from angular.json under projects > <project-name> > architect > build > options > outputPath. This is needed for Capacitor's webDir setting.

Step 2: Add Capacitor to an Angular Project

Skip if @capacitor/core is already in package.json.

  1. Install Capacitor core and CLI: npm install @capacitor/core npm install -D @capacitor/cli
  2. Initialize Capacitor: npx cap init When prompted, set the web directory to the Angular build output path detected in Step 1. For Angular 17+ with the application builder, this is typically dist/<project-name>/browser. For older Angular versions, it is typically dist/<project-name>.
  3. Verify the webDir value in the generated capacitor.config.ts or capacitor.config.json matches the Angular build output path. If incorrect, update it: capacitor.config.ts: import type {CapacitorConfig} from '@capacitor/cli'; const config: CapacitorConfig = {appId: 'com.example.app', appName: 'my-app', webDir: 'dist/my-app/browser',}; export default config; capacitor.config.json: {"appId": "com.example.app", "appName": "my-app", "webDir": "dist/my-app/browser"}
  4. Build the Angular app and add platforms: ng build npm install @capacitor/android @capacitor/ios npx cap add android npx cap add ios npx cap sync

Step 3: Project Structure

A Capacitor Angular project has this structure:

my-app/
├── android/                  # Android native project
├── ios/                      # iOS native project
├── src/
│   ├── app/
│   │   ├── app.component.ts
│   │   ├── app.config.ts     # Standalone: app configuration
│   │   ├── app.module.ts     # NgModule: root module
│   │   ├── app.routes.ts     # Routing configuration
│   │   └── services/         # Angular services for Capacitor plugins
│   ├── environments/
│   │   ├── environment.ts
│   │   └── environment.prod.ts
│   ├── index.html
│   └── main.ts
├── angular.json
├── capacitor.config.ts       # or capacitor.config.json
├── package.json
└── tsconfig.json

Key points:

  • The android/ and ios/ directories contain native projects and should be committed to version control.
  • The src/ directory contains the Angular app, which is the web layer of the Capacitor app.
  • Capacitor plugins are called from Angular services or components inside src/app/.

Step 4: Using Capacitor Plugins in Angular

Capacitor plugins are plain TypeScript APIs. Import and call them directly in Angular components or services.

Direct Usage in a Component

import { Component } from '@angular/core';
import { Geolocation } from '@capacitor/geolocation';

@Component({
  selector: 'app-location',
  template: `
    <div>
      <p>Latitude: {{ latitude }}</p>
      <p>Longitude: {{ longitude }}</p>
      <button (click)="getCurrentPosition()">Get Location</button>
    </div>
  `,
  standalone: true,
})
export class LocationComponent {
  latitude: number | null = null;
  longitude: number | null = null;

  async getCurrentPosition() {
    const position = await Geolocation.getCurrentPosition();
    this.latitude = position.coords.latitude;
    this.longitude = position.coords.longitude;
  }
}

Wrapping Plugins in Angular Services (Recommended)

Wrapping Capacitor plugins in Angular services provides dependency injection, testability, and a single place to handle platform differences:

import { Injectable } from '@angular/core';
import { Camera, CameraResultType, CameraSource, Photo } from '@capacitor/camera';
import { Capacitor } from '@capacitor/core';

@Injectable({
  providedIn: 'root',
})
export class CameraService {
  async takePhoto(): Promise<Photo> {
    return Camera.getPhoto({
      quality: 90,
      allowEditing: false,
      resultType: CameraResultType.Uri,
      source: CameraSource.Camera,
    });
  }

  async pickFromGallery(): Promise<Photo> {
    return Camera.getPhoto({
      quality: 90,
      allowEditing: false,
      resultType: CameraResultType.Uri,
      source: CameraSource.Photos,
    });
  }

  isNativePlatform(): boolean {
    return Capacitor.isNativePlatform();
  }
}

Use the service in a component:

import { Component, inject } from '@angular/core';
import { CameraService } from '../services/camera.service';

@Component({
  selector: 'app-photo',
  template: `
    <button (click)="takePhoto()">Take Photo</button>
    <img *ngIf="photoUrl" [src]="photoUrl" alt="Captured photo" />
  `,
  standalone: true,
})
export class PhotoComponent {
  private cameraService = inject(CameraService);
  photoUrl: string | null = null;

  async takePhoto() {
    const photo = await this.cameraService.takePhoto();
    this.photoUrl = photo.webPath ?? null;
  }
}

Step 5: NgZone Integration for Plugin Event Listeners

Capacitor plugin event listeners run outside Angular's NgZone execution context. When a plugin listener updates component state, Angular's change detection does not automatically trigger. Wrap the handler logic in NgZone.run() to fix this.

Without NgZone (broken — UI does not update):

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Network, ConnectionStatus } from '@capacitor/network';
import { PluginListenerHandle } from '@capacitor/core';

@Component({
  selector: 'app-network',
  template: `<p>Status: {{ networkStatus }}</p>`,
  standalone: true,
})
export class NetworkComponent implements OnInit, OnDestroy {
  networkStatus = 'Unknown';
  private listenerHandle: PluginListenerHandle | null = null;

  async ngOnInit() {
    // BUG: This callback runs outside NgZone — the template will not update.
    this.listenerHandle = await Network.addListener('networkStatusChange', (status) => {
      this.networkStatus = status.connected ? 'Online' : 'Offline';
    });
  }

  async ngOnDestroy() {
    await this.listenerHandle?.remove();
  }
}

With NgZone (correct — UI updates properly):

import { Component, NgZone, OnInit, OnDestroy, inject } from '@angular/core';
import { Network, ConnectionStatus } from '@capacitor/network';
import { PluginListenerHandle } from '@capacitor/core';

@Component({
  selector: 'app-network',
  template: `<p>Status: {{ networkStatus }}</p>`,
  standalone: true,
})
export class NetworkComponent implements OnInit, OnDestroy {
  private ngZone = inject(NgZone);
  networkStatus = 'Unknown';
  private listenerHandle: PluginListenerHandle | null = null;

  async ngOnInit() {
    this.listenerHandle = await Network.addListener('networkStatusChange', (status) => {
      this.ngZone.run(() => {
        this.networkStatus = status.connected ? 'Online' : 'Offline';
      });
    });
  }

  async ngOnDestroy() {
    await this.listenerHandle?.remove();
  }
}

Rule: Always use NgZone.run() inside Capacitor plugin event listener callbacks that update component or service state bound to templates.

Step 6: Lifecycle Hook Patterns

Use Angular lifecycle hooks to manage Capacitor plugin listeners. Register listeners in ngOnInit and remove them in ngOnDestroy to prevent memory leaks.

Service-Based Listener Management

For app-wide listeners (e.g., network status, app state), use a service initialized at app startup:

import { Injectable, NgZone, OnDestroy, inject } from '@angular/core';
import { App } from '@capacitor/app';
import { PluginListenerHandle } from '@capacitor/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class AppStateService implements OnDestroy {
  private ngZone = inject(NgZone);
  private listenerHandle: PluginListenerHandle | null = null;

  private isActiveSubject = new BehaviorSubject<boolean>(true);
  isActive$ = this.isActiveSubject.asObservable();

  constructor() {
    this.initListener();
  }

  private async initListener() {
    this.listenerHandle = await App.addListener('appStateChange', (state) => {
      this.ngZone.run(() => {
        this.isActiveSubject.next(state.isActive);
      });
    });
  }

  async ngOnDestroy() {
    await this.listenerHandle?.remove();
  }
}

Initialize the service at app startup to ensure it runs immediately. In standalone apps, use APP_INITIALIZER or inject it in the root component. In NgModule apps, inject it in AppComponent:

Standalone (app.config.ts):

import { ApplicationConfig, APP_INITIALIZER } from '@angular/core';
import { AppStateService } from './services/app-state.service';

export const appConfig: ApplicationConfig = {
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: (appStateService: AppStateService) => () => {},
      deps: [AppStateService],
      multi: true,
    },
  ],
};

NgModule (app.component.ts):

import { Component } from '@angular/core';
import { AppStateService } from './services/app-state.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
})
export class AppComponent {
  constructor(private appStateService: AppStateService) {}
}

Step 7: Platform Detection

Use Capacitor.isNativePlatform() and Capacitor.getPlatform() to conditionally run native-only code:

import { Injectable } from '@angular/core';
import { Capacitor } from '@capacitor/core';

@Injectable({
  providedIn: 'root',
})
export class PlatformService {
  isNative(): boolean {
    return Capacitor.isNativePlatform();
  }

  getPlatform(): 'web' | 'ios' | 'android' {
    return Capacitor.getPlatform() as 'web' | 'ios' | 'android';
  }

  isIos(): boolean {
    return Capacitor.getPlatform() === 'ios';
  }

  isAndroid(): boolean {
    return Capacitor.getPlatform() === 'android';
  }

  isWeb(): boolean {
    return Capacitor.getPlatform() === 'web';
  }
}

Use it in components to show/hide native-only features:

import { Component, inject } from '@angular/core';
import { PlatformService } from '../services/platform.service';

@Component({
  selector: 'app-settings',
  template: `
    @if (platformService.isNative()) {
      <button (click)="openNativeSettings()">Open Device Settings</button>
    }
  `,
  standalone: true,
})
export class SettingsComponent {
  platformService = inject(PlatformService);

  openNativeSettings() {
    // Native-only logic
  }
}

Step 8: Deep Link Routing

Handle deep links by mapping Capacitor's App.addListener('appUrlOpen',...) event to Angular Router navigation:

import { Injectable, NgZone, inject } from '@angular/core';
import { Router } from '@angular/router';
import { App } from '@capacitor/app';

@Injectable({
  providedIn: 'root',
})
export class DeepLinkService {
  private ngZone = inject(NgZone);
  private router = inject(Router);

  constructor() {
    this.initDeepLinkListener();
  }

  private async initDeepLinkListener() {
    await App.addListener('appUrlOpen', (event) => {
      this.ngZone.run(() => {
        const url = new URL(event.url);
        const path = url.pathname;

        // Navigate to the route matching the deep link path.
        // Adjust the path parsing logic to match the app's URL scheme.
        if (path) {
          this.router.navigateByUrl(path);
        }
      });
    });
  }
}

Initialize DeepLinkService at app startup (same pattern as Step 6 — via APP_INITIALIZER or root component injection).

Step 9: Back Button Handling (Android)

Handle the Android hardware back button using App.addListener('backButton',...):

import { Injectable, NgZone, inject } from '@angular/core';
import { Location } from '@angular/common';
import { App } from '@capacitor/app';
import { Capacitor } from '@capacitor/core';

@Injectable({
  providedIn: 'root',
})
export class BackButtonService {
  private ngZone = inject(NgZone);
  private location = inject(Location);

  constructor() {
    if (Capacitor.getPlatform() === 'android') {
      this.initBackButtonListener();
    }
  }

  private async initBackButtonListener() {
    await App.addListener('backButton', ({ canGoBack }) => {
      this.ngZone.run(() => {
        if (canGoBack) {
          this.location.back();
        } else {
          App.exitApp();
        }
      });
    });
  }
}

Step 10: Build and Sync Workflow

After making changes to the Angular app, build and sync to native platforms:

ng build
npx cap sync

To run on a device or emulator:

npx cap run android
npx cap run ios

To open the native IDE for advanced configuration or debugging:

npx cap open android
npx cap open ios

For live reload during development:

npx cap run android --livereload --external
npx cap run ios --livereload --external

This starts ng serve internally and configures the native app to load from the development server.

Error Handling

  • UI not updating from plugin listeners: Wrap the listener callback body in NgZone.run(() => {...}). This is the most common Angular-specific issue with Capacitor.
  • webDir mismatch: If npx cap sync copies the wrong files, verify that webDir in capacitor.config.ts or capacitor.config.json matches the Angular build output path. For Angular 17+ with the application builder, the path is dist/<project-name>/browser. For older Angular versions, it is dist/<project-name>.
  • Plugin not found at runtime: Run npx cap sync after installing any new plugin. Verify the plugin appears in package.json dependencies.
  • Memory leaks from listeners: Always remove plugin listeners in ngOnDestroy. Store the PluginListenerHandle returned by addListener and call handle.remove() on destroy.
  • Deep links not working: Verify the app URL scheme / universal links are configured in the native projects (android/app/src/main/AndroidManifest.xml for Android, ios/App/App/Info.plist and associated domain entitlement for iOS). Verify DeepLinkService is initialized at app startup.
  • Back button closes app unexpectedly: Ensure the back button listener checks canGoBack before calling App.exitApp(). Only exit when there is no navigation history.
  • Build output empty after ng build: Verify the outputPath in angular.json is correct. For Angular 17+, the default changed to dist/<project-name>/browser with the application builder.

Related Skills

  • capacitor-app-creation — Create a new Capacitor app from scratch.
  • capacitor-app-development — General Capacitor development guidance not specific to Angular.
  • capacitor-plugins — Install and configure Capacitor plugins from official and community sources.
  • capacitor-react — React-specific patterns and best practices for Capacitor app development.
  • ionic-angular — Ionic Framework with Angular (UI components, navigation, theming on top of Capacitor).
  • capacitor-app-upgrades — Upgrade a Capacitor app to a newer major version.

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

37.06%
按下载量换算258

Claude

27.87%
按下载量换算194

Cursor

18.34%
按下载量换算128

Gemini CLI

10.03%
按下载量换算70

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

操作浏览器

该 Skill 可能涉及浏览器控制能力,使用时可能读取或操作网页内容,需要在受控环境中确认权限边界。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills