這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 視頻通話SDK用的即構的,uniapp插件市場地址 推送用的極光的,uniapp插件市場地址 即構音視頻SDK uniapp插件市場的貌似是有些問題,導入不進項目,直接去官網下載,然後放到項目下的 nativeplugins 目錄下,在配 ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
視頻通話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-PLUS var 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); // #endif export default { data() { return { status: 1, // 1: 主動呼叫;2: 被呼叫 pageH: '', // 頁面高度 innerAudioContext: null, // 音樂對象 streamList: [], msg_id: '', // 推送消息id msg_cid: '', // 推送cid roomID: '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 = 3 this.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].userID this.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 = 3 this.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.length for (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); // 對編碼的字元串轉化base64 var 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-PLUS if (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.status if (status < 2) { uni.showToast({ icon: 'none', title: '您還沒有打開通知許可權', duration: 3000 }) } }) jpushModule.addGeofenceListener(result => { let code = result.code let type = result.type let geofenceId = result.geofenceId let userInfo = result.userInfo uni.showToast({ icon: 'none', title: '觸發地理圍欄', duration: 3000 }) }) jpushModule.setIsAllowedInMessagePop(true) jpushModule.pullInMessage(result => { let code = result.code console.log(code) }) jpushModule.addInMessageListener(result => { let eventType = result.eventType let messageType = result.messageType let content = result.content console.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.connectEnable uni.$emit('connectStatusChange', connectEnable) }); jpushModule.addNotificationListener(result => { let notificationEventType = result.notificationEventType let messageID = result.messageID let title = result.title let content = result.content let extras = result.extras console.log(result) this.$util.router(`/pages/public/answer?status=2`) }); jpushModule.addCustomMessageListener(result => { let type = result.type let messageType = result.messageType let content = result.content console.log(result) uni.showToast({ icon: 'none', title: JSON.stringify(result), duration: 3000 }) }) jpushModule.addLocalNotificationListener(result => { let messageID = result.messageID let title = result.title let content = result.content let extras = result.extras console.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.notificationEventType let messageID = result.messageID let title = result.title let content = result.content let extras = result.extras console.log(result) this.$util.router(`/pages/call/call?status=2`) });