暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

鸿蒙版“抖音”,体验贼好!

鸿蒙技术社区 2021-11-11
314

之前大家看过了 Java 版的《 HarmonyOS 分布式之仿抖音应用》,现在讲讲 JS 如何实现分布式仿抖音应用,通过 JS 方式开发视频播放,分布式设备迁移,评论,通过 Java 和 JS 交互,获取设备信息,选择设备信息做分布式迁移。


功能:分布式迁移到不同设备,视频进行评论,播放视频,可以像抖音一样切换视频,可以点赞,分享等操作。


开发版本:sdk6,DevEco Studio3.0 Beta1。


效果演示如下图:

主要代码


①视频播放


鸿蒙 js 中有专门【video】的组件,并且非常完善,可以直接使用:

https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-components-media-video-0000000000611764


    <video id='playerId{{ $idx }}' src='{{ $item.path }}' muted='false' autoplay='true'
           controls="false" onprepared='preparedCallback' onstart='startCallback' onpause='pauseCallback'
           onfinish='finishCallback' onerror='errorCallback' onseeking='seekingCallback'
           onseeked='seekedCallback'
           ontimeupdate='timeupdateCallback' style="object-fit : contain; width : 100%;"
           onlongpress='change_fullscreenchange' onclick="change_start_pause" loop='true'
           starttime="0"
            >

    </video>


js 代码中视频资源:

  list: [{
         path"/common/video/video1.mp4"
          },{
          path"/common/video/video2.mp4"
          }, {
          path"/common/video/video3.mp4"
          }, {
          path"/common/video/video4.mp4"
          }, {
          path"/common/video/video5.mp4"
           }, {
          path"/common/video/video6.mp4"
         }]


②仿抖音视频切换


有关视频切换的开发 js 中也提供了对应的组件【swiper】,可以直接使用来进行视频切换:

https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-components-container-swiper-0000000000611533


<!--index="{{ player_index }}"//设置当前的切换项 -->
<!--onchange="changeVideo"//切换监听 -->
<swiper class="swiper-content" id="swiper" index="{{ player_index }}"
           indicator="false" loop="true" digital="false" vertical="true" onchange="changeVideo">

       <stack class="stack-parent" for="list">
           <div class="videosource">
               <!--src='{{ $item.path }}'//设置视频资源路径-->
               <video id='playerId{{ $idx }}' src='{{ $item.path }}' muted='false' autoplay='true'
                      controls="false" onprepared='preparedCallback' onstart='startCallback' onpause='pauseCallback'
                      onfinish='finishCallback' onerror='errorCallback' onseeking='seekingCallback'
                      onseeked='seekedCallback'
                      ontimeupdate='timeupdateCallback' style="object-fit : contain; width : 100%;"
                      onlongpress='change_fullscreenchange' onclick="change_start_pause" loop='true'
                      starttime="0"
                       >

               </video>
           </div>
       </stack>
   </swiper>


③评论功能添加


评论功能使用了鸿蒙 js 中了两个组件 【list】(负责列表展示) 和 【input】(负责信息发送),可参见有关文档。
https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-components-container-list-0000000000611496


https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-components-basic-input-0000000000611673


评论功能有两部分,评论列表和评论发送输入框。

 <div class="pinglun" style="visibility : {{ ifhidden }};">
     <div style="height : 32%; background-color : transparent;" onclick="hideenbg">
         <text></text>
     </div>
     <!--列表展示-->
     <list class="todo-wrapper" divider="true" style="divider-color : darkgrey;">
         <!--list-item for="{{ todolist }}" class="todo-item" 循环遍历数据 显示item-->
         <list-item for="{{ todolist }}" class="todo-item">
             <div class="photo">
                 <image class="image-set" src="/common/images/science6.png"></image>
                 <text class="todo-title" style="font-size : 14fp; margin-left : 10px;">{{ $item.name }}
                 </text>
             </div>
             <text class="todo-title" style="font-size : 14fp; margin-top : 5px;">{{ $item.detail }}</text>
         </list-item>
     </list>
     <!--输入框信息发送-->
     <div class="butt">
         <!--onchange="change"//监听输入框信息变化-->
         <input id="input" class="input" type="text" value="{{ content }}" maxlength="20" enterkeytype="send"
                placeholder="{{ placecontent }}" onchange="change"
                onenterkeyclick="enterkeyClick">

         </input>
         <button class="last" onclick="sendmessage">发送</button>
     </div>
 </div>


功能实现逻辑:

   change(e) { // 监听输入框 信息变化 获取信息
       this.message = e.value;
       console.log("message===" + this.message)
   },

   sendmessage() { // 提交信息后组织数据 刷新界面
       this.todolist.push({
           name: '王者',
           detail: this.message,
       })
       this.content = "";
       this.message = "";
   },


④JS 和 Java 交互获取设备信息


在实现分布式设备迁移的时候查找 js 没有找到获取设备信息的有关接口,所以考虑通过 js 和 Java 相互调用实现。通过 jsFA 调用 Java PA机制,实现数据的获取和传递。

js 端实现如下:


重点:
  • Ability 类型,对应 PA 端不同的实现方式:0:Ability,1:Internal Ability。

  • syncOption PA 侧请求消息处理同步/异步选项:0:同步方式,默认方式,1:异步方式。
 initAction(code) {
     var actionData = {};
     actionData.firstNum = 1024;
     actionData.secondNum = 2048;
     var action = {};
     action.bundleName = "com.corecode.video.videoplayer";//包名
     action.abilityName = "com.corecode.video.videoplayer.DeviceInternalAbility";// 包名+类名
     action.messageCode = code;// 消息编码
     action.data = actionData;// 传递数据
     action.abilityType = 1;//  ability类型 
     action.syncOption = 1;//同步还是异步类型
     return action;
 },
 getLevelasync function ({
     try {
         var action = this.initAction(1001);
         var result = await FeatureAbility.callAbility(action);
         console.info(" result = " + result);
         this.deviceId = JSON.parse(JSON.parse(result).result);
         console.log("deviceId==" + this.deviceId)
         this.devicelist = "visible";
     } catch (pluginError) {
         console.error("getBatteryLevel : Plugin Error = " + pluginError);
     }
 }


Java 端实现如下:


Java 端需要创建一个 ability 服务继承 AceInternalAbility 具体是使用哪种类型,看上面的解释。


创建后需要注册,比如我创建的是 InternalAbility 这样注册:DeviceInternalAbility.register(this);

package com.corecode.video.videoplayer;
public class DeviceInternalAbility extends AceInternalAbility {
   private static final HiLogLabel TAG = new HiLogLabel(00"DeviceInternalAbility");
   private static final int CONNECT_ABILITY = 2000;
   private static final int DISCONNECT_ABILITY = 2001;
   private static final int SEND_MSG = 1001;
   private static final int SUCCESS_CODE = 0;
   private static final int FAIL_CODE = -1;
   private static DeviceInternalAbility INSTANCE;
   private String selectDeviceId;

   /**
    * default constructor
    *
    * @param context ability context
    */

   public DeviceInternalAbility(AbilityContext context) {
       super("com.corecode.video.videoplayer""com.corecode.video.videoplayer.DeviceInternalAbility");
   }

   public DeviceInternalAbility(String bundleName, String abilityName) {
       super(bundleName, abilityName);
   }

   public DeviceInternalAbility(String abilityName) {
       super(abilityName);
   }

   /**
    * setInternalAbilityHandler for DistributeInternalAbility instance
    *
    * @param context ability context
    */

   static void register(AbilityContext context) {
       INSTANCE = new DeviceInternalAbility(context);
       INSTANCE.setInternalAbilityHandler((code, data, reply, option) ->
               INSTANCE.onRemoteRequest(code, data, reply, option));
   }

   /**
    * destroy DistributeInternalAbility instance
    */

   private static void unregister() {
       INSTANCE.destroy();
   }

   /**
    * default destructor
    */

   private void destroy() {
   }

   /**
    * hand click request from javascript
    *
    * @param code   ACTION_CODE
    * @param data   data sent from javascript
    * @param reply  reply for javascript
    * @param option currently excessive
    * @return whether javascript click event is correctly responded
    */

   private boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
       Map<String, Object> replyResult = new HashMap<>();
       switch (code) {
           // send message to remote device, message contains controller command from FA
           case SEND_MSG: {
               ZSONObject dataParsed = ZSONObject.stringToZSON(data.readString());
               int message = dataParsed.getIntValue("message");
//                // SYNC
//                if (option.getFlags() == MessageOption.TF_SYNC) {
//                    reply.writeString(ZSONObject.toZSONString(result));
//                }
               // ASYNC
               // 返回结果当前仅支持String,对于复杂结构可以序列化为ZSON字符串上报
               Map<String, Object> result = new HashMap<String, Object>();
               result.put("result", MainAbility.getList());
               MessageParcel responseData = MessageParcel.obtain();
               responseData.writeString(ZSONObject.toZSONString(result));
               IRemoteObject remoteReply = reply.readRemoteObject();
               try {
                   remoteReply.sendRequest(0, responseData, MessageParcel.obtain(), new MessageOption());
               } catch (RemoteException exception) {
                   return false;
               } finally {
                   responseData.reclaim();
               }
               break;
           }
           // to invoke remote device's newsShare ability and send news url we transfer
           case CONNECT_ABILITY: {
               ZSONObject dataParsed = ZSONObject.stringToZSON(data.readString());
               selectDeviceId = dataParsed.getString("deviceId");
               break;
           }
           // when controller FA went to destroy lifeCycle, disconnect with remote newsShare ability
           case DISCONNECT_ABILITY: {
               unregister();
               break;
           }
           default:
               HiLog.error(TAG, "messageCode not handle properly in phone distributeInternalAbility");
       }
       return true;
   }

   private void assembleReplyResult(int code, Map<String, Object> replyResult, Object content, MessageParcel reply) {
       replyResult.put("code", code);
       replyResult.put("content", content);
       reply.writeString(ZSONObject.toZSONString(replyResult));
   }
}


js 调用后会进入 Java 的 onRemoteRequest 函数进行数据解析和组织,然后通过如下接口将需要的结果回传给 js 做界面展示和操作。

remoteReply.sendRequest(0, responseDataMessageParcel.obtain(), new MessageOption());


获取设备信息:

List<DeviceInfo> deviceInfos = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);


⑤分布式迁移


鸿蒙中分布式迁移真的是做到了强大,在 js 中只需要四个函数就能完成分布式迁移。

  onSaveData(saveData) { // 数据保存到savedData中进行迁移。
       var data = {
           list: this.list,
           player_index: this.player_index,
       };
       Object.assign(saveData, data)
   },
   onRestoreData(restoreData) {  // 收到迁移数据,恢复。
       console.info('==== onRestoreData ' + JSON.stringify(restoreData))
       this.list = restoreData.list
       this.player_index = restoreData.player_index

       this.$element('swiper').swipeTo({
           index: this.player_index
       });

   },
   onCompleteContinuation(code) { //迁移完成
       console.log("onCompleteContinuation===" + code)
   },
   onStartContinuation() {//迁移开始
       return true;
   },


迁移:上面的四个有关函数设置好后执行下面的接口就能实现分布式迁移了。

continueVideoAbility: async function ({
let conti = await FeatureAbility.continueAbility();
}


⑥权限


需要加上需要的权限:

 "reqPermissions": [
   {
     "reason""",
     "usedScene": {
       "ability": [
         "MainAbility"
       ],
       "when""inuse"
     },
     "name""ohos.permission.DISTRIBUTED_DATASYNC"
   },
   {
     "name""ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"
   },
   {
     "name""ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"
   },
   {
     "name""ohos.permission.GRT_BUNDLE_INFO"
   },
   {
     "name""ohos.permission.INTERNET"
   }
 ]


源码地址【 分布式仿抖音视频】:

https://gitee.com/dot_happydz_admin/video-player


作者:陈建朋
扫码报名今晚鸿蒙直播课

👇👇👇

👇点击关注鸿蒙技术社区👇
了解鸿蒙一手资讯


求分享

求点赞

求在看

数据库
文章转载自 鸿蒙技术社区,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

PHP网站源码盐田网站推广工具龙华网站推广吉祥建设网站龙华seo网站推广大鹏网站优化按天计费横岗网站搭建惠州网站推广工具惠州网站优化排名龙华网站改版南联SEO按天扣费大芬网站开发福永英文网站建设福田网站优化双龙百度网站优化排名南联seo网站推广石岩英文网站建设永湖企业网站改版大运网站排名优化坑梓如何制作网站塘坑外贸网站制作坪地网站优化推广横岗百姓网标王塘坑推广网站罗湖seo排名坪地网络推广松岗网络推广东莞优秀网站设计塘坑标王福永外贸网站设计大运模板推广歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

PHP网站源码 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化