Skip to content

Capacitor Template

The Capacitor template provides a cross-platform native app development solution using web technologies, perfect for building mobile applications that can run on iOS and Android.

Technical Stack

  • Capacitor - Cross-platform native runtime
  • Vue 3 - Progressive JavaScript framework
  • TypeScript - Type-safe development
  • Vite - Fast build tool and dev server
  • Vue Router - Client-side routing
  • Pinia - State management library
  • Vue i18n - Internationalization
  • Tailwind CSS - Utility-first CSS framework

Quick Start

1. Create Project

bash
# Initialize project
vup init my-capacitor-project
cd my-capacitor-project

# Add Capacitor template
vup add my-capacitor-app

2. Install Dependencies

bash
# Install dependencies
pnpm install

3. Start Development

bash
# Start development server
cd apps/my-capacitor-app
pnpm dev

The application will be available at http://localhost:9301.

Project Structure

apps/my-capacitor-app/
├── src/
│   ├── assets/           # Static assets
│   │   └── images/       # Image files
│   ├── locales/          # Internationalization
│   │   ├── index.ts      # i18n configuration
│   │   ├── en_US.ts      # English translations
│   │   └── zh_CN.ts      # Chinese translations
│   ├── router/           # Vue Router
│   │   ├── index.ts      # Router configuration
│   │   └── routes.ts     # Route definitions
│   ├── views/            # Page components
│   │   ├── demo/         # Demo pages
│   │   ├── docs/         # Documentation pages
│   │   ├── empty/        # Empty state pages
│   │   └── index/        # Home page
│   ├── App.vue           # Root component
│   ├── main.ts           # Application entry point
│   └── vue-shim.d.ts     # Vue type declarations
├── ios/                  # iOS native project
│   └── App/              # iOS app files
├── android/              # Android native project
│   └── app/              # Android app files
├── public/               # Public assets
├── capacitor.config.json # Capacitor configuration
├── package.json          # Dependencies and scripts
├── tsconfig.json         # TypeScript configuration
└── vite.config.js        # Vite configuration

Core Features

Vue 3 with Capacitor

vue
<template>
  <div class="container">
    <h1>{{ title }}</h1>
    <p>{{ description }}</p>
    <button @click="handleNativeAction">Call Native Function</button>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { Capacitor } from '@capacitor/core';

const title = ref('Capacitor App');
const description = ref('Cross-platform native app with web technologies');

const handleNativeAction = async () => {
  if (Capacitor.isNativePlatform()) {
    // Call native function
    const { Toast } = await import('@capacitor/toast');
    await Toast.show({
      text: 'Hello from native!',
      duration: 'short',
    });
  } else {
    // Fallback for web
    alert('Hello from web!');
  }
};
</script>

<style scoped>
.container {
  @apply p-4 bg-white rounded-lg shadow-md;
}
</style>

Native Plugin Integration

typescript
// utils/native.ts
import { Capacitor } from '@capacitor/core';
import { Camera, CameraResultType } from '@capacitor/camera';
import { Geolocation } from '@capacitor/geolocation';
import { Device } from '@capacitor/device';

export class NativeService {
  static async takePicture(): Promise<string> {
    if (!Capacitor.isNativePlatform()) {
      throw new Error('Camera is only available on native platforms');
    }

    const image = await Camera.getPhoto({
      quality: 90,
      allowEditing: true,
      resultType: CameraResultType.Uri,
    });

    return image.webPath || '';
  }

  static async getCurrentPosition(): Promise<GeolocationPosition> {
    if (!Capacitor.isNativePlatform()) {
      throw new Error('Geolocation is only available on native platforms');
    }

    const coordinates = await Geolocation.getCurrentPosition();
    return coordinates;
  }

  static async getDeviceInfo(): Promise<any> {
    const info = await Device.getInfo();
    return info;
  }
}

Internationalization

typescript
// locales/en_US.ts
export default {
  common: {
    title: 'Capacitor Application',
    description: 'Cross-platform native app with web technologies',
    button: 'Call Native Function',
  },
  navigation: {
    home: 'Home',
    demo: 'Demo',
    docs: 'Documentation',
  },
};

Tailwind CSS Styling

vue
<template>
  <div class="min-h-screen bg-gray-100">
    <header class="bg-white shadow-sm">
      <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <h1 class="text-3xl font-bold text-gray-900">
          {{ $t('common.title') }}
        </h1>
      </div>
    </header>

    <main class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
      <div class="px-4 py-6 sm:px-0">
        <div class="border-4 border-dashed border-gray-200 rounded-lg h-96">
          <p class="text-center text-gray-500 mt-20">
            {{ $t('common.description') }}
          </p>
        </div>
      </div>
    </main>
  </div>
</template>

Development Tools

Capacitor Configuration

json
// capacitor.config.json
{
  "appId": "com.example.myapp",
  "appName": "My Capacitor App",
  "webDir": "dist",
  "bundledWebRuntime": false,
  "server": {
    "androidScheme": "https"
  },
  "plugins": {
    "SplashScreen": {
      "launchShowDuration": 2000,
      "backgroundColor": "#ffffff",
      "androidSplashResourceName": "splash",
      "androidScaleType": "CENTER_CROP",
      "showSpinner": true,
      "androidSpinnerStyle": "large",
      "iosSpinnerStyle": "small",
      "spinnerColor": "#999999",
      "splashFullScreen": true,
      "splashImmersive": true
    }
  }
}

Vite Configuration

javascript
// vite.config.js
import path from 'path';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import AutoImport from 'unplugin-auto-import/vite';
import { defineConfig, mergeConfig } from 'vite';

export default mergeConfig(
  defineConfig({
    root: '.',
    plugins: [
      vue(),
      vueJsx(),
      AutoImport({
        imports: ['vue', 'vue-router', 'pinia', 'vue-i18n'],
        dts: path.resolve(__dirname, 'auto-imports.d.ts'),
        vueTemplate: true,
      }),
    ],
    resolve: {
      alias: {
        '@': path.resolve(__dirname, './src'),
        '@shared': path.resolve(__dirname, '../../_shared'),
      },
    },
    css: {
      postcss: path.resolve(__dirname, '../../postcss.config.js'),
    },
    build: {
      target: 'es2015',
      minify: 'esbuild',
      sourcemap: false,
      outDir: 'dist',
      rollupOptions: {
        output: {
          manualChunks: {
            vendor: ['vue', 'vue-router', 'pinia'],
            utils: ['lodash-es', 'dayjs'],
          },
        },
      },
    },
    server: {
      host: '0.0.0.0',
      port: 9301,
      open: false,
      cors: true,
    },
  })
);

TypeScript Configuration

json
// tsconfig.json
{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "outDir": "./dist",
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@shared/*": ["../../_shared/*"]
    }
  },
  "include": [
    "src/**/*",
    "src/**/*.vue",
    "src/*.vue",
    "./auto-imports.d.ts",
    "src/vue-shim.d.ts"
  ]
}

Available Scripts

json
{
  "scripts": {
    "dev": "vite",
    "build": "tsc --noEmit && vite build",
    "preview": "vite preview",
    "cap:add:ios": "cap add ios",
    "cap:add:android": "cap add android",
    "cap:sync": "cap sync",
    "cap:run:ios": "cap run ios",
    "cap:run:android": "cap run android",
    "cap:open:ios": "cap open ios",
    "cap:open:android": "cap open android",
    "lint": "eslint src/ --ext .vue,.ts,.js",
    "lint:fix": "eslint src/ --ext .vue,.ts,.js --fix",
    "format": "prettier --write \"src/**/*.{js,ts,vue,json,css,scss}\"",
    "format:check": "prettier --check \"src/**/*.{js,ts,vue,json,css,scss}\""
  }
}

Platform Requirements

iOS Development

  • Xcode 14.0 or later
  • iOS SDK 12.0 or later
  • CocoaPods for dependency management

Android Development

  • Android Studio with Android SDK
  • Java Development Kit (JDK) 11 or later
  • Android SDK API level 21 or later

Development Workflow

1. Web Development

bash
# Start web development server
pnpm dev

# Build for production
pnpm build

2. Add Native Platforms

bash
# Add iOS platform
pnpm cap:add:ios

# Add Android platform
pnpm cap:add:android

3. Sync Changes

bash
# Sync web assets to native platforms
pnpm cap:sync

4. Run on Devices

bash
# Run on iOS simulator
pnpm cap:run:ios

# Run on Android emulator
pnpm cap:run:android

5. Open in Native IDEs

bash
# Open iOS project in Xcode
pnpm cap:open:ios

# Open Android project in Android Studio
pnpm cap:open:android

Best Practices

Platform Detection

typescript
import { Capacitor } from '@capacitor/core';

// Check if running on native platform
if (Capacitor.isNativePlatform()) {
  // Native-specific code
  console.log('Running on native platform');
} else {
  // Web-specific code
  console.log('Running on web platform');
}

// Check specific platform
if (Capacitor.getPlatform() === 'ios') {
  // iOS-specific code
} else if (Capacitor.getPlatform() === 'android') {
  // Android-specific code
}

Error Handling

typescript
import { Capacitor } from '@capacitor/core';

export async function safeNativeCall<T>(
  nativeFunction: () => Promise<T>,
  fallback: T
): Promise<T> {
  try {
    if (Capacitor.isNativePlatform()) {
      return await nativeFunction();
    } else {
      return fallback;
    }
  } catch (error) {
    console.error('Native function failed:', error);
    return fallback;
  }
}

Responsive Design

vue
<template>
  <div class="app-container">
    <div class="content">
      <h1>{{ title }}</h1>
      <p>{{ description }}</p>
    </div>
  </div>
</template>

<style scoped>
.app-container {
  @apply min-h-screen bg-gray-100;
}

.content {
  @apply max-w-md mx-auto p-4;
}

/* Mobile-first responsive design */
@media (min-width: 768px) {
  .content {
    @apply max-w-2xl;
  }
}

@media (min-width: 1024px) {
  .content {
    @apply max-w-4xl;
  }
}
</style>

Build and Deployment

Web Build

bash
# Build for web
pnpm build

# The built files will be in the dist directory

Native Build

bash
# Sync web assets to native platforms
pnpm cap:sync

# Build iOS app
pnpm cap:open:ios
# Then build in Xcode

# Build Android app
pnpm cap:open:android
# Then build in Android Studio