跳转至正文
教程

使用 SvelteKit 和 Capacitor 构建移动应用

学习如何使用 SvelteKit、Capacitor 构建移动应用,并优化 Capgo 的原生导航、过渡效果及 iOS 布局最佳实践。

使用 SvelteKit 和 Capacitor Capgo 构建移动应用博客插图

在本教程中,我们将从一个全新的 SvelteKit 应用开始,并使用 Capacitor 转向原生移动开发。你还可以添加 Capgo Native Navigation and Transitions 来获得原生移动体验,并使用 tailwind-capacitor 处理安全区域。

Capacitor 允许您轻松将 SvelteKit Web 应用转换为原生移动应用,无需进行重大修改或学习 React Native 等新技能。

按照这份分步指南,使用 Capacitor 将您的 SvelteKit 应用转换为移动应用,并可选使用 Capgo 原生导航、过渡效果和 iOS 布局指南。

关于 Capacitor

CapacitorJS 是一款变革性工具!它可以轻松集成到任何 Web 项目中,将您的应用包裹在原生 webview 中,并为您生成原生 Xcode 和 Android Studio 项目。其插件通过 JavaScript 桥接提供对相机等原生设备功能的访问。

Capacitor 让您无需复杂配置或陡峭的学习曲线即可创建出色的原生移动应用。其轻量的 API 和精简的功能使其易于集成到您的项目中。您会惊讶于使用 Capacitor 实现功能完整的原生应用有多简单!

准备你的 SvelteKit 应用

要创建新的 SvelteKit 应用,请运行以下命令:

npm create svelte@latest my-app
cd my-app
npm install
npm run build

运行 build 命令后,你应该会看到一个新的 dist 项目根目录下的文件夹。

稍后 Capacitor 会用到这个文件夹,但现在我们需要先正确配置它。

将 Capacitor 添加到你的 SvelteKit 应用

要将任何 Web 应用打包成原生移动容器,我们需要先完成几个初始步骤。之后,只需运行一条 sync 命令。

首先,安装 Capacitor CLI 作为开发依赖,并在项目中完成配置。设置过程中,你可以按“enter”接受 name 和 bundle ID 的默认值。

接下来,安装核心包以及 iOS 和 Android 平台相关的包。

最后,添加平台,Capacitor 会在项目根目录下为每个平台创建文件夹:

# Install the Capacitor CLI locally
npm install -D @capacitor/cli

# Initialize Capacitor in your SvelteKit project
npx cap init

# Install the required packages
npm install @capacitor/core @capacitor/ios @capacitor/android

# Add the native platforms
npx cap add ios
npx cap add android

此时,你应该能看到新的 iOS 以及 Android 文件夹出现在你的 SvelteKit 项目中。

这些都是真正的原生项目!

之后要访问 Android 项目,需要安装 Android Studio 中的错误日志. 对于 iOS,你需要一台 Mac,并安装 Xcode 的 Mac.

此外,你还需要找到 capacitor.config.ts 项目中的文件,其中包含同步时用到的一些基本 Capacitor 设置。你唯一需要注意的是 webDir,它必须指向构建命令的输出结果。目前该配置不正确。

要修复此问题,请打开 capacitor.config.ts 文件并更新 webDir:

import { CapacitorConfig } from '@capacitor/cli'

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'my-app',
  webDir: 'build',
}

export default config

既然我们已经更新了 Capacitor 设置,接下来下载合适的静态适配器包,把 SvelteKit 项目改成静态应用:

npm i -D @sveltejs/adapter-static

安装完包后,我们需要修改 svelte.config.js 文件,把 auto-adapter 改为 static:

import adapter from '@sveltejs/adapter-static'
import { vitePreprocess } from '@sveltejs/kit/vite'

/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
  preprocess: vitePreprocess(),

  kit: {
    // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
    // If your environment is not supported or you settled on a specific environment, switch out the adapter.
    // See https://kit.svelte.dev/docs/adapters for more information about adapters.
    adapter: adapter({
      // default options are shown. On some platforms
      // these options are set automatically — see below
      pages: 'build',
      assets: 'build',
      fallback: null,
      precompress: false,
      strict: true
    })
  }
}

export default config

使用 svelte.config.js 更新后,我们需要添加一个 prerender 选项,通过创建 +layout.js 页面到 src/routes 然后只需将以下 export 添加到 +layout.js:

export const prerender = true

添加并更新 +layout.js 页面后,我们需要添加移动端平台,并重新构建项目以生成 build 文件夹

你可以运行以下命令来完成:

npm run build
npx cap sync

第一条命令 npm run build 将构建你的 SvelteKit 项目并复制静态 build,而第二条命令 npx cap sync 会将所有 Web code 同步到原生平台的对应位置,以便在 App 中显示。

此外,sync 命令可能会更新原生平台并安装插件,因此当你安装新的 Capacitor 插件,就该运行 npx cap sync 再次尝试。

不知不觉间,你已经完成了整个流程,现在让我们在真机上看看应用吧!

构建并部署原生应用

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

如果你刚接触原生移动开发,可以使用 Capacitor CLI 轻松打开这两个原生项目:

npx cap open ios
npx cap open android

原生项目配置好后,将应用部署到已连接的设备非常简单。在 Android Studio 中,只需等待一切就绪,无需更改任何设置即可将应用部署到已连接的设备。示例如下:

android-studio-run

在 Xcode 中,你需要配置签名账户,以便将应用部署到真机,而不只是模拟器。如果你以前没操作过,Xcode 会引导你完成整个流程(但同样需要加入 Developer Program)。之后,只需点击运行,即可在顶部选中的已连接设备上运行应用。示例如下:

xcode-run

恭喜!您已成功将 SvelteKit Web 应用部署到移动设备上。示例如下:

sveltekit-mobile-app

不过,在开发阶段还有更快的方法……

Capacitor 热重载

到现在,你大概已经习惯了现代框架的热重载,好消息是,你也能拥有同样的功能 在移动设备上 只需极少配置!

启用对本地托管应用的热重载访问 在你的网络上 通过让 Capacitor 应用从特定 URL 加载内容来实现。

第一步是确定你的本地 IP 地址。如果你使用的是 Mac,可以在终端运行以下命令来查看:

ipconfig getifaddr en0

在 Windows 上运行:

ipconfig

然后找到 IPv4 地址。

我们可以通过向我们的配置中再添加一个条目,让 Capacitor 直接从服务器加载应用 capacitor.config.ts 文件:

import { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'my-app',
  webDir: 'dist',
  bundledWebRuntime: false,
  server: {
    url: 'http://192.168.x.xx:3000',
    cleartext: true
  }
};

export default config;

请务必使用 正确的 IP 和端口,如上文示例所示。

现在,我们可以通过将这些更改复制到我们的原生项目中来应用它们:

npx cap copy

本指南中介绍的 copy 命令类似于 sync,但它只会 将 web 文件夹中的更改复制过来 以及配置,而不会更新 native 项目。

现在你可以通过 Android Studio 或 Xcode 再次部署你的 App。之后,如果你修改了 Svelte App 中的内容, App 将会自动重新加载 并显示更改!

请记住 如果你安装了新的插件(例如 camera),仍然需要重新构建你的 native 项目。这是因为 native 文件发生了变化,无法即时完成。

请注意,你应该在配置中使用正确的 IP 和端口。上方的 code 代码块展示了默认的 SvelteKit 端口,仅供演示使用。

使用 Capacitor 插件

我们来看看如何实际使用一个 Capacitor 插件,前面已经提过几次。为此,我们可以运行以下命令安装一个简单的插件:

npm i @capacitor/share

这个 分享插件其实没什么特别的,但它能调起原生分享对话框!现在我们只需要在应用中导入这个 package 并调用 share() 函数即可。让我们把 src/routes/index.svelte 修改为:

<script>
  import { Share } from '@capacitor/share';

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

<h1>Welcome to SvelteKit and Capacitor!</h1>
<button on:click={share}>Share now!</button>

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

npx cap sync

点击按钮后,你就能看到精美的原生分享对话框弹出啦!

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

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

我多年来一直在使用 Ionic 来构建跨平台应用,但把它和 SvelteKit 集成很 hacky,而且当你已经有了 Tailwind CSS.

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

  • @capgo/capacitor-native-navigation — 原生导航栏、iOS 上的 Liquid Glass 标签栏,以及 Android 上的毛玻璃标签栏样式。你的 SvelteKit 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 }) => {
  goto(`/${id}`);
});

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

<script>
  import { goto } from '$app/navigation';
  import { routerOutlet, page, setDirection } from '@capgo/capacitor-transitions/svelte';
  import '@capgo/capacitor-transitions';

  function openSettings() {
    setDirection('forward');
    goto('/settings');
  }
</script>

<cap-router-outlet use:routerOutlet>
  <cap-page use:page>
    <cap-content slot="content">
      <slot />
    </cap-content>
  </cap-page>
</cap-router-outlet>

将路由页面包裹在 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

在 src/app.css:

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

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

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

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

确保 viewport meta 标签已正确应用

在 src/app.html,在……中设置 viewport meta 标签 <head>:

<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />

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

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

html,
body,
body {
  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: 'build',
  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 是基于现有 Web 项目构建原生应用的绝佳选择,它提供了一种简单的方式来共享 code 并保持一致的 UI。

此外,通过引入 Capgo,为应用添加 Live Updates 变得更加简单,确保用户始终能获得最新功能和 Bug 修复。

如果你想了解如何将 Capgo 添加到 SvelteKit 应用,请阅读下一篇文章:

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

继续阅读《使用 SvelteKit 和 Capacitor 构建移动应用》

如果你正在使用 使用 SvelteKit 和 Capacitor 构建移动应用 规划 CI/CD 自动化,并将其与 Capgo CI/CD 集成 用于 Capgo CI/CD 中的产品工作流, Capgo Native Build 用于 Capgo Native Builds 中的产品工作流, Capgo 集成 用于 Capgo 集成中的产品工作流, CI/CD 集成 了解 CI/CD 集成的实现细节,以及 GitHub Actions 集成 有关 GitHub Actions 集成的实现细节。

为 Capacitor 应用提供 Live Updates

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

博客最新动态

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