开发微信公众号网页调用微信js-sdk(扫一扫,语音)
<p>在微信公众号里打开的网页,想要调用手机扫一扫,语音功能,这需要用到微信JS-SDK。因为是在微信里打开,受微信控制,所以只能用官方提供的sdk了。</p><p><span style="color: rgba(255, 0, 0, 1)"><strong><span style="background-color: rgba(255, 255, 0, 1)">注意-_- 坑:</span></strong></span><span style="color: rgba(51, 51, 0, 1); background-color: rgba(255, 255, 255, 1)">多个页面用到接口,必须都配一次config,url要是当前网页完整路径(现在是单页面,即www.abc.com/log,www.abc.com/list),不包括#后面的。</span></p>
<p> </p>
<p><strong>准备工作:</strong></p>
<p>1. 认真读官方文档,可以减少不少坑。 (文档也有坑,字多,有的过时了,没更新。)</p>
<p>2.在公众号后台,配置JS接口安全域名,并把文件(下图第3点)下载到自己服务器。</p>
<p>3. 后端提供了接口,获取微信的签名等信息,用来配置config ( 前端直接调接口就行,生成签名这些只能有后台去调微信接口,官方文档也有写到)</p>
<p> </p>
<p><img src="https://img2020.cnblogs.com/blog/1300767/202009/1300767-20200915094151058-890414381.png" alt="" width="1155" height="596" loading="lazy"></p>
<p> </p>
<p><strong>正式开发:</strong></p>
<p>【扫一扫】</p>
<p>1.在每个用到微信接口的页面,都<span style="color: rgba(0, 0, 255, 1)">需要单独</span>调用一次后台接口,配置一次config。 因为每次签名所需要的url,必须是页面完整的url。</p>
<div class="cnblogs_code">
<pre>我用到的是vue,所以在created生命周期去请求配置config。<br><br> const pageUrl =<span style="color: rgba(0, 0, 0, 1)"> window.location.href; // 当前页面的url
const vx_url</span>="/wx/auth"<span style="color: rgba(0, 0, 0, 1)">; // 这是后台提供的接口。
const data</span>=<span style="color: rgba(0, 0, 0, 1)">{ url:pageUrl }
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.$api.get(vx_url, data).then((result) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (result.success) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.$wx.config({
debug: </span><span style="color: rgba(0, 0, 255, 1)">false</span>, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。</span>
appId: 'wx222222', <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 必填,公众号的唯一标识</span>
timestamp:result.data.timestamp , <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 必填,生成签名的时间戳</span>
nonceStr: result.data.noncestr, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 必填,生成签名的随机串</span>
signature: result.data.signature,<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 必填,签名</span>
jsApiList: ['scanQRCode'] <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 必填,需要使用的JS接口列表</span>
<span style="color: rgba(0, 0, 0, 1)"> });
}
});</span></pre>
</div>
<p>2. 在点击按钮后去调用微信接口,这种方式可以直接调用,不用写在ready里。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.$wx.scanQRCode({
needResult: </span>1, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 默认为0,扫描结果由微信处理,1则直接返回扫描结果,</span>
scanType: ["qrCode"<span style="color: rgba(0, 0, 0, 1)">],
success: (res)</span>=><span style="color: rgba(0, 0, 0, 1)"> {</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> console.log('扫描结果',res);</span>
<span style="color: rgba(0, 0, 0, 1)"> }
});</span></pre>
</div>
<p> </p>
<p><strong>【语音】</strong></p>
<p>1.配置config</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">created() {
const pageUrl </span>=<span style="color: rgba(0, 0, 0, 1)"> window.location.href;
const vx_url </span>= "/wx/auth"<span style="color: rgba(0, 0, 0, 1)">;
const data </span>=<span style="color: rgba(0, 0, 0, 1)"> {
url: pageUrl
}
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.$api.get(vx_url,data).then((result) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (result.success) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.$wx.config({
debug: </span><span style="color: rgba(0, 0, 255, 1)">false</span>, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。</span>
appId: 'wx2222', <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 必填,公众号的唯一标识</span>
timestamp: result.data.timestamp, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 必填,生成签名的时间戳</span>
nonceStr: result.data.noncestr, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 必填,生成签名的随机串</span>
signature: result.data.signature, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 必填,签名</span>
jsApiList: ['startRecord', 'stopRecord', 'uploadVoice', 'onVoiceRecordEnd' ] <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 必填,需要使用的JS接口列表</span>
<span style="color: rgba(0, 0, 0, 1)"> });
}
});
}<br></span></pre>
</div>
<p>2.开始录音</p>
<div class="cnblogs_code">
<pre>sendVoice(event) {
<span style="color: rgba(0, 0, 0, 1)"> event.preventDefault(); </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (util.judgeEquipment().isWeixin) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.$wx.startRecord({
success: () </span>=><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.isSend = <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.isReord = <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
const touch </span>= event.touches, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取第一个触点</span>
x = Number(touch.pageX), <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">页面触点X坐标</span>
y = Number(touch.pageY); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">页面触点Y坐标</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 记录触点初始位置</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.startX =<span style="color: rgba(0, 0, 0, 1)"> x;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.startY =<span style="color: rgba(0, 0, 0, 1)"> y;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.startTime = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date().getTime();
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.voiceTxt = '松开 发送'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.$wx.onVoiceRecordEnd({
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 录音时间超过一分钟没有停止的时候会执行 complete 回调</span>
complete: <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(res) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.resetVoiceOption();
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.uploadVoice(res.localId);
}
});
}
});
}</span><span style="color: rgba(0, 0, 0, 1)">
},</span></pre>
</div>
<p>3.手指移动</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)"> touchmove(event) {
const touch </span>= event.touches, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取第一个触点</span>
x = Number(touch.pageX), <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">页面触点X坐标</span>
y = Number(touch.pageY); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">页面触点Y坐标</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 记录移动位置</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.endX =<span style="color: rgba(0, 0, 0, 1)"> x;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.endY =<span style="color: rgba(0, 0, 0, 1)"> y;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>.startY - <span style="color: rgba(0, 0, 255, 1)">this</span>.endY < 0<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 向上滑</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.recordStatusTxt =<span style="color: rgba(0, 0, 0, 1)"> recordingTxt;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.isSend = <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 向下滑</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.recordStatusTxt =<span style="color: rgba(0, 0, 0, 1)"> cancelRecordTxt;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.isSend = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
}
},</span></pre>
</div>
<p>4.结束录音</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)"> touchend(e) {
e.preventDefault();
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.resetVoiceOption();
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.endTime = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date().getTime();</span>
const diffTime = <span style="color: rgba(0, 0, 255, 1)">this</span>.endTime - <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.startTime;</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>.startTime === 0 || diffTime < 500<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.$toast("录音时间太短", "none", 1500<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
}
const recordTime </span>= Math.ceil(diffTime / 1000); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 录音多少秒<br></span>
<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.$wx.stopRecord({
success: (res) </span>=><span style="color: rgba(0, 0, 0, 1)"> {</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.isSend) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.uploadVoice(res.localId);
}
}
});
},</span></pre>
</div>
<p>5.上传语音 </p>
<p>由于微信服务器只会保留语音文件3天,所以需要后台去微信服务器下载到自己服务器。<em id="__mceDel">后端从微信下载语音接口文档 https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/Get_temporary_materials.html</em></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)"> uploadVoice(_localId) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.$wx.uploadVoice({
localId: _localId, </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 需要上传的音频的本地ID,由stopRecord接口获得</span>
isShowProgressTips: 0, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 1显示进度提示,0不显示</span>
success: (resp) =><span style="color: rgba(0, 0, 0, 1)"> {
const url </span>= '/wx/downloadVoice' // 后台提供的接口。先把语音上传到微信服务器,然后把serverId发给后台,后台通过这id去微信服务器下载语音到自己服务器,再返回url给前端<span style="color: rgba(0, 0, 0, 1)">
const data </span>=<span style="color: rgba(0, 0, 0, 1)"> {
mediaId:resp.serverId
}
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.$api.get(url, data).then((result) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (result.success) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 返回是 .amr</span>
console.log(result.data) <span style="color: rgba(0, 0, 0, 1)">
}
});
}
});
},<br></span></pre>
</div>
<p>6.重置</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)"> resetVoiceOption(){
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.isReord = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.voiceTxt = '按住 说话'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.recordStatusTxt =<span style="color: rgba(0, 0, 0, 1)"> recordingTxt;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.startX = 0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.startY = 0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.endX = 0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.endY = 0<span style="color: rgba(0, 0, 0, 1)">;
},</span></pre>
</div>
<p>7.播放</p>
<p>由于微信录音文件是.amr格式,h5音频标签无法播放的。</p>
<p>方案1:后台从微信服务器下载回来语音文件时,直接转换成MP3格式</p>
<p>方案2:前端使用‘benz-amr-recorder’这个库,可以播放</p>
<div class="cnblogs_code">
<pre>const BenzAMRRecorder = require('benz-amr-recorder'<span style="color: rgba(0, 0, 0, 1)">);
const amr </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BenzAMRRecorder();
</span><span style="color: rgba(0, 128, 0, 1)">// url是后台返回的 </span><span style="color: rgba(0, 128, 0, 1)">https://www.abc.com/7A1BAEEB.amr</span>
amr.initWithUrl(src).then(() =><span style="color: rgba(0, 0, 0, 1)"> {
amr.play(); // 播放
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> const amrDuration = Math.ceil(amr.getDuration());</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> console.log('音频时长', amrDuration); // 获取音频时长</span>
<span style="color: rgba(0, 0, 0, 1)"> });
</span>
amr.onEnded(() =><span style="color: rgba(0, 0, 0, 1)"> {</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> console.log(播放结束)</span>
})</pre>
</div>
<p> </p>
<p>附:官网事例demo</p>
<p> </p>
<p>补上HTML和data部分的代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">用的是uni-app
</span><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">view </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="input"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">input
</span><span style="color: rgba(255, 0, 0, 1)">v-if</span><span style="color: rgba(0, 0, 255, 1)">="featuresType == 0"</span><span style="color: rgba(255, 0, 0, 1)">
class</span><span style="color: rgba(0, 0, 255, 1)">="txt"</span><span style="color: rgba(255, 0, 0, 1)">
placeholder</span><span style="color: rgba(0, 0, 255, 1)">="请输入文字"</span><span style="color: rgba(255, 0, 0, 1)">
v-model</span><span style="color: rgba(0, 0, 255, 1)">="commentText"</span><span style="color: rgba(255, 0, 0, 1)">
confirm-type</span><span style="color: rgba(0, 0, 255, 1)">="send"</span><span style="color: rgba(255, 0, 0, 1)">
@confirm</span><span style="color: rgba(0, 0, 255, 1)">="sendTxt"</span>
<span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">input
</span><span style="color: rgba(255, 0, 0, 1)">disabled
:placeholder</span><span style="color: rgba(0, 0, 255, 1)">="voiceTxt"</span><span style="color: rgba(255, 0, 0, 1)">
v-else
class</span><span style="color: rgba(0, 0, 255, 1)">="btn-voice"</span><span style="color: rgba(255, 0, 0, 1)">
@longpress</span><span style="color: rgba(0, 0, 255, 1)">="sendVoice"</span><span style="color: rgba(255, 0, 0, 1)">
@touchend</span><span style="color: rgba(0, 0, 255, 1)">="touchend"</span><span style="color: rgba(255, 0, 0, 1)">
@touchmove</span><span style="color: rgba(0, 0, 255, 1)">="touchmove"</span>
<span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">view</span><span style="color: rgba(0, 0, 255, 1)">><br><br>data(){<br> return{<br></span></pre>
<div>
<div> voiceTxt: "按住 说话",</div>
<div> startX: 0,</div>
<div> startY: 0,</div>
<div> endX: 0,</div>
<div> endY: 0,</div>
<div> startTime: 0,</div>
<div> endTime: 0,</div>
<div> recordStatusTxt: recordingTxt,</div>
<div> isSend: false,</div>
<div>
<div> isReord: false,</div>
</div>
</div>
<pre><span style="color: rgba(0, 0, 255, 1)"> }<br>}</span></pre>
</div>
<p> </p><br><br>
来源:https://www.cnblogs.com/lucas27/p/13671800.html
頁:
[1]