跳转至正文
教程

用 Capacitor 8 把 Nuxt 应用转成 iOS 和 Android 应用

使用 Capacitor 8 将现有 Nuxt 4 Web 应用转成 iOS 和 Android 原生移动应用。完整指南:配置静态生成、添加原生插件并上架应用商店。

用 Capacitor 8 把 Nuxt 应用转成 iOS 和 Android 应用

简介

已有 Nuxt Web 应用?本指南将教你如何将其转换为原生 iOS 和 Android 移动应用,使用 Capacitor 8 —— 最新版本,性能更强,还带来新功能。

Capacitor 将您的 Web 应用封装在原生容器中,在保留现有 Vue 代码库的同时,让您能够调用摄像头、文件系统和推送通知等设备 API。与 Flutter 或 React Native 不同,您无需重写任何内容 —— 您的 Nuxt code 可以直接运行。

你将学到:

  • 为现有的 Nuxt 应用配置静态生成
  • 添加 Capacitor 8 及必要的原生插件
  • 在 iOS 和 Android 模拟器上构建并测试
  • 启用 live reload 以加快开发
  • 修复常见的 iOS 布局问题(viewport、安全区域、水平溢出)
  • 使用 Capgo Native Navigation and Transitions 打造原生感的 UI

想从零开始一个新项目?请查看我们的指南: 从零开始构建 Nuxt 移动应用.

使用 Nuxt 和 Capacitor 的优势

  • Code 的可复用性: 在 Web 和移动端应用之间共享 Vue 组件与逻辑。
  • 性能: Nuxt 的静态生成功能可创建针对移动端优化的 bundle。
  • 原生能力: 通过 Capacitor 插件调用摄像头、地理位置和文件系统等设备功能。
  • 简化开发流程: 无需学习原生开发,直接使用熟悉的 Vue/Nuxt 开发模式。

前提条件

开始前,请确保你已准备好:

  • Node.js 18+ 已安装
  • 现有的 Nuxt 4 应用
  • Xcode 的 Mac (用于 iOS 开发,仅限 macOS)
  • Android Studio 中的错误日志 (用于 Android 开发)

为移动端配置 Nuxt 应用

第一步是配置 Nuxt 应用以进行静态生成。Capacitor 需要静态 HTML/JS/CSS 文件,以便打包进原生应用。

请确保您的 package.json 包含 generate 脚本:

{
  "scripts": {
    "dev": "nuxt dev",
    "build": "nuxt build",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "mobile": "bun run generate && bunx cap sync",
    "mobile:ios": "bun run mobile && bunx cap open ios",
    "mobile:android": "bun run mobile && bunx cap open android"
  }
}

重要提示: 如果您使用了服务端功能(API 路由、服务端中间件等),就需要将其重构为客户端替代方案或外部 API。

运行以下命令测试静态生成:

bun run generate

你应该会看到一个 .output/public 包含静态文件的文件夹。这就是 Capacitor 将会 bundle 到你的 native app 中的内容。

将 Capacitor 8 添加到项目中

若要将 Nuxt app 打包进 native mobile 容器,请按照以下步骤操作:

  1. 安装 Capacitor 核心库和 CLI:
bun add @capacitor/core
bun add -D @capacitor/cli
  1. 安装你可能会用到的常用 Capacitor 插件:
bun add @capacitor/app @capacitor/keyboard @capacitor/splash-screen @capacitor/status-bar @capacitor/preferences

这些插件提供以下核心功能:

  • @capacitor/app:处理应用生命周期事件(前台/后台、deep links)
  • @capacitor/keyboard:控制移动端的键盘行为
  • @capacitor/splash-screen:管理原生启动屏
  • @capacitor/status-bar: 设置设备状态栏样式
  • @capacitor/preferences: 键值对存储(类似于 localStorage 但原生支持)
  1. 使用你的项目详情初始化 Capacitor:
bunx cap init my-app com.example.myapp --web-dir .output/public

替换 my-app 为你的应用名称,并将 com.example.myapp 使用您的 App ID(反向域名格式)。

  1. 创建或更新 capacitor.config.ts 文件,填入正确的配置:
import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.myapp',
  appName: 'my-app',
  webDir: '.output/public',
  plugins: {
    SplashScreen: {
      launchShowDuration: 2000,
      launchAutoHide: true,
      androidScaleType: 'CENTER_CROP',
      splashFullScreen: true,
      splashImmersive: true,
    },
    Keyboard: {
      resize: 'body',
      resizeOnFullScreen: true,
    },
    StatusBar: {
      style: 'dark',
    },
  },
};

export default config;
  1. 安装原生平台:
bun add @capacitor/ios @capacitor/android
  1. 添加原生平台文件夹:
bunx cap add ios
bunx cap add android

Capacitor 将创建 ios 以及 android 位于项目根目录的文件夹,其中包含原生项目。

要构建 Android 项目,您需要 Android Studio 中的错误日志。对于 iOS,您需要一台安装了 Xcode 的 Mac.

  1. 构建并同步你的项目:
bun run mobile

这会运行你的自定义脚本,生成 Nuxt 静态 build,并将文件同步到原生平台。

构建和部署原生应用

若要构建并部署您的 Native Build 移动应用,请按照以下步骤操作:

若要开发 iOS 应用,您需要安装: Xcode 的 Mac 好,而开发 Android 应用则需要安装 Android Studio 中的错误日志 已安装。此外,如果你计划在应用商店发布应用,则需要加入 iOS 的 Apple Developer Program,并注册 Android 的 Google Play Console。

  1. 打开原生项目:

iOS 端:

bun run mobile:ios

针对 Android:

bun run mobile:android

或者直接使用 Capacitor CLI:

bunx cap open ios
bunx cap open android
  1. 构建并运行 App:

android-studio-run

  • 在 Android Studio 中,等待项目准备就绪,然后点击 “Run” 按钮将 App 部署到已连接的设备或模拟器上。

xcode-run

  • 在 Xcode 中,配置好签名账号以便将 App 部署到真机。如果你之前从未操作过,Xcode 会引导你完成该流程(请注意,你需要加入 Apple Developer Program)。配置完成后,点击 “Play” 按钮即可在已连接的设备上运行 App。

恭喜!你已成功将 Nuxt Web App 部署到移动设备。

nuxtjs-mobile-app

不过等等,在开发过程中其实还有一种更快捷的方法……

Capacitor 热重载

在开发过程中,你可以利用实时重载(live reloading)功能,在移动设备上即时查看更改。要启用此功能,请按照以下步骤操作:

  1. 查找你的本地 IP 地址:
  • 在 macOS 上,请在终端运行以下命令:

    ipconfig getifaddr en0
  • 在 Windows 上运行:

    ipconfig

    在输出结果中查找 IPv4 地址。

  1. 更新您的 capacitor.config.ts 使其指向你的开发服务器:
import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'my-app',
  webDir: '.output/public',
  server: {
    url: 'http://YOUR_IP_ADDRESS:3000',
    cleartext: true,
  },
  plugins: {
    // ... your plugin config
  },
};

export default config;

替换 YOUR_IP_ADDRESS 使用你的本地 IP 地址(例如: 192.168.1.100).

  1. 将更改应用到你的原生项目:
bunx cap copy

本指南中介绍的 copy 该命令会将 web 文件夹和配置更改复制到原生项目,而无需更新整个项目。

  1. 启动 Nuxt 开发服务器,并在 Xcode/Android Studio 中重新构建:
bun run dev

现在,每当你修改 Nuxt 应用时,移动端 App 都会自动重载以反映这些更改。

注意: 如果你安装了新插件或修改了原生文件,则需要重新构建原生项目,因为热重载仅适用于 Web code 的更改。

使用 Capacitor 插件

Capacitor 插件让你能在 Nuxt 应用中访问原生设备功能。下面来看看如何使用 分享插件 作为示例:

  1. 安装 Share 插件:
bun add @capacitor/share
  1. 创建或更新一个页面,以使用 Share 插件。在 Nuxt 4 中,页面放在 app/pages/:
<template>
  <div class="p-6">
    <h1 class="text-2xl font-bold mb-4">Welcome to Nuxt + Capacitor!</h1>
    <button
      @click="shareContent"
      class="px-6 py-3 bg-blue-600 text-white rounded-lg font-semibold"
    >
      Share now!
    </button>
  </div>
</template>

<script setup lang="ts">
import { Share } from '@capacitor/share';

async function shareContent() {
  await Share.share({
    title: 'Check this out!',
    text: 'Built with Nuxt and Capacitor',
    url: 'https://capacitorjs.com',
    dialogTitle: 'Share with friends',
  });
}
</script>
  1. 将更改同步到原生项目:
bun run mobile

或者只同步,不重新构建:

bunx cap sync
  1. 重新构建并在设备上运行应用。

现在,当你点击 “Share now!” 按钮时,就会弹出原生分享对话框。

接下来,你可以通过 Capgo 导航和过渡效果,让应用在 iOS 和 Android 上更具原生感,并修复会导致水平溢出或安全区域被裁剪的常见 iOS 布局问题。

使用 Capgo 原生导航与过渡效果,打造原生感 UI

我多年来一直在使用 Ionic 用于构建跨平台应用,但如果你已经有了,将它与 Nuxt 集成会显得很 hacky,且通常并不划算。 Tailwind CSS.

若想在 Nuxt + Capacitor 应用中获得原生移动端体验,请使用 Capgo 插件,而不是像 Konsta UI 这种仅限 Web 的 UI kit:

  • @capgo/capacitor-native-navigation — 原生导航栏、iOS 上的 Liquid Glass 标签栏,以及 Android 上的毛玻璃标签栏样式。你的 Nuxt router 负责维护路由状态,而插件则负责接管原生 UI 框架。
  • @capgo/capacitor-transitions — 在 WebView 层实现 Ionic 风格的页面过渡和 iOS 边缘侧滑返回,而无需采用 Ionic UI。

安装两者:

bun add @capgo/capacitor-native-navigation @capgo/capacitor-transitions
bunx cap sync

使用 CSS inset 模式配置原生导航,让 Web 内容正确避让原生栏:

import { NativeNavigation } from '@capgo/capacitor-native-navigation';

await NativeNavigation.configure({
  contentInsetMode: 'css',
  animationDuration: 360,
  glass: {
    effect: 'liquidGlass',
  },
});

渲染 Liquid Glass 标签栏(iOS 使用系统原生渲染;Android 使用毛玻璃 WebView 背景):

await NativeNavigation.setTabbar({
  selectedId: 'home',
  labelVisibilityMode: 'labeled',
  icons: true,
  colors: { dynamic: true },
  tabs: [
    { id: 'home', title: 'Home', icon: { svg: '...' } },
    { id: 'settings', title: 'Settings', icon: { svg: '...' } },
  ],
});

await NativeNavigation.addListener('tabSelect', ({ id }) => {
  router.push(`/${id}`);
});

在应用外壳中添加原生页面转场效果:

<script setup>
import { ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import '@capgo/capacitor-transitions';
import { initTransitions, setDirection, setupRouterOutlet } from '@capgo/capacitor-transitions/vue';

initTransitions({ platform: 'auto' });

const router = useRouter();
const outletRef = ref(null);

onMounted(() => {
  if (outletRef.value) {
    setupRouterOutlet(outletRef.value, { platform: 'auto', swipeGesture: 'auto' });
  }
});

const openSettings = () => {
  setDirection('forward');
  router.push('/settings');
};
</script>

<template>
  <cap-router-outlet ref="outletRef">
    <router-view />
  </cap-router-outlet>
</template>

将路由页面包裹在 cap-router-outlet, cap-page,以及 cap-content,并调用 setDirection('forward') 或 setDirection('back') 导航前。当原生导航接管这些区域时,请勿重复添加 Web 页眉或页脚。

查看完整指南: 使用 @capgo/capacitor-native-navigation 以及 使用 @capgo/capacitor-transitions.

使用 Tailwind 处理安全区域

在 Tailwind CSS 中处理设备安全区域,请使用 @capgo/tailwind-capacitor (发布为 tailwind-capacitor 在 npm 上)。它提供 safe-areas 工具类和其他对 Capacitor 友好的 Tailwind 插件:

bun add -D tailwind-capacitor

在 app/assets/css/main.css:

@import 'tailwindcss';
@plugin "@capgo/tailwind-capacitor/platform";
@plugin "@capgo/tailwind-capacitor/safe-areas";

对于使用 Tailwind CSS 4 的 Nuxt 4,请将此 import 保留在从以下位置引用的 CSS 文件中 nuxt.config.ts.

使用以下工具类,例如 pt-safe, pb-safe,以及 px-safe 而不是零散地 env(safe-area-inset-*) 手动完成。该项目正在积极开发中 —— 如果你的 Nuxt 配置缺少某些内容, 请在 GitHub 上提交 PR.

修复 iOS 布局问题(视口、安全区域与水平溢出)

如果 iOS 上的内容看起来被裁剪、偏移或可水平滚动,仅靠添加更多 overflow-x: hidden 或单独调整 viewport 标签通常无法解决问题。请按顺序进行以下检查。

确保 viewport meta 标签已正确应用

在 nuxt.config.ts, 通过以下方式设置视口 (viewport) app.head:

export default defineNuxtConfig({
  app: {
    head: {
      meta: [
        {
          name: 'viewport',
          content: 'width=device-width, initial-scale=1, viewport-fit=cover',
        },
      ],
    },
  },
});

只用一个根容器处理 iOS 安全区域

创建一个统一的 app shell,并在其中应用 safe area 内边距,而不是在多个嵌套组件中:

html,
body,
#__nuxt {
  width: 100%;
  min-height: 100%;
  margin: 0;
  padding: 0;
  overflow-x: hidden;
}

* {
  box-sizing: border-box;
}

.app-shell {
  min-height: 100dvh;
  width: 100%;
  padding-top: env(safe-area-inset-top);
  padding-right: env(safe-area-inset-right);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: env(safe-area-inset-left);
}

将所有页面内容包裹在 .app-shell。在 header、modal 和 layout wrapper 中重复设置 safe-area padding 往往会让 UI 看起来被裁剪或过大。

使用 @capgo/tailwind-capacitor,你可以使用如下 utility 类来实现相同的 padding pt-safe pb-safe px-safe 在这个单一 shell 上。

设置 Capacitor iOS contentInset 改为 never 首先

在 capacitor.config.ts,建议禁用 native inset,让 CSS(或 Native Navigation 的 contentInsetMode: 'css')来管理安全区域:

const config: CapacitorConfig = {
  appId: 'com.example.myapp',
  appName: 'my-app',
  webDir: 'out',
  ios: {
    contentInset: 'never',
  },
};

将 Capacitor 的自动 content inset 与 CSS env(safe-area-inset-*) padding 混合使用,是导致间距翻倍的常见原因。

找到真正溢出的元素

常见原因是某个元素使用了 100vw,Tailwind w-screen,固定像素宽度或较大的 min-width.

在 Safari Web Inspector 中运行:

[...document.querySelectorAll('*')]
  .filter(el => el.scrollWidth > document.documentElement.clientWidth)
  .map(el => ({
    el,
    tag: el.tagName,
    class: el.className,
    scrollWidth: el.scrollWidth,
    clientWidth: document.documentElement.clientWidth,
  }));

使用 Tailwind 时,替换 w-screen 配合 w-full 尽可能避免。许多水平溢出问题都来自 100vw / w-screen重复的 safe-area 内边距或固定宽度容器,而不是 viewport meta 标签本身。

总结

你已成功使用 Capacitor 8 将现有的 Nuxt Web 应用转换为 iOS 和 Android 原生应用。你的 Vue 代码库现在可以在移动设备上原生运行,并能调用设备 API。

你完成了什么:

  • 配置 Nuxt 以进行静态生成
  • 添加 Capacitor 8 及核心插件
  • 构建并部署到 iOS 和 Android 模拟器
  • 开启开发环境的 live reload
  • 修复常见的 iOS 布局问题(viewport、safe area、overflow)
  • 使用 Capgo Native Navigation and Transitions 打造原生感 UI

后续步骤:

  • 设置 Capgo 用于无需重新提交到 App Store 的 OTA 更新
  • 添加更多原生插件,如 Camera、Geolocation 或 Push Notifications
  • 配置生产环境的应用图标与启动页
  • 为提交 App Store 和 Google Play 做准备

想要开启新项目?请查看 从零开始构建 Nuxt 移动应用 获取分步指南。

资源

了解 Capgo 如何帮你更快构建更好的应用, 注册免费账号 今天就开始。

继续阅读《使用 Capacitor 将 Nuxt 应用转换为 iOS &amp; Android》第 8 部分

如果你正在使用 用 Capacitor 8 把 Nuxt 应用转成 iOS 和 Android 应用 要规划原生插件工作,请将其与 Capgo 插件目录 查看 Capgo 插件目录中的产品工作流, Capgo 提供的 Capacitor 插件 查看由 Capgo 提供的 Capacitor 插件中的实现细节, 添加或更新插件 查看添加或更新插件中的实现细节, Ionic Enterprise 插件替代方案 查看 Ionic Enterprise 插件替代方案中的产品工作流,以及 Capgo Native Build 查看 Capgo Native Builds 中的产品工作流。

为 Capacitor 应用提供 Live Updates

当 Web 层出现线上 Bug 时,通过 Capgo 发布修复,而不用等 App Store 审核好几天。用户会在后台收到更新,原生变更则仍走正常审核流程。

博客最新动态

Capgo 为你提供打造真正专业的移动应用所需的最有价值的洞察。