鸿蒙版JS如何实现分布式仿抖音应用

描述

   

之前大家看过了 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

 



<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">
               
               <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">
             <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">
         
         <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 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 result = new HashMap();
               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 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

 

责任编辑:haq
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分