结合声网 Web UIKit 与 Remix 框架,实现多人视频通话场景

Remix 是一个基于 React 的全栈式 Web 框架,利用分布式系统进行部署。Remix 的独特之处在于它从服务器加载数据和预渲染网页的方式。

对于 React 这样的纯客户端框架来说,这种方式有点奇怪。我们会使用服务器从加密凭证中生成 Token,并在声网 Web UIKit 这个客户端库中使用它们。


前期准备

  • 声网开发者账户(点击这里免费注册)
  • Node.js LTS
  • 对 React 框架有深度了解


设置

创建一个新的 Remix 项目

大家可以在 GitHub 上找到完成版项目。创建 Remix 项目的步骤:打开终端,执行 npx create-remix@latest demo,选择下列选项,得到一个用 TypeScript 编写的基本 app 模板:

❯ npx create-remix@latest demo
? What type of app do you want to create? Just the basics
? Where do you want to deploy? Choose Remix if you're unsure, it's easy to change deployment targets. Remix App Server
? TypeScript or JavaScript? TypeScript
? Do you want me to run `npm install`? Yes

键入 cd demo,进入项目目录。执行下列代码,安装声网 Web UIKit 和 token 库:

注意:撰写本文时 agora-react-uikit 的最新版本是 v1.1.0

npm i agora-react-uikit agora-access-token

设置声网证书

登录声网开发者账户,在声网控制台点击 Project Management tab

  1. 点击“创建”;
  2. 输入项目名称;
  3. 选择安全模式;
  4. 将 .env.example 文件重命名为 .env.;
  5. 从声网项目页面复制你的 App ID 和 App 证书,如下:
APP_ID=c0cXXXXXXXXXXX
CERTIFICATE=c18XXXXXXXXXXX

设置完成!现在你可以执行 npm run dev,在 localhost:3000 上启动 Remix 服务器。

项目结构

模板结构如下:

├── app
│   ├── entry.client.tsx
│   ├── entry.server.tsx
│   ├── root.tsx
│   └── routes
│       └── index.tsx
├── package.json
├── public
│   ...


开始 Coding

Remix 的其中一个突出特点是嵌套路由。我们为视频通话创建一个动态路由,这样你就会有一个example.com/channel/<channelName>,进入同一 <channelName> 的用户可以相互交流。该路由从我们的声网凭证中生成并托管 Token。你可以增加一个安全层,限制认证用户对 /channel 路由的访问。

使用 Remix 和声网 Web UIKit,只需几分钟就可以将项目上线!

创建动态路由

要在 example.com/channel/<yourChannelName> 上托管动态视频通话,我们需要为该路由创建一个新文件 /app/routes/channel/$channel.tsx:

import { RtcRole, RtcTokenBuilder, RtmRole, RtmTokenBuilder } from "agora-access-token";
import { useEffect, useState } from "react";
import { json, LoaderFunction, useLoaderData } from "remix";
import Videocall from '~/components/videocall.client'

export type loaderData = {
  rtcToken: string;
  rtmToken: string;
  appId: string;
  channel: string;
  username: number;
}

export const loader: LoaderFunction = async ({params}) => {
  const { APP_ID, CERTIFICATE } = process.env as unknown as { APP_ID: string, CERTIFICATE: string }
  console.log(APP_ID, CERTIFICATE)
  const channel = params.channel as string
  const username = Date.now()
  const time = Math.floor(username / 1000) + 600
  const rtcToken = RtcTokenBuilder.buildTokenWithUid(APP_ID, CERTIFICATE, channel, 0, RtcRole.PUBLISHER, time)
  const rtmToken = RtmTokenBuilder.buildToken(APP_ID, CERTIFICATE, String(username), RtmRole.Rtm_User, time)
  const data: loaderData = { rtcToken, appId: APP_ID, channel, rtmToken, username }
  return json(data);
};

...

要生成视频通话组件的道具,需要创建一个 loader 函数,该函数使用 .env 文件中的 App ID 和证书生成 RTC 和 RTM Token。我们从 params 道具中获得路由 channel 的名称,从 data 对象中创建一个 JSON 字符串,从 loader 函数返回:

...
export default function Index() {
  const [mounted, setMounted] = useState(false);
  const jsonData: loaderData = useLoaderData()
  const { rtcToken, rtmToken, appId, channel, username } = jsonData

  useEffect(() => {
    setMounted(true);
  }, []);

  return (
    <div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
      <h1>Videocall</h1>
      <div style={{ display: 'flex', flex: 1 }}>
        {mounted && <Videocall appId={appId} channel={channel} rtcToken={rtcToken} rtmToken={rtmToken} username={username} />}
      </div>
    </div>
  );
}

现在,我们来为频道路由创建 React 组件。我们将使用 mounted 状态变量,该状态变量在 useEffect Hook 里设置为 true。这样,只在文件在浏览器中渲染时,才会渲染 Videocall 组件。我们可以使用 Remix 的 userLoaderData Hook 来获取 jsonData。我们将从对象中提取值,并将这些值传递给一个名为 Videocall 的组件。最后,返回一些 JSX 来渲染我们接下来会创建的 <Videocall> 组件。

视频通话组件

创建一个新文件 /app/components/videocall.client.tsx,并使用声网 Web UIKit 来创建视频通话:

import AgoraUIKit, { layout } from 'agora-react-uikit';
import { loaderData } from '~/routes/channel/$channel';

export default function Videocall(props: loaderData) {
    const { appId, channel, rtcToken, rtmToken, username } = props

    return (
        <div style={{display: 'flex', flex: 1, height: '80vh'}}>
            <AgoraUIKit
                rtcProps={{ appId, channel, token: rtcToken, layout: layout.grid}}
                rtmProps={{ token: rtmToken, uid: String(username), displayUsername: true, username: 'User' + String(username).slice(-3) }}
            />
        </div>
    )
}

然后,访问我们传递给此组件的数据道具,并将它们传递给 <AgoraUIKit> 组件。 该组件负责处理视频通话的所有逻辑,不需要其他代码。如果你想了解如何自定义设计和功能(例如直播),可以查看这篇文章

找到 localhost:3000/channel/test,查看你的视频通话用户界面。你可以在单独窗口中打开该网址,模拟视频通话并测试。


总结

欢迎在 GitHub 上为此 Remix demo 或为 UIKit 的功能请求开启拉动请求,或创建问题来报告错误。我们期待着大家的贡献。我们也有 AndroidiOSReact NativeFlutter 版本的 UIKit,欢迎大家查看并试用。



原文作者:Ekaansh Arora
原文链接:https://www.agora.io/en/blog/adding-video-calling-to-a-remix-app-using-the-agora-web-uikit/
推荐阅读
相关专栏
SDK 教程
167 文章
本专栏仅用于分享音视频相关的技术文章,与其他开发者和声网 研发团队交流、分享行业前沿技术、资讯。发帖前,请参考「社区发帖指南」,方便您更好的展示所发表的文章和内容。