跳过主要内容
教程

使用React和Capacitor构建移动应用

了解如何使用React,Capacitor和Capgo Native Navigation, Transitions,和iOS布局最佳实践来构建移动应用

马丁·多纳迪尤

马丁·多纳迪尤

内容营销人员

使用React和Capacitor构建移动应用

本教程中,我们将从新建一个 React 应用程序开始,逐步过渡到使用 Capacitor 的原生移动开发。您还可以添加 Capgo 原生导航和过渡,使用 tailwind-capacitor 来实现安全区域。

Capacitor 允许您轻松将 React 网页应用程序转换为原生移动应用程序,无需进行重大修改或学习新的技能,如 React Native。

仅需几个简单的步骤,大多数 React 应用程序都可以转换为移动应用程序。

本教程将指导您完成整个过程,首先从新建一个 React 应用程序开始,然后将 Capacitor 引入,以便进入原生移动应用程序的领域。您还可以使用 Capgo 原生导航、过渡和 tailwind-capacitor 来实现安全区域。

关于 Capacitor

CapacitorJS 是一个革命性的工具!您可以轻松将其集成到任何 web 项目中,它将您的应用程序包装在一个原生 webview 中,生成原生的 Xcode 和 Android Studio 项目。其插件还提供访问原生设备功能的 JS 桥,如摄像头。

使用 Capacitor,您可以获得一个功能齐全的原生移动应用程序,无需进行复杂的设置或陡峭的学习曲线。其 API 和功能流线化使其成为轻松集成到您的项目中的理想选择。相信我,您将惊叹于如何轻松地使用 Capacitor 实现一个功能齐全的原生应用程序!

准备您的 React 应用程序

在本教程中,我们将使用最简单的方法来启动 React 应用程序:

npx create-react-app my-app

为了创建一个原生移动应用,我们需要将我们的项目 export 到一个文件中。因此,让我们在我们的 package.json 中添加一个简单的脚本,用于构建和

{
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }
}

export npm run build React 项目:

This folder will be used by Capacitor later on, but for now, we must set it up correctly.

Adding Capacitor to Your React App

此文件夹将由 __CAPGO_KEEP_0__ 后续使用,但现在我们必须正确设置它。 sync 将 __CAPGO_KEEP_0__ 添加到您的 React 应用程序中:

首先,我们可以将 Capacitor CLI 作为开发依赖项安装,并在项目中设置它。在设置过程中,您可以按“回车”键以接受名称和包ID的默认值。

接下来,我们需要安装核心包和iOS和Android平台的相关包。

最后,我们可以添加平台,Capacitor将在项目根目录创建每个平台的文件夹:

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

# Initialize Capacitor in your React 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

到目前为止,您应该能够在您的React项目中观察到新的 iosandroid 文件夹。

这些是真正的本机项目!

稍后要访问Android项目,您必须安装 Android Studio. For iOS, you need a Mac and should install Xcode.

Additionally, you should find a capacitor.config.ts 文件在你的项目中,包含一些基本的Capacitor设置,这些设置在同步过程中会被使用。需要注意的是 webDir,它必须指向你的构建命令的结果。目前它是不准确的。

为了修复这个问题,请打开 capacitor.config.json 文件并更新 webDir:

{
  "appId": "com.example.app",
  "appName": "my-app",
  "webDir": "out",
  "bundledWebRuntime": false
}

您可以通过执行以下命令来试验:

npm run build
npx cap sync

第一个命令 npm run build 将仅仅构建您的 React 项目并导出静态构建。

而第二个命令 npx cap sync 将同步所有的 web code 到原生平台的正确位置,以便在应用中显示。

此外,同步命令可能会更新原生平台并安装插件,因此当您安装新的 Capacitor 插件时 npx cap sync 需要重新运行

命令。

不经意间,您现在实际上已经完成了,所以让我们在设备上查看应用!

构建和部署原生应用程序 Xcode 需要安装 Android Studio 安装。另外,如果您计划将应用程序发布到应用商店,则需要为iOS和Android分别加入Apple Developer Program和Google Play Console。

如果您是native移动开发的新手,可以使用Capacitor CLI轻松打开两种native项目:

npx cap open ios
npx cap open android

一旦您设置了native项目,部署应用程序到连接设备就很容易了。在Android Studio中,只需等待所有内容就绪,然后您可以在不更改任何设置的情况下将应用程序部署到连接设备。以下是示例:

android-studio-run

在Xcode中,您需要设置签名账户才能将应用程序部署到真实设备,而不是仅仅在模拟器上运行。如果您之前没有这样做过,Xcode会引导您完成此过程(但请再次注意,您需要加入开发者计划)。然后,您只需点击播放即可在连接设备上运行应用程序,您可以在顶部选择设备。以下是示例:

xcode-run

恭喜!您已经成功将React web应用程序部署到移动设备。以下是示例:

react-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: 'out',
  bundledWebRuntime: false,
  server: {
    url: 'http://192.168.x.xx:3000',
    cleartext: true
  }
};

export default config;

请确保使用 正确的 IP 和端口,本例中我使用了默认的 React 端口。

现在,我们可以将这些更改应用到我们的原生项目中:

npx cap copy

命令与 copy 类似,但它只会 sync将对 web 文件夹和配置的更改复制过去,而不会更新原生项目。 您现在可以通过 Android Studio 或 Xcode 再次部署您的应用。之后,如果您在 React 应用中更改了什么 ,应用将自动重新加载

并显示更改! __CAPGO_KEEP_0__ __CAPGO_KEEP_1__

请注意 如果您安装了新插件,如摄像头插件,它仍然需要重新构建您的原生项目。这是因为原生文件发生了变化,不能在飞行中完成。

请注意,您应该在配置中使用正确的IP和端口。上面的code块显示了示例目的地的默认React端口。

使用Capacitor插件

让我们看看如何使用Capacitor插件的示例,这是我们之前提到的几次。要实现这一点,我们可以通过运行以下命令来安装一个相当简单的插件:

npm i @capacitor/share

没有什么特别的关于" 分享插件",但它仍然会弹出原生的分享对话框!现在,我们只需要导入包并调用 share() 函数即可。让我们将 src/App.js 修改为如下内容:

import React from 'react';
import { Share } from '@capacitor/share';

function App() {
  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>
      <h1>Welcome to React and Capacitor!</h1>
      <p>
        <h2>Cool channel</h2>
        <button onClick={() => share()}>Share now!</button>
      </p>
    </div>
  );
}

export default App;

如前所述,当安装新插件时,我们需要执行同步操作,然后重新部署应用到设备上。要实现这一点,请运行以下命令:

npx cap sync

点击按钮后,您可以亲眼目睹美丽的原生分享对话框的运行!

react-capacitor-share

接下来,您可以让应用程序在iOS和Android上感觉更原生,使用Capgo导航和过渡,并修复常见的iOS布局问题,例如水平溢出或裁剪安全区域。

原生感知UI与Capgo原生导航和过渡

我已经工作了几年, Ionic 来构建跨平台应用程序,但将其与React集成起来很hacky,并且很少值得在您已经有 Tailwind CSS.

For a native mobile feel in a React + Capacitor app, use Capgo plugins instead of web-only UI kits like Konsta 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 }) => {
  navigate(`/${id}`);
});

在应用壳中添加原生页面过渡:

import { useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import '@capgo/capacitor-transitions';
import { initTransitions, setDirection, setupRouterOutlet } from '@capgo/capacitor-transitions/react';

initTransitions({ platform: 'auto' });

export function AppShell() {
  const navigate = useNavigate();
  const outletRef = useRef<HTMLElement>(null);

  useEffect(() => {
    if (outletRef.current) {
      setupRouterOutlet(outletRef.current, { platform: 'auto', swipeGesture: 'auto' });
    }
  }, []);

  const openSettings = () => {
    setDirection('forward');
    navigate('/settings');
  };

  return <cap-router-outlet ref={outletRef}>{/* routes */}</cap-router-outlet>;
}

将路由页面包裹在 cap-router-outlet, cap-pagecap-content中, setDirection('forward')setDirection('back') 前导航。不要在原生导航拥有这些表面的情况下重复web头部或底部。

查看完整指南: 使用@capgo/capacitor-native-navigation 使用 @__CAPGO_KEEP_0__/__CAPGO_KEEP_1__-transitions Using @capgo/capacitor-transitions.

在 Tailwind CSS 中使用设备安全区域时,请使用

@__CAPGO_KEEP_0__/tailwind-__CAPGO_KEEP_1__ @capgo/tailwind-capacitor 上。它提供 tailwind-capacitor 有助于 npm 的 Tailwind 插件: safe-areas utilities and other Capacitor-friendly Tailwind plugins:

bun add -D tailwind-capacitor

使用类似于 src/index.css:

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

pt-safe, pb-safepx-safe 的实用工具,而不是随意使用 env(safe-area-inset-*) by hand. 该项目正在积极开发中 — 如果您的 React 设置中缺少某些内容, 在 GitHub 上打开一个 PR.

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

如果内容在 iOS 上被裁切、偏移或水平滚动, overflow-x: hidden 或仅仅调整视口标签通常无法解决问题。按照以下检查顺序进行工作.

确保视口元标签已正确应用

index.html 中添加视口元标签 <head>:

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

html,
body,
#root {
  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);
}

从根包装器中处理 iOS 安全区域 .app-shell创建一个单独的应用 shell 并在其中应用安全区域填充 — 不要在多个嵌套组件中进行填充:','将所有页面内容包装在','内。重复的安全区域填充在头部、模态窗口和布局包装器中通常会使 UI 看起来被裁切或过大。

使用 @capgo/tailwind-capacitor,您可以使用类似 pt-safe pb-safe px-safe 的工具来实现相同的填充效果

在 iOS 设备上设置 Capacitor contentInsetnever 首选项

在 iOS 设备上,优先使用原生边距禁用并让 CSS(或 Native Navigation 的) capacitor.config.ts控制安全区域: contentInsetMode: 'css'混合使用 __CAPGO_KEEP_0__ 的自动内容内边距和 CSS

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

Mixing Capacitor’s automatic content inset with CSS env(safe-area-inset-*) __CAPGO_KEEP_0__

在 Safari Web Inspector 中运行:

通常的罪魁祸首是使用 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 with w-full 可能。许多水平溢出问题来自 100vw / w-screen、重复的安全区域填充或固定宽度容器,而不是视口元标签本身。

结论

Capacitor 是基于现有 Web 项目构建原生应用的出色选择,提供了一个简单的方法来共享 code 并保持一致的 UI。

并且通过添加 Capgo让您轻松添加实时更新到您的应用程序,使您的用户始终可以访问最新的功能和bug修复。

如果您想学习如何将Capgo添加到您的React应用程序,请查看下一篇文章:

继续从使用React和Capacitor构建移动应用

如果您正在使用 使用React和Capacitor构建移动应用 来规划CI/CD自动化,连接它与 Capgo CI/CD 在Capgo CI/CD中为产品工作流程 Capgo Native Builds 在Capgo Native Builds中为产品工作流程 Capgo Integrations 为Capgo产品工作流程中的集成 CI/CD集成 为CI/CD集成中的实现细节 GitHub动作集成 为GitHub动作集成中的实现细节

实时更新 Capacitor 应用程序

当 web 层面 bug 活跃时,通过 Capgo 将修复推送到用户,而不是等待几天的应用商店审批。用户在后台接收更新,而本机更改保持在正常审批路径中。

立即开始

最新博客文章

Capgo 为您提供创建真正专业移动应用程序所需的最佳见解。