OpenHarmony开发案例:【分布式遥控器】

2024-04-17 06:12

本文主要是介绍OpenHarmony开发案例:【分布式遥控器】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 1.概述

目前家庭电视机主要通过其自带的遥控器进行操控,实现的功能较为单一。例如,当我们要在TV端搜索节目时,电视机在遥控器的操控下往往只能完成一些字母或数字的输入,而无法输入其他复杂的内容。分布式遥控器将手机的输入能力和电视遥控器的遥控能力结合为一体,从而快速便捷操控电视。

分布式遥控器的实现基于OpenHarmony的分布式能力和RPC通信能力,UI使用eTS进行开发。如下图所示,分别用两块开发板模拟TV端和手机端。

  1. 分布式组网后可以通过TV端界面的Controller按钮手动拉起手机端的遥控界面,在手机端输入时会将输入的内容同步显示在TV端搜索框,点击搜索按钮会根据输入的内容搜索相关节目。
  2. 还可以通过点击方向键(上下左右)将焦点移动到我们想要的节目上,再点击播放按钮进行播放,按返回按钮返回TV端主界面。
  3. 同时还可以通过手机遥控端关机按钮同时关闭TV端和手机端界面。

UI效果图如下:

图1 TV端主页默认页面

  • 图2 手机端遥控页面

    • 图3 TV端视频播放页面

 说明:  本示例涉及使用系统接口,需要手动替换Full SDK才能编译通过,具体操作可参考[替换指南]。

2.搭建OpenHarmony环境

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:

  1. [获取OpenHarmony系统版本]:标准系统解决方案(二进制)。

    以3.1版本为例:

  2. 搭建烧录环境。

    1. [完成DevEco Device Tool的安装]
    2. [完成RK3568开发板的烧录]
    3. 鸿蒙开发文档指导:gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或这复制转到。
  3. 搭建开发环境。

    1. 开始前请参考[工具准备],完成DevEco Studio的安装和开发环境配置。
    2. 开发环境配置完成后,请参考[使用工程向导]创建工程(模板选择“Empty Ability”),选择JS或者eTS语言开发。
    3. 工程创建完成后,选择使用[真机进行调测])。

搜狗高速浏览器截图20240326151450.png

3.分布式组网

本章节以系统自带的音乐播放器为例(具体以实际的应用为准),介绍如何完成两台设备的分布式组网。

  1. 硬件准备:准备两台烧录相同的版本系统的RK3568开发板A、B。

  2. 开发板A、B连接同一个WiFi网络。

    打开设置-->WLAN-->点击右侧WiFi开关-->点击目标WiFi并输入密码。

  3. 将设备A,B设置为互相信任的设备。

    • 找到系统应用“音乐”。

    • 设备A打开音乐,点击左下角流转按钮,弹出列表框,在列表中会展示远端设备的id。选择远端设备B的id,另一台开发板(设备B)会弹出验证的选项框。

    • 设备B点击允许,设备B将会弹出随机PIN码,将设备B的PIN码输入到设备A的PIN码填入框中。

    配网完毕。

4.代码结构解读

本篇Codelab只对核心代码进行讲解,首先来介绍下整个工程的代码结构:

  • MainAbility:

    • model:数据模型。

      • RemoteDeviceModel.ets:获取组网内的设备列表模型。
      • PicData.ets:图片信息数据。
      • PicDataModel.ets:图片信息模型。
      • ConnectModel.ets:连接远端Service和发送消息模型。
    • pages:存放TV端各个页面。

      • TVindex.ets:TV端主页面。
      • VideoPlay.ets:TV端视频播放页面。
  • PhoneAbility:存放应用手机控制端主页面。

    • pages/PhoneIndex.ets:手机控制端主页面。
  • ServiceAbility:存放ServiceAbility相关文件。

    • service.ts:service服务,用于跨设备连接后通讯。
  • resources :存放工程使用到的资源文件。

    • resources/rawfile:存放工程中使用的图片资源文件。
  • config.json:配置文件。

5.实现TV端界面

在本章节中,您将学会开发TV端默认界面和TV端视频播放界面,示意图参考第一章图1和图3所示。

建立数据模型,将图片ID、图片源、图片名称和视频源绑定成一个数据模型。详情代码可以查看MainAbility/model/PicData.ets和MainAbility/model/PicDataModel.ets两个文件。

  1. 实现TV端默认页面布局和样式。

    • 在MainAbility/pages/TVIndex.ets 主界面文件中添加入口组件。页面布局代码如下:

      // 入口组件
      @Entry
      @Component
      struct Index {private letters: string[] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']private source: string@State text: string = ''@State choose: number = -1build() {Flex({ direction: FlexDirection.Column }) {TextInput({text: this.text, placeholder: 'Search' }).onChange((value: string) => {this.text = value})Row({space: 30}) {Text('Clear').fontSize(16).backgroundColor('#ABB0BA').textAlign(TextAlign.Center).onClick(() => {this.text = ''}).clip(true).borderRadius(10)Text('Backspace').fontSize(16).backgroundColor('#ABB0BA').textAlign(TextAlign.Center).onClick(() => {this.text = this.text.substring(0, this.text.length - 1)}).clip(true).borderRadius(10)Text('Controller').fontSize(16).backgroundColor('#ABB0BA').textAlign(TextAlign.Center).onClick(() => {......}).clip(true).borderRadius(10)}Grid() {ForEach(this.letters, (item) => {GridItem() {Text(item).fontSize(20).backgroundColor('#FFFFFF').textAlign(TextAlign.Center).onClick(() => {this.text += item}).clip(true).borderRadius(5)}}, item => item)}.rowsTemplate('1fr 1fr 1fr 1fr').columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr').columnsGap(8).rowsGap(8).width('75%').height('25%').margin(5).backgroundColor('#D2D3D8').clip(true).borderRadius(10)Grid() {ForEach(this.picItems, (item: PicData) => {GridItem() {PicGridItem({ picItem: item })}}, (item: PicData) => item.id.toString())}.rowsTemplate('1fr 1fr 1fr').columnsTemplate('1fr 1fr').columnsGap(5).rowsGap(8).width('90%').height('58%').backgroundColor('#FFFFFF').margin(5)}.width('98%').backgroundColor('#FFFFFF')}
      }

    • 其中PicGridItem将PicItem的图片源和图片名称绑定,实现代码如下:

      // 九宮格拼图组件
      @Component
      struct PicGridItem {private picItem: PicDatabuild() {Column() {Image(this.picItem.image).objectFit(ImageFit.Contain).height('85%').width('100%').onClick(() => {......})})Text(this.picItem.name).fontSize(20).fontColor('#000000')}.height('100%').width('90%')}
      }

  2. 实现TV端视频播放界面。

    • 在MainAbility/pages/VideoPlay.ets 文件中添加组件。页面布局代码如下:

      import router from '@system.router'
      @Entry
      @Component
      struct Play {
      // 取到Index页面跳转来时携带的source对应的数据。private source: string = router.getParams().sourcebuild() {Column() {Video({src: this.source,}).width('100%').height('100%').autoPlay(true).controls(true)}}
      }

    • 在MainAbility/pages/TVIndex.ets中,给PicGridItem的图片添加点击事件,点击图片即可播放PicItem的视频源。实现代码如下:

            Image(this.picItem.image).......onClick(() => {router.push({uri: 'pages/VideoPlay',params: { source: this.picItem.video }})})

6.实现手机遥控端界面

在本章节中,您将学会开发手机遥控端默认界面,示意图参考第一章图2所示。

  • PhoneAbility/pages/PhoneIndex.ets 主界面文件中添加入口组件。页面布局代码如下:

    @Entry
    @Component
    struct Index {build() {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {Row() {Image($rawfile('TV.png')).width(25).height(25)Text('华为智慧屏').fontSize(20).margin(10)}// 文字搜索框TextInput({ placeholder: 'Search' }).margin(20).onChange((value: string) => {if (connectModel.mRemote){......}})Grid() {GridItem() {// 向上箭头Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('up.png')).width(80).height(80)}.onClick(() => {......}).width(80).height(80).backgroundColor('#FFFFFF')}.columnStart(1).columnEnd(5)GridItem() {// 向左箭头Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('left.png')).width(80).height(80)}.onClick(() => {......}).width(80).height(80).backgroundColor('#FFFFFF')}GridItem() {// 播放键Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('play.png')).width(60).height(60)}.onClick(() => {......}).width(80).height(80).backgroundColor('#FFFFFF')}GridItem() {// 向右箭头Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('right.png')).width(70).height(70)}.onClick(() => {......}).width(80).height(80).backgroundColor('#FFFFFF')}GridItem() {// 向下箭头Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('down.png')).width(70).height(70)}.onClick(() => {......}).width(80).height(80).backgroundColor('#FFFFFF')}.columnStart(1).columnEnd(5)}.rowsTemplate('1fr 1fr 1fr').columnsTemplate('1fr 1fr 1fr').backgroundColor('#FFFFFF').margin(10).clip(new Circle({ width: 325, height: 325 })).width(350).height(350)Row({ space:100 }) {// 返回键Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('return.png')).width(40).height(40)}.onClick(() => {......}).width(100).height(100).backgroundColor('#FFFFFF')// 关机键Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('off.png')).width(40).height(40)}.onClick(() => {......}).width(100).height(100).backgroundColor('#FFFFFF')// 搜索键Button({ type: ButtonType.Circle, stateEffect: true }) {Image($rawfile('search.png')).width(40).height(40)}.onClick(() => {......}).width(100).height(100).backgroundColor('#FFFFFF')}.padding({ left:100 })}.backgroundColor('#E3E3E3')}
    }

7.实现分布式拉起和RPC通信

在本章节中,您将学会如何拉起在同一组网内的设备上的FA,并且连接远端Service服务。

  1. 首先通过TV端拉起手机端界面,并将本端的deviceId发送到手机端。

    • 点击TV端主页上的"Controller"按钮,增加.onClick()事件。调用RegisterDeviceListCallback()发现设备列表,并弹出设备列表选择框CustomDialogExample,选择设备后拉起远端FA。CustomDialogExample()代码如下:

      // 设备列表弹出框
      @CustomDialog
      struct CustomDialogExample {@State editFlag: boolean = falsecontroller: CustomDialogControllercancel: () => voidconfirm: () => voidbuild() {Column() {List({ space: 10, initialIndex: 0 }) {ForEach(DeviceIdList, (item) => {ListItem() {Row() {Text(item).width('87%').height(50).fontSize(10).textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF).onClick(() => {onStartRemoteAbility(item);this.controller.close();})}}.editable(this.editFlag)}, item => item)}}.width('100%').height(200).backgroundColor(0xDCDCDC).padding({ top: 5 })}
      }

    • 点击设备弹出框内的Text组件会调用onStartRemoteAbility()方法拉起远端FA(手机端),将TV端的deviceId传给手机端,并连接手机端的Service。因此在featureAbility.startAbility()成功的回调中也要调用onConnectRemoteService()方法。这里将连接远端Service和发送消息抽象为ConnectModel,详细代码可查看MainAbility/model/ConnectModel.ets文件中onConnectRemoteService()方法。onStartRemoteAbility()方法的代码如下:

      function onStartRemoteAbility(deviceId) {AuthDevice(deviceId);let numDevices = remoteDeviceModel.deviceList.length;if (numDevices === 0) {prompt.showToast({message: "onStartRemoteAbility no device found"});return;}var params = {remoteDeviceId: localDeviceId}var wantValue = {bundleName: 'com.example.helloworld0218',abilityName: 'com.example.helloworld0218.PhoneAbility',deviceId: deviceId,parameters: params};featureAbility.startAbility({want: wantValue}).then((data) => {// 拉起远端后,连接远端serviceconnectModel.onConnectRemoteService(deviceId)});
      }

    • 需要注意的是,配置文件config.json中ServiceAbility的属性visible要设置为true,代码如下:

      "abilities": [...{"visible": true,"srcPath": "ServiceAbility","name": ".ServiceAbility","icon": "$media:icon","srcLanguage": "ets","description": "$string:description_serviceability","type": "service"}
      ],

  2. 成功拉起手机端界面后,通过接收TV端传过来的deviceId连接TV端的Service。在手机端的生命周期内增加aboutToAppear()事件,在界面被拉起的时候读取对方的deviceId并调用onConnectRemoteService()方法,连接对方的Service,实现代码如下:

      async aboutToAppear() {await featureAbility.getWant((error, want) => {// 远端被拉起后,连接对端的serviceif (want.parameters.remoteDeviceId) {let remoteDeviceId = want.parameters.remoteDeviceIdconnectModel.onConnectRemoteService(remoteDeviceId)}});}

  3. 建立一个ServiceAbility处理收到的消息并发布公共事件,详细代码请看ServiceAbility/service.ts文件。TV端订阅本端Service的公共事件,并接受和处理消息。

    • 创建SubscribeEvent(),实现代码如下:
     subscribeEvent() {let self = this;// 用于保存创建成功的订阅者对象,后续使用其完成订阅及退订的动作var subscriber;// 订阅者信息var subscribeInfo = {events: ["publish_change"],priority: 100};// 设置有序公共事件的结果代码回调function SetCodeCallBack() {}// 设置有序公共事件的结果数据回调function SetDataCallBack() {}// 完成本次有序公共事件处理回调function FinishCommonEventCallBack() {}// 订阅公共事件回调function SubscribeCallBack(err, data) {let msgData = data.data;let code = data.code;// 设置有序公共事件的结果代码subscriber.setCode(code, SetCodeCallBack);// 设置有序公共事件的结果数据subscriber.setData(msgData, SetDataCallBack);// 完成本次有序公共事件处理subscriber.finishCommonEvent(FinishCommonEventCallBack)// 处理接收到的数据data......// 创建订阅者回调function CreateSubscriberCallBack(err, data) {subscriber = data;// 订阅公共事件commonEvent.subscribe(subscriber, SubscribeCallBack);}// 创建订阅者commonEvent.createSubscriber(subscribeInfo, CreateSubscriberCallBack);}
    }
    • 在TV端的生命周期内增加aboutToAppear()事件,订阅公共事件,实现代码如下:
      async aboutToAppear() {this.subscribeEvent();}

  4. 成功连接远端Service服务后,在手机遥控器端进行按钮或者输入操作都会完成一次跨设备通讯,消息的传递是由手机遥控器端的FA传递到TV端的Service服务。这里将连接远端Service和发送消息抽象为ConnectModel,详细代码可查看MainAbility/model/ConnectModel.ets文件中sendMessageToRemoteService()方法。

8.设置遥控器远端事件

手机端应用对TV端能做出的控制有:向上移动、向下移动、向左移动、向右移动、确定、返回、关闭。在手机端按键上增加点击事件,通过sendMessageToRemoteService()的方法发送到TV端Service。TV端根据发送code以及数据,进行数据处理,这里只展示TV端数据处理部分的核心代码:

// code = 1时,将手机遥控端search框内数据同步到TV端
if (code == 1) {self.text = data.parameters.dataList;
}
// code = 2时,增加选中图片效果
if (code == 2) {// 如果在图片序号范围内就选中图片,否则不更改var tmp: number = +data.parameters.dataList;if ((self.choose + tmp <= 5) && (self.choose + tmp >= 0)) {self.choose += tmp;}
}
// code = 3时,播放选中图片对应的视频
if (code == 3) {self.picItems.forEach(function (item) {if (item.id == self.choose) {router.push({uri: 'pages/VideoPlay',params: { source: item.video }})}})
}
// code = 4时,回到TV端默认页面
if (code == 4) {router.push({uri: 'pages/TVIndex',})
}
// code = 5时,关闭程序
if (code == 5) {featureAbility.terminateSelf()
}
// code = 6时,搜索图片名称并增加选中特效
if (code == 6) {self.picItems.forEach(function (item) {if (item.name == self.text) {self.choose = Number(item.id)}})
}

鸿蒙开发岗位需要掌握那些核心要领?

目前还有很多小伙伴不知道要学习哪些鸿蒙技术?不知道重点掌握哪些?为了避免学习时频繁踩坑,最终浪费大量时间的。

自己学习时必须要有一份实用的鸿蒙(Harmony NEXT)资料非常有必要。 这里我推荐,根据鸿蒙开发官网梳理与华为内部人员的分享总结出的开发文档。内容包含了:【ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战】等技术知识点。

废话就不多说了,接下来好好看下这份资料。

如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。鸿蒙OpenHarmony知识←前往。下面是鸿蒙开发的学习路线图。

针对鸿蒙成长路线打造的鸿蒙学习文档。鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,帮助大家在技术的道路上更进一步。

其中内容包含:

《鸿蒙开发基础》鸿蒙OpenHarmony知识←前往

  1. ArkTS语言
  2. 安装DevEco Studio
  3. 运用你的第一个ArkTS应用
  4. ArkUI声明式UI开发
  5. .……

《鸿蒙开发进阶》鸿蒙OpenHarmony知识←前往

  1. Stage模型入门
  2. 网络管理
  3. 数据管理
  4. 电话服务
  5. 分布式应用开发
  6. 通知与窗口管理
  7. 多媒体技术
  8. 安全技能
  9. 任务管理
  10. WebGL
  11. 国际化开发
  12. 应用测试
  13. DFX面向未来设计
  14. 鸿蒙系统移植和裁剪定制
  15. ……

《鸿蒙开发实战》鸿蒙OpenHarmony知识←前往

  1. ArkTS实践
  2. UIAbility应用
  3. 网络案例
  4. ……

最后

鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行!

这篇关于OpenHarmony开发案例:【分布式遥控器】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/910998

相关文章

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

客户案例:安全海外中继助力知名家电企业化解海外通邮困境

1、客户背景 广东格兰仕集团有限公司(以下简称“格兰仕”),成立于1978年,是中国家电行业的领军企业之一。作为全球最大的微波炉生产基地,格兰仕拥有多项国际领先的家电制造技术,连续多年位列中国家电出口前列。格兰仕不仅注重业务的全球拓展,更重视业务流程的高效与顺畅,以确保在国际舞台上的竞争力。 2、需求痛点 随着格兰仕全球化战略的深入实施,其海外业务快速增长,电子邮件成为了关键的沟通工具。

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta