本文档面向已经了解 面板小程序开发 的开发者,你需要充分的了解什么是面板小程序 产品功能 若您对上述概念有所疑问,我们推荐你去看一些预备知识。如果您已了解,可跳过本文。

理解关系

面板作为 IoT 智能设备在 App 终端上的产品形态,创建产品之前,首先来了解一下什么是面板,以及和产品、设备之间的关系。

  1. 面板 是运行在 智能生活 AppOEM App(涂鸦定制 App) 上的界面交互程序,用于控制 智能设备 的运行,展示 智能设备 实时状态。
  2. 产品面板智能设备 联系起来,产品描述了其具备的功能、在 App 上面板显示的名称、智能设备拥有的功能点等。
  3. 智能设备 是搭载了 涂鸦智能模组 的设备,通常在设备上都会贴有一张二维码,使用 智能生活 App 扫描二维码,即可在 App 中获取并安装该设备的控制 面板
  4. 产品面板设备 之间的关系可参考下图。

IPC 通用模板使用 SDM(Smart Device Model) 开发,关于 SDM 相关可以 查看 SDM 文档

相关概念

产品名称:云台摄像机

需求原型

  1. 支持视频实时预览功能(清晰度切换视频全屏等)
  2. 支持对讲功能
  3. 支持录制视频视频截取功能
  4. 支持云台聚焦功能
  5. 支持回放相册
  6. 支持明、暗两种主题(跟随 APP)

首先需要创建一个电工类产品,定义产品有哪些功能点,然后面板中再根据这些功能点一一实现。

进入IoT 平台,点击左侧产品菜单,产品开发,创建产品,选择标准类目 -> 摄像机 -> 云台摄像机:

选择功能点,这里根据自己需求选择即可,这些功能未选择不影响视频预览。

🎉 在这一步,我们创建了一个名为 Camera的云台摄像机产品。

开发者平台创建面板小程序

这部分我们在 小程序开发者 平台上进行操作,注册登录 小程序开发者平台

拉取并运行模板项目

面板模板仓库

拉取项目

git clone https://github.com/Tuya-Community/tuya-ray-demo.git
        

进入 IPC 模板,直接通过 IDE 导入源码目录,并关联到创建的小程序。

cd ./examples/panel-ipc
        

导入项目到 IDE,并关联到已经创建的面板小程序与产品。

工程目录

上面的步骤我们已经初始化好了一个面板小程序的开发模板,下面我们介绍下工程目录。

├── src
          │ ├── api # api目录
          │ ├── app.config.ts # 自动生成配置
          │ ├── app.tsx # App 根组件
          │ ├── components # 组件目录
          │ ├── constant # 常量目录
          │ ├── config # 配置文件目录
          │ ├── devices # 智能设备模型目录
          │ │ ├── index.ts # 定义并导出智能设备模型
          │ │ └── schema.ts # 当前智能设备 DP 功能点描述,IDE 可自动生成
          │ ├── global.config.ts
          │ ├── hooks # 自定义 hooks 目录
          │ ├── i18n # 多语言目录
          │ ├── pages # 页面目录
          │ ├── redux # 状态管理
          │ ├── styles # 全局样式文件
          │ ├── utils # 工具库
          │ └── routes.config.ts # 路由配置
          │─── typings #业务类型定义目录
          │ └── sdm.d.ts #智能设备类型定义文件
        

依赖库

视频预览

1. 通过接口获取摄像头的配置信息

接口参数解析:

{
          "audioAttributes": [1, 2], // 设备能力 1:是否支持扬声器 2:是否支持对讲
          "callMode": [1, 2], // 支持对讲方式 0:未知;1:单向对讲;2:双向对讲
          "vedioClaritys": [2, 4], // 支持的清晰度 2:标清 4:高清
          "vedioClarity": 4 // 默认清晰度
          }
        

注:

2. 引入视频播放器

import { IpcPlayer as Player } from
          "@ray-js/components-ty-ipc";
          <View className={Styles.playerWrap}>
          {devInfo?.devId && ( // 获取到设备id之后再渲染播放器,避免无法出流情况
          <Player
          defaultMute={isMute} // 静音状态
          devId={devInfo?.devId} // 设备id
          onlineStatus={devInfo.isOnline} // 设备在线状态
          updateLayout={`${playerLayout}`} // 更新播放器位置及大小时更新此值
          onChangeStreamStatus={onChangeStreamStatus} // 流状态变化事件
          onCtx={getIpcPlayer} // player组件实例
          onPlayerTap={handlePlayerClick} // 点击组件事件
          clarity={videoClarityObj[mainDeviceCameraConfig.videoClarity]} // 视频清晰度
          privateState={dpState.basic_private || false} // 隐私模式
          />
          )}
          </View>;
        

播放器内部封装了从通道建立到视频预览一系列功能,相关 UI 均已实现,直接引入使用即可

录制截屏对讲等方法均挂载在组件实例上,可通过onCtx获取组件实例,模板内部将相关方法都封装到了/src/utils/util.ts文件

参考文档

摄像头通用设置页

// global.config.ts文件配置
          export const tuya = {
          window: {
          // 5.10以下版本配置右上角"点点点"设备详情跳转
          systemMenus: [
          {
          key: "system_setting",
          text: "xxx",
          isShow: true,
          },
          ],
          },
          // 5.10以上版本配置右上角"点点点"设备详情跳转
          functionalPages: {
          settings: {
          appid: "tycryc71qaug8at6yt",
          },
          },
          };

          // composeLayout.tsx
          const composeLayout = (Comp: React.ComponentType<any>) => {
          return class PanelComponent extends Component<Props, State> {
          onLaunch() {
          // 5.10以上版本监听右上角"点点点"设备详情跳转事件
          ty.onAppMore((e) => {
          if (!holdUp()) {
          openPanelApp();
          }
          });

          // 5.10以下版本监听右上角"点点点"设备详情跳转事件
          ty.onAppEvent((e) => {
          if (!holdUp()) {
          // 打开设置二级页
          if (e.key === "system_setting") {
          openPanelApp();
          }
          }
          });
          }
          };
          };

          // utils/index.ts
          import { preloadPanel, openPanel } from "@/utils/index";
          import { exitMiniProgram } from "@ray-js/ray";

          // 预下载面板小程序
          export const getPanelApp = () => {
          const { devInfo } = store.getState();
          preloadPanel({
          devId: devInfo.devId,
          productId: devInfo.productId, // 产品id
          productVersion: devInfo.pv, // 产品版本
          i18nTime: devInfo.time, // 面板多语言时间戳
          });
          };

          // 打开面板小程序
          export const openPanelApp = () => {
          const { devInfo, ipcCommon } = store.getState();
          const { mainDeviceCameraConfig } = ipcCommon;
          // mainDeviceCameraConfig 包含当前支持的对讲方式以及是否支持切换对讲,此信息通过接口获取

          openPanel(devInfo.devId, { mainDeviceCameraConfig }, (data) => {
          // 监听设置页传递的消息
          const { type } = data;
          const supportedAudioMode = data?.mainDeviceCameraConfig?.supportedAudioMode;
          switch (type) {
          case "changeTalkType":
          // 切换对讲方式,对讲方式存储到本地缓存
          Storage.setDevItem("talkType", supportedAudioMode).then(() => {
          store.dispatch(
          actions.common.mainDeviceCameraConfig({
          supportedAudioMode,
          })
          );
          });
          break;
          case "exitMiniProgram":
          // 退出小程序,关闭设置页的同时,关闭一级小程序
          setTimeout(() => {
          exitMiniProgram();
          }, 50);
          break;
          default:
          }
          });
          };
        

因摄像头产品功能都较为统一,已形成一套标准,所以针对摄像头设备专门实现一套摄像头设置页面

设置页面所呈现的相关功能与产品创建时所选择的功能相关

设置页面支持的功能如下:

若不想使用通用设置页,也可通过配置修改使用自定义设置页

主题

IPC 通用模板主题跟随 APP,支持两种主题

APP 主题切换:我的 - 设置 - 深色模式

全局主题样式在/scr/styles目录下,使用 less 变量的方式达到切换主题的目的

国际化

通用设置页与播放器使用的多语言是一级小程序的多语言,上传多语言时需将相应的多语言一并上传,字段信息在/src/i18n目录下

rem

小程序里的通用单位是 dp,但是此单位会跟随屏幕尺寸变化其比例会变化,在屏幕旋转时也会跟随变化,为了能在横屏下获得较好的体验,此处使用了 rem 单位