一、简介
本样例是基于即时通讯(Instant messaging,简称IM)服务实现的OpenAtom OpenHarmony(简称“OpenHarmony”)应用,允许两人或多人使用互联网即时地传递文字、图片、文件、语音、emoji等讯息,可应用于各类聊天场景,为人们带来更加及时高效的通讯体验。
此外即时通讯平台具备较高的定制化特点,适用于多种行业,客户可以根据自己的需求来定制,实现即时通讯的内部私有化。
设备端:DAYU200(RK3568)开发板,OpenHarmony 3.1 release系统。
二、即时通讯实现原理
想要实现多个设备之间的无障碍即时通讯,需要多台终端设备、终端应用和服务器配合一起使用。首先应该将终端应用安装到终端设备上,用户通过应用向服务器申请注册账号。随后,用户可以通过账号进行查找,添加其他好友,并向好友发送文字、图片、文件、语音、emoji等讯息。用户发送的讯息会先送达服务器,由服务器判断其好友的状态(离线/在线),然后选择发送或者暂时缓存消息等操作。最后,好友的终端应用接收到消息。
实现即时通讯的设备需求:安装应用的终端设备、网络环境和云端服务器。
前提条件:用户将应用安装在终端设备上,并且拥有注册账号,且需要通讯的用户也成功注册了账号并且添加了好友。
通讯原理:用户在安装了应用的终端设备上编辑信息(文字、图片、文件、语音、emoji等),通过网络将消息发送至云端服务器。当对方用户在线时,云端服务器将把消息推送给对方用户,对方用户安装了应用的终端设备也将接收到信息。当对方用户不在线时,信息将被暂时缓存在云端服务器。
三、4步实现多人即时通讯
(1) 通讯功能通讯功能是通过TCP协议实现的,我们将通讯接口connect()、send()、receive()的实现放置在CPP文件中,通过NAPI的方式对JS层暴露接口。
• connect():客户端和服务器建立连接;
• send():消息发送功能
• receive():消息接收功能;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | //建立TCP连接 if (connect(sock_cli, ( struct sockaddr *)&servaddr, sizeof (servaddr)) < 0) { napi_create_int32(env, 0, &result); } else { napi_create_int32(env, 1, &result); OH_LOG_INFO(LOG_APP, "C++ 接收线程启动" ); startRec(); } //发送消息 if (send(sock_cli, data, strlen(data),0) == -1) { OH_LOG_INFO(LOG_APP, "zjf == send() : -1" ); napi_create_int32(env, 0, &result); } else { OH_LOG_INFO(LOG_APP, "zjf == send() : !-1" ); napi_create_int32(env, 1, &result); } //接收消息 getStep(queue0,sharedMessage); //取出一条消息 const char *c_s=sharedMessage.c_str(); //换为char*形式处理 napi_value result; napi_create_string_utf8(env, c_s, sharedMessage.length(), &result); std:: string ().swap(sharedMessage); //清空字符串 |
(2) 文件消息的发送与接收
文件转发是即时通讯办公场景下的重要功能。样例中的文件功能支持文件消息的发送、接收和下载。用户通过点击聊天界面的“+”按钮,选择“文件”按钮,完成本地文件的浏览,随后可以选择是否将文件发送给好友。这个功能的实现包括三个步骤:(1)文件的选择;(2)文件上传到服务器;(3)文件的接收。
• 文件上传
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | //文件的选择 let file1 = {filename: this .$app.$def.uid + '-' + FILE_URL, name: 'file' , uri: FILE_URL, type:fileType } let fileId = this .guid(); let data = {}; let header = { "filename" : this .selectedFileName.toString()}; //文件上传到服务器 request.upload({ url: "http://" + this .$app.$def.ip + "/file/fileUpload?fileSignature=" + fileId + "&uid=" + this .$app.$def.uid + "&fileType=" + this .$app.$def.chatData[ this .idx].unRead, header: header, method: "POST" , files: [file1], data: [data] }).then((data) => { uploadTask = data; uploadTask. on ( 'headerReceive' , function callback(headers){ _this.socketSendFile(fileId, timestamp); }); }). catch ((err) => { console.error( 'fileSelect=====Failed to request the upload. Cause: ' + JSON.stringify(err)); }) //文件的接收 let downloadConfig = { //下载参数 url: fileUrl, header: {}, enableMetered: true , enableRoaming: true , filePath: '/data/storage/el2/base/haps/entry/files/' + downloadFileName, networkType: request.NETWORK_WIFI } request.download(downloadConfig, (err, data) => { if (err) { return ; } downloadTask = data; //下载完成 downloadTask. on ( 'complete' , function callback() { prompt.showToast({ message: '下载文件成功!' , duration: 1000, }); }); |
(3) 语音消息的发送与接收
用户通过点击聊天界面的录制按钮,完成语音的录制,随后可以选择是否将语音发送给好友。这个功能的实现包括三个步骤:(1)语音的录制;(2)语音上传到服务器;(3)语音的接收。
图片消息的发送与语音消息的发送步骤相同,文章中不再赘述。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | //语音录制 startRecorder(config, callback) { if ( typeof ( this .audioRecorder) !== 'undefined' ) { this .audioRecorder. on ( 'prepare' , () => { this .audioRecorder.start() }) this .audioRecorder. on ( 'start' , () => { callback() }) this .audioRecorder.prepare(config) } else { logger.info(`${TAG} case failed, audiorecorder is null `) } } //录制好的语音文件的位置 let srcPath = 'internal://cache/' + this .mainData.file + '.wav' let file1 = { filename: this .$app.$def.uid + '-' + this .mainData.path, name: 'audio' , uri: srcPath, type: "wav" }; //语音消息发送到服务器 request.upload({ url: myurl, header: header, method: "POST" , files: [file1], data: [data] }).then((data) => { uploadTask = data; uploadTask. on ( 'headerReceive' , function callback(headers){ _this.sendAudio(audioId) }); uploadTask. on ( 'progress' , function callback(uploadedSize, totalSize) { console.info( "dialogPages=====upload totalSize:" + totalSize + " uploadedSize:" + uploadedSize); }); }). catch ((err) => { console.error( 'dialogPages=====Failed to request the upload. Cause: ' + JSON.stringify(err)); }) //语音的接收 let downloadConfig = { //下载参数 url: item.content.path, header: {}, enableMetered: true , enableRoaming: true , filePath: filePath, networkType: request.NETWORK_WIFI } let downloadTask; let _this = this request.download(downloadConfig, (err, data) => { if (err) { return ; } downloadTask = data; //下载完成 downloadTask. on ( 'complete' , function callback() { let audio = { content: { path: filePath } } _this.playAudio(audio) }); |
(4) emoji消息的发送与接收
emoji是即时通讯软件不可缺少的一部分,可以更加生动地表现用户的聊天情感。在样例中,用户通过点击聊天界面的emoji按钮,即可找到目前应用内支持的所有样式的emoji,随后可以选择具体样式并将其发送给好友。
1 2 3 4 5 6 7 8 9 10 11 12 13 | //引入emoji第三方组件 <element name= "emojiExpression" src= "../../common/components/emojiExpression/emojiExpression.hml" ></element> //第三方组件的展示布局 <div id= "moreContainer" if = "{{showFace}}" > <div id= "moreOneLine" > <div class = "moreFillGap" style= "flex: 1 1;" ></div> <text style= "left: 25fp; top: 10fp;" >所有表情</text> <emojiExpression></emojiExpression> <div class = "moreFillGap" style= "flex: 1 1;" ></div> </div> </div> |
四、即时通讯功能总结
本样例是基于OpenHarmony实现的即时通讯应用,目前已经支持文字、图片、文件、语音、emoji等讯息的快速发送与接收。除此之外还实现了好友的添加与删除、黑名单、安全登录、私聊/群聊、个人信息设置(二维码/头像等)等功能的全方面支持。
代码地址https://gitee.com/isrc_ohos/instant-message_ohos
五、相关参考链接
样例源码https://gitee.com/isrc_ohos/instant-message_ohos
OpenHarmony知识体系工作组https://gitee.com/openharmony-sig/knowledge
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析