QQ小程序踩坑(一?)

qq也开始做自己的小程序了,我们“有幸”拿到了内测资格,比其他开发者早了几个月开始开发(踩坑),不得不说,这个内测还是很有必要的

先说几个记忆深刻的地方吧

视频激励广告的回调方法如果请求了接口,在iOS中会报错,经过仔细排查,怀疑是线程有问题,所以加上了250ms的延时,果然解决了。

1
2
3
4
5
6
7
8
self.videoAd.onClose((e)=>{
if(e.isEnded){
setTimeout(()=>{
//request
//...
}, 250);
}
});

还有一个是以弹窗形式显示的输入框,在iOS下(为什么又是iOS)会出现第一次正常显示,再之后就看不到了的问题。这个纠结了很久,最后发现是因为当时为了效率在页面使用了hidden来显示隐藏弹窗,可能是iOS渲染输入框的时候有一些问题,使用if来显示隐藏就没问题了

接下来总结一下一些技术点吧

小程序比较重要的一个就是登录及授权,因为小程序拉取用户信息需要授权,而并不是所有用户都想要授权,所以我们一开始做的时候是使用了我们自己的一套用户体系,用户完全不需要授权。但是,QQ的人却说,要用他们的授权(虽然我也不知道为什么我们的产品会有QQ的人来提意见)。于是最后就改成了,每个页面都会检测用户授权,而且为了提升未授权用户的体验,即使不授权也不会影响页面展示。

在页面的onShow方法中,检测用户授权状态,获取标示来限制页面信息及功能

1
2
3
4
5
6
7
8
9
10
11
Page({
...
onShow(){
app.newCheckUserInfo(()=>{
self.setData({
hasuinfo: app.hasUserInfo()
});
});
},
...
});

在app.js中实现方法

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
31
App({
...
newCheckUserInfo(cb, autologin = true){
let
self = this;
qq.getSetting({
success(res){
if(res.authSetting['scope.userInfo']){
qq.getUserInfo({
success(res){
//updata and upload user info
self.updateUserInfo(res.userInfo);
!!cb && cb();
}
})
}else if(self.globalData.firstGotoLogin == 0 && autologin){
self.globalData.firstGotoLogin++;
qq.navigateTo({
url: "/pages/login/index"
});
}else{
!!cb && cb();
}
},
fail(res){
console.log(res);
}
});
},
...
});

成功拉取到用户信息后,需要向服务器上传用户信息。如果用户并未授权,且当前是小程序打开的第一次,就跳转到专门的登录页面,以此来保证未授权用户不会每打开一个页面都会跳到登录页面。

然后就是用户登录,小程序的用户登录是后台静默执行的,需要处理的就是一个token过期的问题,由于所有的接口基本都会传token,也就是说,所有的接口都有可能面对token过期的问题,在所有接口的返回中,都要针对过期的错误码,来重新登录,并且在登录的回调中,执行当前方法。这里还会有一个问题,就是如果一个界面有多个请求,如果登录方法中不做任何处理,就会出现多次重连的情况,所以还需要在登录方法中记录一个状态以保证当前重登录只会有一次,并记录回调方法,在重登录成功后执行所有在此期间的回调。

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
App({
reLoginTimes: 0,
tokenCbs: [],
isGetTokening: false,
...
doLogin(callback){
let self = this;
if(callback){
self.tokenCbs.push(callback);
}
if(self.isGetTokening){
return
}
self.isGetTokening = true;
qq.login({
success(res){
Util.getAjax({
purl: "/test/login",
data: {
app_id: Util.getAPPID(),
code: res.code
},
success(data){
if(data.error == ERROR.AJAX_SUCCESS){
qq.setStorageSync("theToken", data.token);
qq.setStorageSync("theUserID", data.userID);
for(let cb of self.tokenCbs){
cb();
}
self.reLoginTimes = 0;
self.isGetTokening = false;
self.tokenCbs = [];
}else{
self.isGetTokening = false;
self.reLoginTimes++;
if(self.reLoginTimes >= 5){
self.exitApp();
}else{
setTimeout(self.doLogin, 1000);
}
}
},
fail(data){
self.isGetTokening = false;
self.reLoginTimes++;
if(self.reLoginTimes >= 5){
self.exitApp();
}else{
setTimeout(self.doLogin, 1000);
}
}
});
},
fail(){
self.isGetTokening = false;
self.tokenCbs = [];
},
});
},
...
});