微信小程序阶段性踩坑

前几天接了一个修小程序bug的活儿,距离上一次开发小程序已经过去一年多了,看了一下,改动了不少东西,编辑器的预览功能做的挺不错的(编辑功能还是不敢恭维),总结一下遇到的几个点吧。

登录获取用户信息

之前的微信小程序获取用户信息是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
wx.login({
success: function(res){
let theCode = res.code;
if(theCode){
wx.getUserInfo({
success: function(res){
let userInfo = res.userInfo;
//登录成功
},
fail: function(){
wx.openSetting({
success: function(res){
res = res.authSetting;
if(res["scope.userInfo"]){
//获取授权成功,重新登录
}else{
//未对获取用户信息进行授权,请关闭小程序后重试
}
}
});
}
})
}else{
//获取用户登录状态失败!
}
},
fail: function(){
//获取用户登录状态失败!
}
});

先试用wx.login请求登录,然后使用wx.getUserInfo获取用户信息,此操作涉及到权限,如果用户没有授权,之前是可以在fail回调中使用wx.openSetting方法打开授权界面,在用户授权后重新操作。

但微信在今年四月(好像)计划废弃wx.openSetting方法,这样在wx.getUserInfo的回调中,就无法使用打开授权界面,让用户重新授权的方法了。

而是在一开始(用户第一次使用)的时候就要让用户获取授权,并且这个获取授权的过程,必须是通过用户点击小程序中的按钮控件来完成的,通常是通过一个独立的授权页面来完成,页面主要结构如下。

1
<button open-type="getUserInfo" lang="zh_CN" bindgetuserinfo="onGotUserInfo">授权微信用户信息</button>

还有对应的逻辑代码,如果用户在微信弹出的授权框中点了取消,或者允许,都需要给出相应的反馈。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
...
...
onGotUserInfo: function(res){
if(res.detail.errMsg == "getUserInfo:fail auth deny"){
//未同意授权
wx.showModal({
title: '警告',
content: '您拒绝了授权,将无法正常使用本小程序',
showCancel: false
})
}else{
wx.navigateBack({
delta: 1
})
}
}

然后修改过后的登录逻辑就是,先使用wx.login登录,然后使用wx.getSetting获取授权信息,在这里判断是否同意了授权,如果没有同意过,则跳转至授权页面,反之则可以直接使用wx.getUserInfo方法获取用户信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
wx.login({
success: function(res){
wx.getSetting({
success (res){
if(res.authSetting['scope.userInfo']){
wx.getUserInfo({
withCredentials: true,
success: function(res){
//授权成功
//res.encryptedData,
//res.iv
},
fail: function(res){
}
})
}else{
// console.log("跳转至授权页面");
wx.hideLoading();
wx.navigateTo({
url: "/pages/test/test"
});
}
}
});
}
})

整体看下来其实登录的流程是被简化了的,除了用户第一次的授权需要用户多点击一下(其实这一步可以理解为其他软件的用户协议那一个确定),之后的授权就都可以直接获取了。

音频播放

之前的微信小程序中的音频,可以直接使用audio标签来实现

1
<audio poster="{{audio.poster}}" name="{{audio.name}}" author="{audio.author" src="{{audio.src}}" controls loop id="myAudio" binderror="audioError" bindplay="audioPlay"></audio>

这个标签之前是不需要管样式的,直接使用,但是可能微信觉得程序员直接用标签显得不够高端吧,表明audio标签即将不再维护,而这个结果就导致,包括我在内的好几个人都无法播放audio中的音频(可能跟iOS12更新有关)。于是查看文档,只能使用InnerAudioContext对象来实现播放,当然UI只能手写了。

于是使用样式拼一个跟之前audio标签差不多的界面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<view class="audioblock" catchtap="audioplay">
<view class="audioposter">
<image class="posterimg" src="{{audio.poster}}" mode="aspectFill"></image>
<image class="playstatus" wx:if="{{audioPlayStatus}}" src="/images/audio-pause.png"></image>
<image class="playstatus" wx:else src="/images/audio-play.png"></image>
</view>
<view class="audiotitile">{{lessonName}}</view>
<view class="audiotimes">{{audio_countdown}}</view>
</view>

...
...
audioplay: function(){
if(innerAudioContext.paused){
innerAudioContext.play();
}else{
innerAudioContext.pause();
}
}

然后是逻辑代码,这要注意如果对象不执行销毁或者暂停操作的话,即使切换页面,声音也不会停止,多次触发还会重复播放。

所以我将innerAudioContext对象放在了页面全局,在onLoad事件中初始化,在onUnload事件中销毁,在onHide事件中暂停(先判断状态),然后是innerAudioContext对象自己的一些事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
innerAudioContext.onTimeUpdate(() => {
_this.setData({
audio_countdown: Math.floor(innerAudioContext.currentTime)
});
});
innerAudioContext.onPlay(() => {
_this.setData({
audioPlayStatus: true
});
});
innerAudioContext.onPause(() => {
_this.setData({
audioPlayStatus: false
});
});
innerAudioContext.onStop(() => {
_this.setData({
audioPlayStatus: false
});
});