第三方平臺(tái)選型:騰訊、阿里、即構(gòu)、聲網(wǎng)
由于即構(gòu)直播平臺(tái)支持uni-app故本文章選用的是即構(gòu)sdk版講解
一、效果
二、sdk集成
? ? ?1、? 首先注冊(cè)即構(gòu)平臺(tái)賬號(hào),然后對(duì)照即構(gòu)官網(wǎng)一步步集成
主要分為sdk插件集成與JS 封裝層集成這兩部分,具體步驟請(qǐng)移步官網(wǎng)查看。
uni-app實(shí)時(shí)音視頻示例源碼下載 - 開發(fā)者中心 - ZEGO即構(gòu)科技
? ?
? ?2、調(diào)試,即構(gòu)官網(wǎng)提供了pc網(wǎng)頁直播推流地址,如下
? ??推拉流基礎(chǔ)功能
?????????需要到控制臺(tái)獲取自己創(chuàng)建的AppID、RoomID、UserID、Token、StreamID,填入其中,app直播端也需要填寫一樣的appid.有關(guān)app部分下一步再講。需要注意的是,直播端與觀眾端的AppID、RoomID、StreamID三個(gè)需要一致才可看到對(duì)方的直播。
??
3、app端代碼文章來源:http://www.zghlxwxcb.cn/news/detail-553144.html
需要修改 appSign、AppID,修改成自己的。文章來源地址http://www.zghlxwxcb.cn/news/detail-553144.html
<template>
<view class="colum_layout">
<!-- 狀態(tài)欄 -->
<view class="title" style="width: 100%;height: 70rpx;background-color: black;"></view>
<!-- <zego-local-view style="height: 300rpx;width: 400rpx;position: absolute;display: flex;z-index:999"></zego-local-view> -->
<!-- 拉流布局 -->
<view class="live_parent" @click="hide_edit">
<zego-remote-view class="live_play" :streamID="playStreamID" :viewMode="AspectFit=1">
</zego-remote-view>
</view>
<!-- 在線人數(shù) -->
<view class="onlines">
<text class="user_name">昵稱:醫(yī)生</text>
<!-- @click="loginOut" -->
<view class="onlineMd">
<text class="onlineTag">在線</text>
<text class="online_num">{{online}}</text>
<image @click="closed" style="width: 40rpx;height: 40rpx; margin-right: 40rpx;" src="/static/cha.png">
</image>
</view>
</view>
<!-- 消息列表 -->
<view :class="isShowKeyboad?'msg_list_height':'msg_list_low'">
<scroll-view scroll-y="true" class="list-content" show-scrollbar="false" :enhanced="true" :bounces="false"
:scroll-with-animation="true" :scroll-top="commentScrollTop">
<view class="list-item" id="commentContent" v-for="(item,index) in msg" :key="index">
<!-- item.fromUser.userName -->
<text class="person_title">{{item.fromUser.userName}}</text>
<!-- item.message -->
<text class="content_body">{{item.message}}</text>
</view>
</scroll-view>
</view>
<!-- 消息輸入 -->
<view class="enter_input" v-if="isShowKeyboad">
<textarea class="input_reply_msg" maxlength="50" :show-confirm-bar="false" v-model="msg_enter" auto-height
focus='true' placeholder="請(qǐng)輸入消息" @input="inputHandle" />
<text class="send_msg" @click="sendMsg">發(fā)送</text>
</view>
<!-- 消息反饋模塊 -->
<view class="interaction" v-if="!isShowKeyboad">
<!-- <view> -->
<!-- <zego-local-view class="push_live"></zego-local-view> -->
<!-- </view> -->
<text class="input_msg" @click="inputMsg">說點(diǎn)什么吧...</text>
<!-- <text class="like_click" @click="likeClick">點(diǎn)贊</text> -->
<likeButton :throttle="100" :large="2" :site="[60, 160]"
style="display: flex;position: fixed;bottom: 32rpx;right: 30rpx;">
</likeButton>
</view>
</view>
</template>
<script>
// 導(dǎo)入權(quán)限工具類
import permision from "@/pages/permission.js";
// 導(dǎo)入直播引擎
import ZegoExpressEngine from '@/components/zego-ZegoExpressUniApp-JS/lib/ZegoExpressEngine';
// 導(dǎo)入推流布局組件
import ZegoLocalView from '@/components/zego-ZegoExpressUniApp-JS/zego-view/ZegoLocalView';
// 導(dǎo)入拉流布局組件
import ZegoRemoteView from '@/components/zego-ZegoExpressUniApp-JS/zego-view/ZegoRemoteView';
//點(diǎn)贊按鈕
import likeButton from '@/components/like-button/like-button.vue';
export default {
components: {
ZegoLocalView: ZegoLocalView,
ZegoRemoteView: ZegoRemoteView,
ZegoExpressEngine,
likeButton
},
data() {
return {
title: 'Hello',
isShowKeyboad: false,
msg_enter: "",
engine: undefined,
playStreamID: 'streamID123',
msg: [],
commentScrollTop: 999999, //評(píng)論區(qū)滾動(dòng)高度
roomID: 'mghome123', //房間id
userID: '222222', //用戶id
userName: '醫(yī)生', //用戶名
online: 0, //在線用戶數(shù)
}
},
onLoad: function(option) { //option為object類型,會(huì)序列化上個(gè)頁面?zhèn)鬟f的參數(shù)
console.log("=====打印出上個(gè)頁面?zhèn)鬟f的參數(shù)=="); //打印出上個(gè)頁面?zhèn)鬟f的參數(shù)。
this.userID = Math.floor(Math.random(10000) * 10000) + ""; //用戶id
this.userName = option.usName; //用戶名
},
//返回鍵
onBackPress() {
console.log("===onBackPress===");
this.loginOut();
},
created() {
this.playStreamID = 'streamID123';
},
onReady() {
this.playStreamID = 'streamID123';
var that = this;
this.initZegoExpressEngine();
},
//隱藏
onHide() {
that.logoutRoom(that.roomID);
},
mounted() {
},
methods: {
async initZegoExpressEngine() {
var that = this;
console.log("==mounted==");
//Android 權(quán)限請(qǐng)求
if (uni.getSystemInfoSync().platform === "android") {
await permision.requestAndroidPermission(
"android.permission.RECORD_AUDIO"
);
await permision.requestAndroidPermission(
"android.permission.CAMERA"
);
}
//異步按順序執(zhí)行
new Promise(res => {
that.createEngine(); //創(chuàng)建視頻流引擎
setTimeout(() => {
console.log("===mogu===");
res();
}, 100);
}).then(res => {
console.log("===mogu11===");
//登錄房間
that.loginRoom(that.roomID, that.userID, that.userName);
}).then(res => {
console.log("===mogu22===");
that.addListeners(); //添加監(jiān)聽
});
},
//關(guān)閉頁面
closed() {
this.loginOut();
},
//登出sasaa
loginOut() {
var that = this;
that.engine.stopPlayingStream(that.playStreamID);
that.logoutRoom(that.roomID);
ZegoExpressEngine.destroyEngine(res => {
});
uni.reLaunch({
url: '/pages/login/login'
})
// plus.runtime.quit();
},
//發(fā)送消息
sendMsg: function(e) {
var that = this;
// console.log("====發(fā)送消息====" + JSON.stringify(this.engine));
if (this.msg_enter == '' || this.msg_enter.length == 0) {
uni.showToast({
title: '輸入不能為空',
icon: "error",
duration: 2000
});
return 1;
}
let msgConn = [{
"sendTime": 1687763213632,
"message": "" + this.msg_enter,
"messageID": 1,
"fromUser": {
"userID": this.userID,
"userName": this.userName
}
}];
that.msgListDeal(msgConn);
// 發(fā)送廣播消息,每個(gè)登錄房間的用戶都會(huì)通過 IMRecvBroadcastMessage 回調(diào)事件收到此消息
this.engine.sendBroadcastMessage('mghome123', "" + this.$data.msg_enter).then((
result) => {
// 獲取消息發(fā)送結(jié)果
console.log("====按鈕發(fā)送====" + JSON.stringify(result));
that.msg_enter = '';
//隱藏軟鍵盤方法
that.hide_edit();
})
},
// 接收消息
receiverMsg: function(e) {
var that = this;
this.engine.on("IMRecvBroadcastMessage", (mghome, messageList) => {
console.log("==1111==" + JSON.stringify(that.$data.msg));
that.msgListDeal(messageList);
console.log("==2222==" + JSON.stringify(that.$data.msg));
});
this.engine.on('IMRecvBarrageMessage', (mghome, messageList) => {
console.log("===received barrage message==" + JSON.stringify(messageList))
});
// this.engine.on('IMRecvCustomCommand', (mghome, fromUser, command) => {
// console.log("("===received custom command=="+JSON.stringify(messageList))
// })
},
//消息列表顯示處理e
msgListDeal: function(messageList) {
var that = this;
if (that.$data.msg.length >= 10) { //只顯示最新10條消息
that.$data.msg.shift();
}
that.$data.msg.push(...messageList); //新消息添加
setTimeout(() => {
this.commentScrollTop = this.commentScrollTop + 1;
}, 100);
},
//鍵盤監(jiān)聽
keyBoardHeightListener: function(e) {
uni.onKeyboardHeightChange(res => {
if (res.height == '0') { //隱藏鍵盤
this.$data.isShowKeyboad = false;
}
})
},
//輸入消息監(jiān)聽
inputHandle(e) {
this.$data.msg_enter = e.detail.value;
console.log("==輸入消息監(jiān)聽===" + e.detail.value)
},
// 鍵盤彈出
inputMsg() {
this.$data.isShowKeyboad = true;
// console.log("===鍵盤彈出===");
},
//隱藏鍵盤
hide_edit(e) {
console.log("===隱藏軟鍵盤方法===");
this.$data.isShowKeyboad = false;
uni.hideKeyboard() //隱藏軟鍵盤方法
},
//創(chuàng)建引擎
async createEngine() {
// 采用通用場景
const profile = {
appID: ,//換成自己的appid
// AppSign 僅滿足簡單的鑒權(quán)需求,如果需要升級(jí)為更加安全的鑒權(quán)方式,請(qǐng)參考[如何從 AppSign 鑒權(quán)升級(jí)為 Token 鑒權(quán)](https://doc-zh.zego.im/faq/token_upgrade?product=ExpressVideo&platform=all)
// AppSign 可通過[控制臺(tái)](https://console.zego.im/dashboard)獲取,格式為 @"39011cbxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
appSign: '',//換成自己的appSign
scenario: 0
};
this.engine = await ZegoExpressEngine.createEngineWithProfile(
profile
);
console.log("==創(chuàng)建引擎==" + JSON.stringify(this.engine));
//設(shè)置分辨率
let config = {
encodeWidth: 360,
encodeHeight: 640
}
ZegoExpressEngine.instance().setVideoConfig(config);
},
//登錄房間
async loginRoom(roomID, userID, userName) {
this.logoutRoom(roomID);
let roomConfig = {};
// 只有傳入 “isUserStatusNotify” 參數(shù)取值為 “true” 的 ZegoRoomConfig,才能收到 onRoomUserUpdate 回調(diào)。
roomConfig.isUserStatusNotify = true;
// 登錄房間
// 開始登錄房間
this.engine.loginRoom(roomID, {
'userID': userID,
'userName': userName
}, roomConfig);
this.receiverMsg(); //接收消息監(jiān)聽
},
//登出房間
logoutRoom(roomID) {
this.engine.logoutRoom(roomID);
},
//推流
async likeClick() {
// #需要使用$nextTick延時(shí)調(diào)用,否則沒有效果
console.log("==推流==");
/** 1. 創(chuàng)建美顏環(huán)境 */
// await this.engine.startEffectsEnv();
/** 開關(guān)美顏效果 */
// await this.engine.enableEffectsBeauty(true);
//js部分:
/** 開始預(yù)覽 */
// ZegoExpressEngine.instance().startPreview();
/** 開始推流 APP-PULL stream無值, Web有值,為MediaStream*/
// const stream = await ZegoExpressEngine.instance().startPublishingStream("streamID123");
// 推流視頻流監(jiān)聽
// ZegoExpressEngine.instance().on("publisherStateUpdate", (streamID, state, errorCode, extendedData) => {
// 調(diào)用推流接口成功后,當(dāng)推流器狀態(tài)發(fā)生變更,如出現(xiàn)網(wǎng)絡(luò)中斷導(dǎo)致推流異常等情況,SDK在重試推流的同時(shí),會(huì)通過該回調(diào)通知
//....
// });
},
//房間監(jiān)聽
addListeners() {
console.log("=======房間監(jiān)聽======");
var that = this;
// 以下為常用的房間相關(guān)回調(diào)
that.engine.on('roomStateUpdate', (roomID, state, errorCode,
extendedData) => {
// 房間狀態(tài)更新回調(diào),登錄房間后,當(dāng)房間連接狀態(tài)發(fā)生變更(如出現(xiàn)房間斷開,登錄認(rèn)證失敗等情況),SDK會(huì)通過該回調(diào)通知
console.log("==房間狀態(tài)更新回調(diào)==" + JSON.stringify(roomID));
});;
that.engine.on('roomUserUpdate', (roomID, updateType, userList) => {
// 用戶狀態(tài)更新,登錄房間后,當(dāng)房間內(nèi)有用戶新增或刪除時(shí),SDK會(huì)通過該回調(diào)通知
console.log("==用戶狀態(tài)更新==" + JSON.stringify(userList));
if (updateType == 0) {
that.online = that.online + userList.length;
} else {
if (that.online >= userList.length) {
that.online = that.online - userList.length;
}
console.log("==用戶狀態(tài)更新==" + that.online);
}
});
that.engine.on('roomStreamUpdate', (roomID, updateType, streamList) => {
// 流狀態(tài)更新,登錄房間后,當(dāng)房間內(nèi)有用戶新推送或刪除音視頻流時(shí),SDK會(huì)通過該回調(diào)通知
// 開始拉流
if (streamList.length > 0) {
if (streamList[0].streamID != '') {
that.playStreamID = streamList[0].streamID;
const streamss = that.engine.startPlayingStream(streamList[0]
.streamID);
console.log("==流狀態(tài)更新==" + JSON.stringify(streamList[0].streamID));
}
}
});
},
recycleData: function() {
var that = this;
//異步按順序執(zhí)行
// new Promise(res => {
// console.log("===mogu===");
// // setTimeout(() => {
// // res();
// // }, 100);
// /** 停止本地預(yù)覽 */
// // that.engine.stopPreview();
// /** 停止推流 */
// // that.engine.stopPublishingStream();
// /** 停止拉流 */
// that.engine.stopPlayingStream(that.playStreamID);
// /** 退出房間 */
// that.engine.logoutRoom(that.roomID);
// /** 銷毀引擎 */
// ZegoExpressEngine.destroyEngine();
// //移除鍵盤高度監(jiān)聽
// uni.offKeyboardHeightChange(res => {
// });
// console.log("===銷毀引擎==="+that.playStreamID+"=="+that.roomID);
// });
}
},
onUnload() {
this.recycleData();
// console.log("===銷毀引擎===");
}
}
</script>
<style>
.page {
display: flex;
flex-direction: column;
height: 100%;
background: transparent
}
.colum_layout {
flex: 1;
height: 100px;
}
.play_screen {
display: flex;
height: 100vh;
width: 100vh;
flex-direction: column;
justify-content: flex-end;
}
/* 在線人數(shù)模塊 */
.onlines {
height: 90rpx;
width: 750rpx;
background: transparent;
position: absolute;
top: 90rpx;
align-items: center;
flex-direction: row;
justify-content: space-between;
}
/* */
.user_name {
height: 70rpx;
background-color: #09c2fa;
margin-left: 30rpx;
padding-top: 20rpx;
padding-left: 40rpx;
padding-right: 40rpx;
border-radius: 30rpx;
align-items: center;
text-align: center;
font-size: 29rpx;
color: #fff;
background-color: rgba(128, 128, 128, 0.2);
}
/* 在線模塊 */
.onlineMd {
background: transparent;
margin-right: 40rpx;
flex-direction: row;
align-items: center;
}
/*在線標(biāo)記*/
.onlineTag {
color: white;
margin-right: 8rpx;
font-size: 28rpx;
}
/* 在線用戶數(shù) */
.online_num {
width: 80rpx;
background-color: red;
height: 80rpx;
margin-right: 40rpx;
border-radius: 40rpx;
align-items: center;
text-align: center;
padding-top: 25rpx;
font-size: 28rpx;
background-color: rgba(128, 128, 128, 0.2);
color: #fff;
}
/* 直播父布局 */
.live_parent {
flex: 1;
height: 100px;
position: sticky;
}
/* 直播組件 */
.live_play {
flex: 1;
position: relative;
height: 100px;
z-index: -1
}
/* 拉流 */
.push_live {
height: 300rpx;
width: 400rpx;
position: absolute;
bottom: 100rpx;
display: flex;
z-index: 999
}
/* 消息列表 */
.list-content {
max-height: 300px;
padding-bottom: 30rpx;
}
/* 鍵盤未彈起消息布局 */
.msg_list_low {
position: absolute;
width: 420rpx;
height: 600rpx;
background-color: red;
background: transparent;
bottom: 160rpx;
justify-content: flex-end;
}
/* 鍵盤彈起消息布局 */
.msg_list_height {
position: absolute;
width: 420rpx;
/* height: 600rpx; */
background: transparent;
bottom: 300rpx;
max-height: 600rpx;
justify-content: flex-end;
}
/* 水平內(nèi)容 */
.list-item {
background-color: yellow;
margin-top: 20rpx;
margin-left: 20rpx;
border-radius: 10rpx;
flex-direction: row;
background: transparent;
background-color: rgba(128, 128, 128, 0.1);
padding: 10rpx;
}
.person_title {
margin-left: 5rpx;
color: #09c2fa;
margin-right: 10rpx;
font-size: 28rpx;
}
.content_body {
font-size: 28rpx;
width: 344rpx;
color: #fcfcfc;
padding-right: 10rpx;
}
/* */
/* 消息輸入按鈕模塊 */
.enter_input {
width: 750rpx;
position: absolute;
display: flex;
flex-direction: row;
justify-content: space-between;
bottom: 120rpx;
align-items: center;
background-color: white;
border: transparent;
}
/* 消息輸入框 */
.input_reply_msg {
border: transparent;
flex: 1;
min-height: 66rpx;
padding-top: 10rpx;
padding-bottom: 10rpx;
background-color: #f0f0f0;
margin-left: 10rpx;
padding-left: 20rpx;
border-radius: 40rpx;
margin-right: 30rpx;
}
/* 發(fā)送消息 */
.send_msg {
width: 100rpx;
height: 58rpx;
font-size: 28rpx;
text-align: center;
margin-right: 30rpx;
padding-top: 13rpx;
background-color: #FF9999;
border-radius: 30rpx;
color: white;
margin-top: 15rpx;
margin-bottom: 15rpx;
}
/* 底部浮動(dòng)布局 */
.interaction {
background: transparent;
background-color: transparent;
position: fixed;
bottom: 20rpx;
display: flex;
flex: 1;
width: 750rpx;
flex-direction: row;
justify-content: space-between;
}
/* 點(diǎn)擊輸入消息 */
.input_msg {
width: 320rpx;
margin-left: 30rpx;
height: 78rpx;
background-color: rgba(128, 128, 128, 0.3);
border-radius: 40rpx;
color: #999999;
padding-top: 20rpx;
text-align: left;
padding-left: 30rpx;
}
.like_click {
height: 70rpx;
width: 160rpx;
display: flex;
background-color: #06c6ad;
padding-top: 20rpx;
color: white;
font-weight: 600;
border-radius: 20rpx;
font-size: 28rpx;
margin-right: 40rpx;
text-align: center;
}
</style>
到了這里,關(guān)于uni-app直播開發(fā)教程的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!