跳转至正文
教程

使用 Capacitor 8 将你的 Next.js 应用转换为 iOS 和 Android 应用

使用 Capacitor 8 将现有 Next.js 15 Web 应用转换为 iOS 和 Android 原生移动应用。完整指南:配置静态导出、添加原生插件并上架应用商店。

用 Capacitor 8 Capgo 将你的 Next.js 应用转换为 iOS 和 Android 应用(博客插图)

简介

已经有一个现成的 Next.js Web 应用了吗?在本指南中,你将学习如何使用 Capacitor 8 —— 最新版本,性能更强,还带来新功能。

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

你将学到:

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

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

使用 Next.js 和 Capacitor 的优势

  • Code 的可复用性:Next.js 允许你编写可复用组件,并在 Web 和移动应用之间共享 code,从而节省开发时间和精力。
  • 性能:Next.js 提供内置的性能优化,例如服务端渲染和 code 拆分,确保快速加载和流畅的用户体验。
  • 原生能力:Capacitor 让你可以访问相机、地理位置等原生设备功能,从而构建功能丰富的移动应用。
  • 简化开发:借助 Capacitor,你可以使用熟悉的 Web 技术开发和测试移动应用,降低学习门槛并简化开发流程。

前提条件

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

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

为移动端配置您的 Next.js 应用

第一步,先为 Next.js 应用配置静态导出。Capacitor 需要静态 HTML/JS/CSS 文件,才能打包进原生应用。

打开你的 next.config.js (或 next.config.ts) 文件,并添加导出配置:

/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'export',
  images: {
    unoptimized: true,
  },
};

module.exports = nextConfig;

本指南中介绍的 output: 'export' 该设置让 Next.js 生成静态 HTML 文件,并 images: { unoptimized: true } 绕过需要服务器的 Next.js 图片优化。

重要提示: 如果你用到了需要服务器的功能(API 路由、带数据获取的 Server Components 等),就需要把它们重构为客户端替代方案或外部 API。

将移动端专用脚本添加到你的项目中 package.json:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "mobile": "bun run build && bunx cap sync",
    "mobile:ios": "bun run mobile && bunx cap open ios",
    "mobile:android": "bun run mobile && bunx cap open android"
  }
}

运行以下命令测试静态导出:

bun run build

你应该会看到一个 out 文件夹,位于项目根目录。其中包含 Capacitor 会 bundle 进你的原生 App 的所有静态文件。

将 Capacitor 8 添加到项目中

要将你的 Next.js 应用打包进原生移动端容器,请按以下步骤操作:

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

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

  • @capacitor/app:处理应用生命周期事件(前台/后台、URL)
  • @capacitor/keyboard:控制移动端的键盘行为
  • @capacitor/splash-screen:管理原生启动屏
  • @capacitor/preferences:持久化存储键值对数据
  1. 使用你的项目详情初始化 Capacitor:
bunx cap init my-app com.example.myapp --web-dir out

替换 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: 'out',
  plugins: {
    SplashScreen: {
      launchShowDuration: 2000,
      launchAutoHide: true,
      androidScaleType: 'CENTER_CROP',
      showSpinner: false,
      splashFullScreen: true,
      splashImmersive: true,
    },
  },
};

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

这会运行你的自定义脚本,构建 Next.js 项目并将静态文件同步到原生平台。

构建和部署原生应用

要构建并部署你的原生移动应用,请按以下步骤操作: 开发 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。

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

nextjs-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: 'out',
  server: {
    url: 'http://YOUR_IP_ADDRESS:3000',
    cleartext: true,
  },
};

export default config;

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

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

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

  1. 使用 Android Studio 或 Xcode 在设备上重新构建并运行 App。

现在,每当你对 Next.js 应用进行更改时,移动端 App 都会自动重新加载以反映这些更改。

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

使用 Capacitor 插件

Capacitor 插件让你可以在 Next.js 应用中使用原生设备功能。下面来看看如何使用 分享插件 作为示例:

  1. 安装 Share 插件:
bun add @capacitor/share
  1. 更新 pages/index.js 在文件中使用 Share 插件:
import Head from 'next/head';
import styles from '../styles/Home.module.css';
import { Share } from '@capacitor/share';

export default function Home() {
  const share = async () => {
    await Share.share({
      title: 'Open Youtube',
      text: 'Check new video on youtube',
      url: 'https://www.youtube.com',
      dialogTitle: 'Share with friends',
    });
  };

  return (
    <div className={styles.container}>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className={styles.main}>
        <h1 className={styles.title}>
          Welcome to <a href="https://nextjs.org">Capgo!</a>
        </h1>

        <p className={styles.description}>
          <h2>Cool channel</h2>
          <button onClick={() => share()}>Share now!</button>
        </p>
      </main>
    </div>
  );
}
  1. 将更改同步到原生项目:

如前所述,安装新 plugin 时,我们需要执行 sync 操作,然后将应用重新部署到设备上。为此,请运行以下命令:

bun run mobile

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

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

现在,当你点击“Share now!”按钮时,会弹出原生分享对话框,让你可以把内容分享到其他应用。

next-capacitor-share
接下来,你可以借助 Capgo 的导航和转场,让应用在 iOS 和 Android 上更有原生感,并修复常见的 iOS 布局问题,例如横向溢出或安全区域被裁切。 ## 使用 Capgo 原生导航与转场打造原生感 UI

我多年来一直在使用 Ionic 用于构建跨平台应用,但把它与 Next.js 集成很 hacky,已有现成方案时通常不值得。 Tailwind CSS 4.

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

  • @capgo/capacitor-native-navigation — 原生 navbar、iOS 上的 Liquid Glass tab bar,以及 Android 上的毛玻璃 tab bar 样式。Next.js router 保留路由状态,插件则掌控原生外壳。
  • @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}`);
});

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

import '@capgo/capacitor-transitions';
import { initTransitions, setDirection, setupRouterOutlet } from '@capgo/capacitor-transitions/react';

initTransitions({ platform: 'auto' });

将路由页面包裹在 cap-router-outlet, cap-page,以及 cap-content,并调用 setDirection('forward') 或 setDirection('back') 在……之前 router.push() 或 router.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

在 styles/globals.css:

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

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

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

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

确保 viewport meta 标签已正确应用

App Router (app/): export viewport 来自 app/layout.tsx:

import type { Viewport } from 'next';

export const viewport: Viewport = {
  width: 'device-width',
  initialScale: 1,
  viewportFit: 'cover',
};

Pages Router (pages/): 请将 viewport meta 标签放入 pages/_app.tsx,而不是 _document.tsx (Next.js 可能不会按你预期的方式 _document.tsx 应用 viewport 行为相关的标签)。

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

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

html,
body,
#__next {
  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 标签本身。

性能优化

为了确保您的 Next.js 和 Capacitor 应用获得最佳性能,请参考以下最佳实践:

  • 通过移除未使用的依赖项和资源来减小应用体积。
  • 优化图片和其他媒体文件,以缩短加载时间。
  • 对组件和页面实现懒加载 (lazy loading),以提升初始加载性能。
  • 利用 Next.js 的服务端渲染 (SSR) 来提升应用加载速度和搜索引擎优化 (SEO)。
  • 利用 Capacitor 的内置优化,例如 WebView 缓存和应用打包 (bundling)。

总结

您已成功使用 Capacitor 8 将现有的 Next.js Web 应用转换为原生 iOS 和 Android 应用。您的 Web 代码库现在可在移动设备上原生运行,并能访问设备 API。

你完成了什么:

  • 配置 Next.js 实现静态导出
  • 添加 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 图标和启动画面
  • 为 App Store 和 Google Play 提交做好准备

刚开始新项目?查看 从零开始构建 Next.js 移动应用 获取分步指南。

资源

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

常见问题

如何将 Next.js 应用转换为移动应用?

在 next.config 中将 output 设置为 export,让 Next.js 构建静态站点,添加 Capacitor 以及 iOS 和 Android 平台,将 webDir 指向 out 文件夹,然后运行 npx cap sync 并打开原生项目。像 API 路由这类仅服务端功能必须迁移到单独的后端。发布后, Capgo 实时更新 无需经过应用商店审核即可推送 Web 端更新。

继续阅读:使用 Capacitor 将 Next.js 应用转换为 iOS & Android 8

如果你正在使用 使用 Capacitor 8 将你的 Next.js 应用转换为 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 为你提供打造真正专业的移动应用所需的最有价值的洞察。