# VideoPlayer
**Repository Path**: dot_happydz_admin/video-player
## Basic Information
- **Project Name**: VideoPlayer
- **Description**: 鸿蒙js开发分布式仿抖音视频。
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 5
- **Forks**: 0
- **Created**: 2021-10-19
- **Last Updated**: 2022-03-08
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 分布式仿抖音视频
#### 项目介绍
- 项目名称:分布式仿抖音视频
- 功能:可以实现分布式迁移到不同设备,可以对视频进行评论,可以播放视频,可以像抖音一样切换视频,可以点赞,分享等操作。
- 开发版本:sdk6,DevEco Studio3.0 Beta1
#### 效果演示

#### 开发简介
通过js方式开发视频播放,分布式设备迁移,评论,通过Java和js交互,获取设备信息,选择设备信息做分布式迁移。
#### 使用说明
下面通过几点说明:1,视频播放 2,仿抖音视频切换 3,评论功能添加 4,js和Java交互获取设备信息 ,5,分布式迁移
- 1、视频播放,鸿蒙js中有专门的组件,并且非常完善,可以直接使用(https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-components-media-video-0000000000611764)
```xml
```
js 代码中视频资源
```xml
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"
}],
```
- 2,仿抖音视频切换,有关视频切换的开发 js中也提供了对应的组件,可以直接使用来进行视频切换(https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-components-container-swiper-0000000000611533)
```xml
```
index="{{ player_index }}" 设置当前的切换项
onchange="changeVideo" 切换监听
src='{{ $item.path }}' 设置视频资源路径
- 3,评论功能添加,评论功能使用了鸿蒙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
```xml
{{ $item.name }}
{{ $item.detail }}
```
评论功能有两部分 评论列表和评论发送输入框。
onchange="change" 监听输入框信息变化
循环遍历数据 显示item
功能实现逻辑:
```xml
change(e) { // 监听输入框 信息变化 获取信息
this.message = e.value;
console.log("message===" + this.message)
},
sendmessage() { // 提交信息后组织数据 刷新界面
this.todolist.push({
name: '王者',
detail: this.message,
})
this.content = "";
this.message = "";
},
```
- 4,js和Java交互获取设备信息
在实现分布式设备迁移的时候 查找js没有找到获取设备信息的有关接口,所以考虑通过js和Java相互调用实现。
通过jsFA 调用 Java PA机制,实现数据的获取和传递。
js端实现:
```xml
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;
action.syncOption = 1;
return action;
},
getLevel: async 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);
}
}
```
通过相应 函数 getLevel 来组织 initAction中的数据 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;//同步还是异步类型
重点:
Ability类型,对应PA端不同的实现方式:
0:Ability 1:Internal Ability
syncOption PA侧请求消息处理同步/异步选项
0:同步方式,默认方式。 1:异步方式。
Java端实现:
Java 端需要创建一个 ability 服务 继承 AceInternalAbility 具体是使用哪种类型 看上面的解释。
创建后需要注册,比如我创建的是 InternalAbility 这样注册: DeviceInternalAbility.register(this);
```java
package com.corecode.video.videoplayer;
public class DeviceInternalAbility extends AceInternalAbility {
private static final HiLogLabel TAG = new HiLogLabel(0, 0, "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 函数进行数据解析和组织,然后通过接口:
remoteReply.sendRequest(0, responseData, MessageParcel.obtain(), new MessageOption());
将需要的结果回传给 js做界面展示和操作。
获取设备信息:
List deviceInfos = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
- 5,分布式迁移
鸿蒙中分布式迁移 真的是做到了强大,在js中只需要四个函数就能完成 分布式迁移。
```xml
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();
}
- 最后
需要加上 需要的权限:
```xml
"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"
}
]
```
#### 版权信息
Copyright [2021] [chenjianpeng of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.