QQ小程序踩坑(二?)

不知不觉又两个月过去了,再总结一下近期的小程序开发情况

这几个月在QQ上也尝试了好几个类型的小程序,包括影评社区类的,匿名聊天类的,做到最后,还是都没有已经不怎么维护的测试类数据好看。按理说那个影评类的,有电影更新,有发帖互动,应该不差,可能QQ的用户群体还是对影评这个东西不怎么感兴趣吧,或者说使用QQ小程序的用户和喜欢影评的用户交集太小了。

WebSocket

在匿名聊天那个小程序中,使用到了WS,主要有私聊页面中当WS收到推送时,请求新的聊天数据;在首页的时候如果收到新消息的推送,展示新消息提示。

由于考虑到很多页面都会用到,所以在app.js中声明ws对象,在onLaunch事件中进行初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
App({
...
qqsocket: null,
onLaunch(option){
let
...
qqsocket = self.qqsocket;
if(!qqsocket){
self.initSocket();
qqsocket = self.qqsocket;
}
...
},
...
});

在初始化方法中,通过一个对象记录各个页面的回调事件,在onMessage中依次执行。同时,还需要有一个心跳来一直维持这个WS链接

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
App({
...
socketOnMsgCb: {},
initSocket(){
let
global = this,
qqsocket = qq.connectSocket({
url: `wss://${APPCONFIG.WSHOST}/api/ws`
});
qqsocket.onMessage((e)=>{
let
res = JSON.parse(e.data);
if(res.error == ERROR.TOKEN_ERROR){
global.doLogin(msgCb);
}else{
msgCb();
}
function msgCb(){
for(let i in global.socketOnMsgCb){
(global.socketOnMsgCb[i])(res);
}
}
});
qqsocket.onClose((e)=>{
if(!!global.qqsocketTimer){
clearInterval(global.qqsocketTimer);
}
setTimeout(global.initSocket, 3000);
});
global.qqsocketTimer = setInterval(global.qqSocketPing, 5000);
global.qqsocket = qqsocket;
},
qqSocketPing(){
let
self = this;
self.qqSocketSend({
msg_type: 1,
token: Util.getTheToken()
});
},
qqSocketSend(objs){
let
self = this,
qqsocket = self.qqsocket;
qqsocket.send({
data: JSON.stringify(objs)
});
},
...
});

之后,在页面中,读取并修改app的socketOnMsgCb对象即可,此外还需要判断一下当前页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Page({
...
onLoad(){
let
...
msgcb = app.socketOnMsgCb;
msgcb.messageGetting = (res) => {
if(res.error == ERROR.AJAX_SUCCESS && res.msg_type == 2 && app.isCurrentPage("pages/message/detail")){
console.log(res);
self.refrushMsgNew();
}
};
},
...
});

登录异常

在开发过程中,发现有极个别情况,qq.login方法返回的code是一个空字符串,虽然不知道为什么但还是给登录方法加入了一个重新登录的功能

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
App({
...
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){
if(res.code === ""){
reLogin();
}else{
//ajax login
//if error reLogin
}
}
});
function reLogin(){
self.isGetTokening = false;
self.globalData.reLoginTimes++;
if(self.globalData.reLoginTimes >= 5){
self.exitApp();
}else{
setTimeout(self.doLogin, 1000);
}
}
},
...
});

分享其他页面之后回到首页

这个需求是当用户分享非首页的页面时,其他用户点击进入的是分享的那个页面,这时会出现一种情况,就是他可能无法返回到首页了,导致很多功能会无法使用,有一种解决办法是,使用自定义的顶部菜单,这样可以在顶部添加回到首页的按钮,但这种做法也会导致整个项目要考虑的兼容性问题非常多。另一种做法是,分享出去的页面都是首页,只不过会在地址栏中带上分享页面,首页接收到之后,跳转到那个页面,这样用户点击返回时就会跳到首页了。

首先,修改app.js中的获取分享信息方法shareDetail,将当前页面的地址添加到地址栏参数之中,添加之前要转义一下。还要记得把当前页面的option也都加上,不然可能导致页面错误

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
App({
...
shareDetail(needCurrent = false){
let
global = this,
pages = getCurrentPages(),
currentPage = pages[pages.length - 1],
tmp = {
title: "share title",
path: "/pages/index/index"
};
if(needCurrent){
let
path = `/${currentPage.route}?${makeUrlParams(currentPage.options)}`;
path = encodeURIComponent(path);
tmp.path += `?path=${path}`
}
//分享用户id
//tmp.path += `${needCurrent ? '&': '?'}fromuid=${Util.getTheUserID()}`;
return JSON.parse(JSON.stringify(tmp));

function makeUrlParams(datas){
let
tmp = [];
for(let i in datas){
tmp.push(`${i}=${datas[i]}`);
}
return tmp.join("&");
}
},
...
});

之后在首页的onLoad事件中,针对参数path进行判断并跳转,最好再添加一个遮照层,以避免未跳转前的页面显示问题

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
Page({
...
onLoad(option){
let
path = option.path || "";
if(!!path && path != ""){
path = decodeURIComponent(path);
Util.showLoading();
setTimeout(()=>{
qq.navigateTo({
url: path
});
setTimeout(()=>{
Util.hideLoading();
self.setData({
jumpmask: false
});
}, 800);
}, 250);
}else{
self.setData({
jumpmask: false
});
}
},
...
});