之前大家看过了 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。
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;
},
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);
}
}
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(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 函数进行数据解析和组织,然后通过如下接口将需要的结果回传给 js 做界面展示和操作。
remoteReply.sendRequest(0, responseData, MessageParcel.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
全部0条评论
快来发表一下你的评论吧 !