记录--uniapp开发安卓APP视频通话模块初实践
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
视频通话SDK用的即构的,uniapp插件市场地址
推送用的极光的,uniapp插件市场地址
即构音视频SDK
uniapp插件市场的貌似是有些问题,导入不进项目,直接去官网下载,然后放到项目下的 nativeplugins
目录下,在配置文件中填入即构后台的appID和AppSign,接下来就可以开干了
准备两个页面
首页:/pages/index/index
// 新建一个按钮
<button @click="sendVideo">发送视频邀请</button>// 发送事件,主动发送直接进入下一个页面即可
sendVideo(){uni.navigateTo({url: '/pages/call/call'})
}
通话页:pages/call/call
这个页面会复杂一点
注意这个页面为
nvue
页面
先把所有代码都列出来,再一一做说明
<template><view><view v-if="status === 1" class="switch-bg" :style="{'height': pageH + 'px'}"><view class="top-info u-flex" style="flex-direction: row;"><image src="http://cdn.u2.huluxia.com/g3/M02/32/81/wKgBOVwN9CiARK1lAAFT4MSyQ3863.jpeg" class="avatar"></image><view class="info u-flex u-flex-col u-col-top"><text class="text">值班中心</text><text class="text" style="margin-top: 10rpx;">正在呼叫</text></view></view><view class="switch-handle u-flex u-row-center" style="flex-direction: row; justify-content: center;"><image src="/static/hang_up.png" class="img" @click="hangUp"></image></view></view><view v-if="status === 2" class="switch-bg" :style="{'height': pageH + 'px'}"><view class="top-info u-flex" style="flex-direction: row;"><image src="http://cdn.u2.huluxia.com/g3/M02/32/81/wKgBOVwN9CiARK1lAAFT4MSyQ3863.jpeg" class="avatar"></image><view class="info u-flex u-flex-col u-col-top"><text class="text">值班中心</text><text class="text" style="margin-top: 10rpx;">邀请您视频聊天</text></view></view><view class="switch-handle"><view class="u-flex" style="justify-content: flex-end; flex-direction: row; padding-right: 10rpx; padding-bottom: 30rpx;"><text style="font-size: 26rpx; color: #fff; margin: 10rpx;">切到语音接听</text><image src="/static/notice.png" style="width: 64rpx; height: 52rpx;"></image></view><view class="u-flex u-row-center u-row-between" style="flex-direction: row; justify-content: space-between;"><image src="/static/hang_up.png" class="img" @click="hangUp"></image><image src="/static/switch_on.png" class="img" @click="switchOn"></image></view></view></view><view v-if="status === 3" style="background-color: #232323;" :style="{'height': pageH + 'px'}"><view style="flex-direction: row; flex-wrap: wrap;"><zego-preview-view class="face" style="width: 375rpx; height: 335rpx;"></zego-preview-view><view v-for="(stream, index) in streamList" :key="index" style="flex-direction: row; flex-wrap: wrap;"><zego-view :streamID="stream.streamID" style="width: 375rpx; height: 335rpx;"></zego-view></view></view><view class="switch-handle"><view style="flex-direction: row; justify-content: center; padding-bottom: 30rpx;"><text style="font-size: 26rpx; color: #fff; margin: 10rpx;">{{minute}}:{{seconds}}</text></view><view style="flex-direction: row; justify-content: space-between;"><view style="align-items: center;"><view class="icon-round"><image src="/static/notice.png" class="icon1" mode=""></image></view><text class="h-text">切到语音通话</text></view><view style="align-items: center;"><image src="/static/hang_up.png" class="img" @click="hangUp"></image><text class="h-text">挂断</text></view><view style="align-items: center;"><view class="icon-round" @click="changeCamera"><image src="/static/change_camera.png" class="icon2" mode=""></image></view><text class="h-text">转换摄像头</text></view></view></view></view></view>
</template><script>// #ifdef APP-PLUSvar jpushModule = uni.requireNativePlugin("JG-JPush")import ZegoExpressEngine from '../../zego-express-video-uniapp/ZegoExpressEngine';import {ZegoScenario} from '../../zego-express-video-uniapp/impl/ZegoExpressDefines'import {AppID,AppSign} from '../../zegoKey.js'var instance = ZegoExpressEngine.createEngine(AppID, AppSign, true, 0);// #endifexport default {data() {return {status: 1, // 1: 主动呼叫;2: 被呼叫pageH: '', // 页面高度innerAudioContext: null, // 音乐对象streamList: [],msg_id: '', // 推送消息idmsg_cid: '', // 推送cidroomID: 'dfmily110001',publishStreamID: uni.getStorageSync('userinfo').nickname,userID: uni.getStorageSync('userinfo').nickname, userName: uni.getStorageSync('userinfo').nickname, camera_dir: 'before', // 摄像头 before 前置,after 后置};},destroyed: () => {console.log('destroyed');ZegoExpressEngine.destroyEngine();},mounted() {var client = uni.getSystemInfoSync()if (client.platform == 'android') {//安卓事先请求摄像头、麦克风权限var nativeEngine = uni.requireNativePlugin('zego-ZegoExpressUniAppSDK_ZegoExpressUniAppEngine');nativeEngine.requestCameraAndAudioPermission();}},onLoad(opt) {this.getSysInfo();this.playAudio();if(opt.status == 2){ // 带参数 status=2时代表被呼叫this.status = parseInt(opt.status)}if(!opt.status){ // 主动呼叫、需要发推送消息this.getPushCid();}this.initZegoExpress();},onBackPress() {// return true;this.innerAudioContext.stop();this.logout();},methods: {getSysInfo() { // 获取手机信息let sys = uni.getSystemInfoSync()this.pageH = sys.windowHeight},playAudio() { // 播放音乐this.innerAudioContext = uni.createInnerAudioContext();this.innerAudioContext.autoplay = true;this.innerAudioContext.src = '/static/message.mp3';this.innerAudioContext.onPlay(() => {console.log('开始播放');});},stopAudio(){ // 停止播放音乐if (this.innerAudioContext) {this.innerAudioContext.stop()}},hangUp() { // 挂断this.stopAudio();this.sendCustomCommand(500)this.revocationPushMsg();this.logout();uni.navigateBack({delta:1})},switchOn() { // 接通this.stopAudio();this.status = 3this.sendCustomCommand(200)},changeCamera() { // 切换摄像头var instance = ZegoExpressEngine.getInstance();if (this.camera_dir == 'before') {instance.useFrontCamera(false)this.camera_dir = 'after'} else if (this.camera_dir == 'after') {instance.useFrontCamera(true)this.camera_dir = 'before'}},sendCustomCommand(msg){ // 发送自定义信令var instance = ZegoExpressEngine.getInstance();instance.sendCustomCommand(this.roomID, msg, [{"userID": this.userID,"userName": this.userName}], res => {console.log(res)});},getPushCid(){ // 极光推送cid获取uni.request({url: 'https://api.jpush.cn/v3/push/cid',header: {'Authorization': 'Basic ' + this.encode('appKey:masterSecret')},success: (res) => {this.msg_cid = res.data.cidlist[0]this.sendPushMsg();}})},revocationPushMsg(){ // 撤销推送uni.request({url: 'https://api.jpush.cn/v3/push/' + this.msg_id,method: 'DELETE',header: {'Authorization': 'Basic ' + this.encode('appKey:masterSecret')},success: (res) => {console.log(res)}})},sendPushMsg(idArr) {uni.request({url: 'https://api.jpush.cn/v3/push',method: 'POST',header: {'Authorization': 'Basic ' + this.encode('appKey:masterSecret')},data: {"cid": this.msg_cid,"platform": "all","audience": {"registration_id": ['160a3797c8ae473a331']},"notification": {"alert": "邀请通话","android": {},"ios": {"extras": {"newsid": 321}}}},success: (res) => {this.msg_id = res.data.msg_id}})},initZegoExpress(){ // 初始化// instance.startPreview();instance.on('roomStateUpdate', result => {console.log('From Native roomStateUpdate:' + JSON.stringify(result));if (result['state'] == 0) {console.log('房间断开')} else if (result['state'] == 1) {console.log('房间连接中')} else if (result['state'] == 2) {console.log('房间连接成功')}});instance.on('engineStateUpdate', result => {if (result == 0) {console.log('引擎启动')} else if (result['state'] == 1) {console.log('引擎停止')}});instance.on('roomStreamUpdate', result => {var updateType = result['updateType'];if (updateType === 0) {var addedStreamList = result['streamList'];this.streamList = this.streamList.concat(addedStreamList);for (let i = 0; i < addedStreamList.length; i++) {console.log('***********&&&&', addedStreamList[i].streamID)var streamID = addedStreamList[i].streamID;var instance = ZegoExpressEngine.getInstance();instance.startPlayingStream(streamID);}} else if (updateType === 1) {this.removeStreams(result['streamList']);}});instance.on('roomUserUpdate', result => {var updateType = result['updateType'];if (updateType === 0) {this.userID = result.userList[0].userIDthis.userName = result.userList[0].userName// this.userList = this.userList.concat(result['userList']);} else if (updateType === 1) {// this.removeUsers(result['userList']);}});instance.on('IMRecvCustomCommand', result => {var fromUser = result['fromUser'];var command = result['command'];// console.log(`收到${fromUser.userID}的消息:${JSON.stringify(result)}`)if(result.command == 200){console.log('接听视频通话')this.status = 3this.stopAudio();}else if(result.command == 500){console.log('拒绝通话')uni.navigateBack({delta: 1})}});this.login();this.publish();},login() { // 登录房间var instance = ZegoExpressEngine.getInstance();instance.loginRoom(this.roomID, {'userID': this.userID,'userName': this.userName});},logout() { // 退出房间var instance = ZegoExpressEngine.getInstance();instance.logoutRoom(this.roomID);this.destroyEngine();},publish() { // 推流var instance = ZegoExpressEngine.getInstance();instance.startPublishingStream(this.publishStreamID);instance.setVideoConfig({encodeWidth: 375,encodeHeight: 336})},destroyEngine() {ZegoExpressEngine.destroyEngine(boolResult => {this.streamList = [];});},removeStreams(removedStreams) { // 删除流let leg = this.streamList.lengthfor (let i = leg - 1; i >= 0; i--) {for (let j = 0; j < removedStreams.length; j++) {if (this.streamList[i]) {if (this.streamList[i].streamID === removedStreams[j].streamID) {this.streamList.splice(i, 1)continue; //结束当前本轮循环,开始新的一轮循环}}}}},encode: function(str) {// 对字符串进行编码var encode = encodeURI(str);// 对编码的字符串转化base64var base64 = btoa(encode);return base64;},}}
</script><style lang="scss">.switch-bg {position: relative;background-color: #6B6B6B;}.top-info {padding: 150rpx 35rpx;flex-direction: row;align-items: center;.avatar {width: 150rpx;height: 150rpx;border-radius: 10rpx;}.info {padding-left: 18rpx;.text {color: #fff;font-size: 26rpx;}}}.switch-handle {position: absolute;bottom: 100rpx;left: 0;right: 0;padding: 0 85rpx;.img {width: 136rpx;height: 136rpx;}.icon-round {align-items: center;justify-content: center;width: 136rpx;height: 136rpx;border: 1rpx solid #fff;border-radius: 50%;.icon1 {width: 64rpx;height: 52rpx;}.icon2 {width: 60rpx;height: 60rpx;}}.h-text {margin-top: 10rpx;font-size: 26rpx;color: #fff;}}
</style>
说明:
代码中的masterSecret
需要修改为极光后台的masterSecret
,appKey
需要修改为极光后台的appKey
view
部分:
status=1
中的为主动呼叫方进入页面是初始显示内容,最重要的是 hangUp
方法,用来挂断当前邀请
status=2
中的为被邀请者进入页面初始显示的内容,有两个按钮,一个hangUp
挂断,一个switchOn
接听
status=3
中为接听后显示的内容(显示自己与对方视频画面)
script
部分:
最开始五行是引入相关SDK的。极光推送、即构音视频
在 onLoad
中有一个判断语句,这个就是用于判断进入页面时是主动呼叫方还是被动答应方的,显示不同内容
if(opt.status == 2){ // 带参数 status=2时代表被呼叫this.status = parseInt(opt.status)
}
if(!opt.status){ // 主动呼叫、需要发推送消息this.getPushCid();
}
sendCustomCommand
是用来在房间内发送自定义信令的,用于通知另一个人是接听了还是挂断了通话
getPushCid
是获取极光推送的cid,避免重复发送推送消息(极光推送)
changeCamera
切换摄像头
revocationPushMsg
撤销推送(主动呼叫方挂断通话)
sendPushMsg
发推送消息
initZegoExpress
初始化即构音视频SDK相关,与官网demo,此处我做了小改动
login
登录即构房间
logout
退出即构房间
publish
推流
destroyEngine
销毁音视频实例
removeStreams
删除流
encode
base64转码
在App.vue中进行极光推送的初始化
onLaunch: function() {console.log('App Launch')// #ifdef APP-PLUSif (uni.getSystemInfoSync().platform == "ios") {// 请求定位权限let locationServicesEnabled = jpushModule.locationServicesEnabled()let locationAuthorizationStatus = jpushModule.getLocationAuthorizationStatus()console.log('locationAuthorizationStatus', locationAuthorizationStatus)if (locationServicesEnabled == true && locationAuthorizationStatus < 3) {jpushModule.requestLocationAuthorization((result) => {console.log('定位权限', result.status)})}jpushModule.requestNotificationAuthorization((result) => {let status = result.statusif (status < 2) {uni.showToast({icon: 'none',title: '您还没有打开通知权限',duration: 3000})}})jpushModule.addGeofenceListener(result => {let code = result.codelet type = result.typelet geofenceId = result.geofenceIdlet userInfo = result.userInfouni.showToast({icon: 'none',title: '触发地理围栏',duration: 3000})})jpushModule.setIsAllowedInMessagePop(true)jpushModule.pullInMessage(result => {let code = result.codeconsole.log(code)})jpushModule.addInMessageListener(result => {let eventType = result.eventTypelet messageType = result.messageTypelet content = result.contentconsole.log('inMessageListener', eventType, messageType, content)uni.showToast({icon: 'none',title: JSON.stringify(result),duration: 3000})})}jpushModule.initJPushService();jpushModule.setLoggerEnable(true);jpushModule.addConnectEventListener(result => {let connectEnable = result.connectEnableuni.$emit('connectStatusChange', connectEnable)});jpushModule.addNotificationListener(result => {let notificationEventType = result.notificationEventTypelet messageID = result.messageIDlet title = result.titlelet content = result.contentlet extras = result.extrasconsole.log(result)this.$util.router(`/pages/public/answer?status=2`)});jpushModule.addCustomMessageListener(result => {let type = result.typelet messageType = result.messageTypelet content = result.contentconsole.log(result)uni.showToast({icon: 'none',title: JSON.stringify(result),duration: 3000})})jpushModule.addLocalNotificationListener(result => {let messageID = result.messageIDlet title = result.titlelet content = result.contentlet extras = result.extrasconsole.log(result)uni.showToast({icon: 'none',title: JSON.stringify(result),duration: 3000})})// #endif
},
不要忘了在最开始引入极光推送的插件
var jpushModule = uni.requireNativePlugin("JG-JPush")
官方demo的代码,直接拿过来了。。
其中最重要的就是下面这段,用来监听获取推送消息的,这里如果收到推送消息自动跳转至通话页面,也就是上面status=2的状态下
jpushModule.addNotificationListener(result => {let notificationEventType = result.notificationEventTypelet messageID = result.messageIDlet title = result.titlelet content = result.contentlet extras = result.extrasconsole.log(result)this.$util.router(`/pages/call/call?status=2`)
});
https://juejin.cn/post/6954172658195906567
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
记录--uniapp开发安卓APP视频通话模块初实践相关推荐
- uniapp 开发安卓App实现高德地图路线规划导航
文章目录 技术概述 技术详述 问题与解决 我的总结 参考文献 技术概述 描述这个技术是做什么的/什么情况下会使用到这个技术,学习该技术的原因,技术的难点在哪里.控制在50-100字内. uniapp的 ...
- uniApp开发安卓App调试与打包
总结一下auniapp开发安卓app的调试方式及打包; 代码编程查看文档即可.; 1通过vue-cli方式初始化项目 参考地址: https://uniapp.dcloud.io/quickstart ...
- uni-app开发安卓APP运行到真机,未检测到手机或模拟器
本文以 EMUI10 手机系统为例(华为.荣耀手机) 问题 在开发安卓应用时,因为安卓模拟器性能较差,uni-app官方不推荐使用,所以选择真机运行的方式调试. 上手就踩了一个小坑,在 HBuilde ...
- uniapp开发安卓APP测试实现微信支付(初学者都能轻松get)
前提条件 上代码 打包运行 注意bug!! 这里我们是前后端各一个人测试,这里分享一点前端的代码知识以及我们在测试过程中遇到的bug 前提条件 首先我们要去微信开放平台申请微信开放APP的应用包名和应 ...
- uni-app 开发安卓app踩坑记录
uni-app离线打包android -- 官方文档 Android studio打包apk后弹窗提示"打包时未添加ui模块" 在工程应用目录的build.gradle文件中bui ...
- uniapp开发安卓app 实现nfc读卡功能
<template><view class="content"><view class="box"><view cla ...
- 安卓上比较好的python开发软件-手机随时随地写Python,还可以开发安卓APP,太厉害了!...
python, 近五年最为火爆的编程语言,语法优雅,类库丰富,一行代码即可完成 Java 十行代码量. 本次,舞剑来推荐一款手机端使用 Python 的APP. QPython QPython是安卓上 ...
- python安卓版汉化版-手机随时随地写Python,还可以开发安卓APP,太厉害了!
python, 近五年最为火爆的编程语言,语法优雅,类库丰富,一行代码即可完成 Java 十行代码量. 本次,舞剑来推荐一款手机端使用 Python 的APP. QPython QPython是安卓上 ...
- python手机版安卓-手机随时随地写Python,还可以开发安卓APP,太厉害了!
python, 近五年最为火爆的编程语言,语法优雅,类库丰富,一行代码即可完成 Java 十行代码量. 本次,舞剑来推荐一款手机端使用 Python 的APP. QPython QPython是安卓上 ...
最新文章
- Python:SQLMap源码精读—基于错误的盲注(error-based blind)
- Linux常用命令——paste
- MVC学习笔记1 MVC概述
- 梦中女孩,不知还能不能再见你一面
- 升级openssh版本
- Oracle9i数据库DataGuard实施及维护手册3
- 编译使用CEF2623遇到的错误解决办法
- 注意力(Attention)
- MATLAB中.m文件命名规则
- JS之获取银行卡信息
- SafeArea的使用
- 为什么使用VO,DTO,BO
- 亲历医院蹩脚程序(项目)的糟糕
- 如何使用光盘启动计算机,如何从光驱启动?从光驱启动方法介绍【图文详解】...
- contiki之list(1)
- mysql:列类型之float、double
- 数据结构c语言进制转换八进制,C语言数据结构中数制转换实例代码
- 杰理-手表-AC701-watch-马达振动一次
- 如何实现小投资大回报?
- 光电二极管放大电路的应用
热门文章
- 比我们优秀的人比我们还努力,你有什么资格不去奋斗
- Ural 1998 The old Padawan(二分)
- lms算法的matlab实现,LMS算法的MATLAB实现
- 北邮复试 | 北邮机试往年题汇总 | 计算机院 | 网研院 | 网安院 | 软院
- 揭秘:网赚圈很红的“小说项目”!月入十万的裂变套路
- Unity3d游戏制作 建模与蒙皮
- 300M无线路由器 TL-WR842N - TP-LINK官方网站
- matlab-diary函数用法之一
- 《电商网络营销理论与实战》
- 无人机从零到一(组装、校准到起飞)