微信小程序直播是最近上线的一个新功能,用了将近一天半的时间实现了用直播API去创建直播间,中间踩了很多坑(有的到现在也不是很明白为啥这样就可以 那样就不行),网上有关直播功能的参考文章也比较少,所以这篇文章主要记录一下填坑之路,更详细的代码笔记后面慢慢补。。
微信的小程序直播功能是利用他封装好的直播组件(live-player-plugin)实现的。先放上来直播功能开放文档,后面所有都按照这个文档走。我实现直播功能的流程如下:
我个人认为小程序直播创建核心就是这五步,并且我后端没有使用自己的服务器,全程用的是微信的云开发。微信云开发当中的云函数充当了后端的角色,并且云开发这种模式弱化了后端和运维的概念,不需要考虑服务器和运维的问题。因此,微信云开发提供了两个使用思路(个人理解):
前面说完了介绍,小程序直播开发的第一步就是引入直播组件。微信的开放文档提供了两种引入方式:主包引入和分包引入。这里我把所有的小程序页面暂时都写在了一个pages文件下,所以采用了主包引入的方法,对分包引入和分包感兴趣的可以看这里,不得不说分包的优势就是用户的体验感比较好,不用在首次打开小程序的时候一次性把所有的代码包都从客户端加载,需要哪个包就下载哪个包,另外对团队协同开发也很友好。
回归正题,放一下主包引入的代码吧,在app.json中直接复制就行(需要去掉注释)。使用前需要在你的小程序管理后台开通一下直播功能,需要具备:1、小程序存在支付行为 2、90天内没违规。
"plugins": {
"live-player-plugin": {
"version": "1.1.1", // 注意填写该直播组件最新版本号,微信开发者工具调试时可获取最新版本号
"provider": "wx2b03c6e691cd7370" // 必须填该直播组件appid,该示例值即为直播组件appi
}
}
为了后面的思路更清楚,我先把创建直播间API需要的参数和接口列上
请求方式:POST 请求URL:https://api.weixin.qq.com/wxaapi/broadcast/room/create?access_token=
请求参数示例: json
{
name: "测试直播房间1", // 房间名字
coverImg: "", // 通过 uploadfile 上传,填写 mediaID
startTime: 1588237130, // 开始时间
endTime: 1588237130 , // 结束时间
anchorName: "zefzhang1", // 主播昵称
anchorWechat: "WxgQiao_04", // 主播微信号
shareImg: "" , //通过 uploadfile 上传,填写 mediaID
type: 1 , // 直播类型,1 推流 0 手机直播
screenType: 0, // 1:横屏 0:竖屏
closeLike: 0 , // 是否 关闭点赞 1 关闭
closeGoods: 0, // 是否 关闭商品货架,1:关闭
closeComment: 0 // 是否开启评论,1:关闭
}
这个access_token之前在layui的学习记录里也提到过,这是调用接口凭证,在直播开发中主要是用来调用创建直播间API时作为URL参数去请求。在之前的学习记录中我是用自己的服务器cURL去请求的,这回是用小程序云开发的云函数充当服务器的角色去向微信服务器请求。
接口文档里写的很清楚,新建个云函数把该写的参数都写上去GET。云函数用的是node.js,之前没咋接触过,我也是参考了别人的代码。
// 云函数入口文件
const cloud = require('wx-server-sdk')
const rp = require('request-promise'); //这里使用了promise封装的request模块
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
//appid 和秘钥
const appid = '你的appid',
secret = '你的appSecret';
const AccessToken_options = {
method: 'GET',
url: 'https://api.weixin.qq.com/cgi-bin/token',
qs: {
appid,
secret,
grant_type:'client_credential'
},
json: true
};
//获取AccessToken
const resultValue = await rp(AccessToken_options);
const token = resultValue;
return token ;
}
云函数使用了request-promise
模块,request模块的options用AccessToken_options
变量封装好了传入,url请求方法还有参数都按照文档里写。我这里返回的是所有请求结果,不单是access_token,我前端回调云函数的时候再取出来access_token。回调代码:
getAccessToken:function(){
var that = this
wx.cloud.callFunction({
// 云函数名称
name: 'getAccess',
success: function(res) {
console.log(res.result.access_token) // access_token
that.setData({
access_token:res.result.access_token
})
},
fail: console.error
})
},
回调成功后,res.result.access_token
就是我们要的参数,并且利用setData赋值给access_token,方便后面使用。
这部分感觉微信文档写的不是很好,示例和接口的使用跳转到微信公众号部分了,我绕了好大一圈没搞明白咋去向微信服务器请求这个media_id。这个media_id是用来调用创建直播间API时作为JSON参数去请求的,直播间的封面图和分享封面图都是用media_id当参数的。微信给的注释是:通过 uploadfile 上传,填写 mediaID,我寻思这应该是需要上传图片后用自己的服务器去请求微信服务器返回media_id,我想做的是用微信云开发,暂时不考虑用自己的服务器。
再来看参数详细说明:背景图,填入mediaID(mediaID获取后,三天内有效);图片mediaID的获取,请参考以下文档: https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/New_temporary_materials.html;直播间背景图,图片规则:建议像素1080*1920,大小不超过2M。
这个跳转到了微信公众号的素材管理,并且给出的示例是用CURL方式也涉及到使用自己的服务器。找了半天没找到怎么用云函数去请求media_id,感觉好像这个是公众号才有的。
我找了半天最后在服务端的客服消息找到个customerServiceMessage.uploadTempMedia接口返回的参数有media_id并且可以用云函数调用,太不容易了T-T,示例代码贴出来:
// cloud = require('wx-server-sdk')
// ...
// 方法返回 Promise
cloud.openapi.customerServiceMessage.uploadTempMedia({
type: 'image',
media: {
contentType: 'image/png',
value: Buffer
}
})
注意这里的value参数是buffer,(所以问题又变成咋去找这个buffer格式的值)利用云开发的文件下载接口downloadFile实现,这里补充一句,我的所有本地图片上传是存在了云存储里(wx.chooseImage(Object object)和wx.cloud.uploadFile联合使用)。回归主题,downloadFile这个接口真香,只需要fileID一个参数,返回的fileContent正好是buffer格式的。而fileID是作为uploadFile接口的返回参数。所以我的思路就是本地图片上传–>uploadFile把图片存在云存储并返回fileID–>云函数调用downloadFile接口得到buffer–>传给uploadTempMedia–>返回media_id。【拿到media_id 太不容易了】先把代码贴上来:
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
exports.main = async (event, context) => {
const fileID = event.fileID //传入文件ID参数
const res = await cloud.downloadFile({
fileID: fileID,
})
const buffer = res.fileContent //得到了buffer
const result= await cloud.openapi.customerServiceMessage.uploadTempMedia({
type: 'image',
media: {
contentType: 'image/jpg',
value: buffer
}
})
return result
}
云函数前端回调需要传入fileID,返回的result里包含media_id,并用setData传值供后面调用。前端代码如下:
/* 获取mediaID */
getMediaID:function(){
var that=this
// console.log(that.data.access_token)
wx.chooseImage({
success (res) {
const tempFilePaths = res.tempFiles
// console.log(tempFilePaths)
wx.cloud.uploadFile({
cloudPath: 'company-coverimg/test.jpg',
filePath: tempFilePaths[0].path, // 文件路径
success: res => {
wx.cloud.callFunction({
// 云函数名称
name: 'getMedia',
data:{
fileID:res.fileID //云函数传入fileID
},
success: function(res) {
console.log(res.result.mediaId)
that.setData({
mediaID:res.result.mediaId
})
},
fail: console.error
})
},
fail: err => {
console.log(err)
}
})
}
})
},
创建直播间API的参数都准备好了以后,还是用云函数require-promise模块的POST方式调用。传入云函数的参数有access_token、media_id、start(开始时间)和end(结束时间)。这部分我参考了别人的代码,具体还没仔细研究,回头慢慢补回来。
// 云函数入口文件
const cloud = require('wx-server-sdk')
const rp =require('request-promise')
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
const access_token=event.access_token
const option={
method:'POST',
url:'https://api.weixin.qq.com/wxaapi/broadcast/room/create?access_token='+access_token,
form:{
name:"直播测试", // 房间名字
coverImg: event.mediaID, // 通过 uploadfile 上传,填写 mediaID
startTime: event.start, // 开始时间
endTime: event.end, // 结束时间
anchorName: "GGGGuiii", // 主播昵称
anchorWechat: "long-962464", // 主播微信号
shareImg: event.mediaID, //通过 uploadfile 上传,填写 mediaID
type: 0 , // 直播类型,1 推流 0 手机直播
screenType: 0, // 1:横屏 0:竖屏
closeLike: 1 , // 是否 关闭点赞 1 关闭
closeGoods: 1, // 是否 关闭商品货架,1:关闭
closeComment: 0 // 是否开启评论,1:关闭
},
headers: {
// 'cache-control': 'no-cache',
// "Accept": "application/json",
"content-Type": "application/x-www-form-urlencoded"
},
json: true
}
const resultValue = await rp(option);
const result = resultValue;
return result
}
前端回调代码:
create:function(){
var that=this
console.log(that.data.mediaID)
var start='1594974912'
var end='1594978512'
this.createLive(that.data.access_token,that.data.mediaID,start,end)
},
createLive:function(access_token,mediaID,start,end){
var that=this
wx.cloud.callFunction({
// 云函数名称
name: 'createLive',
data:{
start:start,
end:end,
mediaID:mediaID,
access_token:access_token
},
success: function(res) {
console.log(res)
that.setData({
roomID:res.result.roomId
})
console.log(res.result.roomId) // access_token
},
fail: console.error
})
},
这里比较坑的是开始时间和结束时间,一直显示20002入参错误:开始时间和结束时间不存在。按照微信客服说的header改成"content-Type": "application/json"
也不行,后来在数据上加了个单引号,云函数里改成form还有header改成"content-Type": "application/x-www-form-urlencoded"
,就莫名其妙的可以了- -。至于是啥原理我也没整明白。最后调用创建直播间API返回房间号roomID后算是完成了90%,只需要把这个房间号传给直播组件就可以了。
直播组件的使用我用的是第二种方法,在js文件里使用。
微信开放文档代码如下:
let roomId = [直播房间id] // 填写具体的房间号,可通过下面【获取直播房间列表】 API 获取
let customParams = encodeURIComponent(JSON.stringify({ path: 'pages/index/index', pid: 1 })) // 开发者在直播间页面路径上携带自定义参数(如示例中的path和pid参数),后续可以在分享卡片链接和跳转至商详页时获取,详见【获取自定义参数】、【直播间到商详页面携带参数】章节(上限600个字符,超过部分会被截断)
wx.navigateTo({
url: `plugin-private://wx2b03c6e691cd7370/pages/live-player-plugin?room_id=${roomId}&custom_params=${customParams}`
})
// 其中wx2b03c6e691cd7370是直播组件appid不能修改
我的代码:
start:function(){
var that=this
console.log(that.data.roomID)
let roomId = that.data.roomID // 填写具体的房间号,可通过下面【获取直播房间列表】 API 获取
let customParams = encodeURIComponent(JSON.stringify({ path: 'pages/live/live', pid: 1 })) // 这里我修改了跳转页面
wx.navigateTo({
url: `plugin-private://wx2b03c6e691cd7370/pages/live-player-plugin?room_id=${roomId}&custom_params=${customParams}`
})
},