前言
这里是一个工作了1年多的前端小白,这是从业以来的第一篇文章,主要跟大家分享一下最近在开发字节跳动小程序时遇到一些问题与自己的解决方法,如果有什么更好的解决方案欢迎大佬们指点一下,写的不好的地方还请各位多多谅解。
项目说明
这是一个基于字节跳动平台开发的小程序,业务主要在抖音上面,属于一个咨询、电商类的小程序(关于字节跳动发表的电商类入驻名额不做过多讨论,这不是我一个开发该考虑的问题。),主要的功能点包括即时通讯,商品订单,订单中心。
遇到的问题
-
即时通讯(环信IM)
即时通讯应该是在该项目中遇到问题最多的一块了,因为项目周期的问题,考虑到从新开发socket功能成本较高,所以公司决定对接第三方的能力,这里对接的是环信IM-
sdk修改:因为环信中提供的demo是微信小程序的,所以下载环信小程序demo之后还需要对sdk进行一下兼容性修改,其实也就是将sdk中调用到微信api的前缀(wx.)替换成字节跳动的(tt.)即可,不过有些微信上有而字节跳动上没有的api记得删除一下,不然会报错。【Tip: 其实不将 wx. 替换成 tt. 也没关系,因为微信api可以在字节跳动上直接运行,亲测有效,不过字节跳动的api前缀就无法在微信小程序上运行了。】
-
IM重连:根据环信IM提供的文档进行IM登陆操作,在开发者工具中一切显示正常,但是到了真机调试中问题就来,小程序断连之后就无法重连了,经过多次测试发现了几种情况。
autoReconnectNumMax: 15 // 设置 IM 最多重连次数
- 切换程序时,隔4 ~ 10秒再将抖音切换回到前台,这时候控制台打印socket连接关闭 -> 重新连接 -> 连接失败。(偶尔会重连成功)
- 小程序保持在前台,这时候锁屏操作,隔10s以上后重新解锁屏幕,控制台打印了 n(n < autoReconnectNumMax) 次重连失败提示,也就是说在锁屏期间小程序会一直尝试重新连接IM,重连次数与锁屏时间有关,重连次数不会超过设置的最多重连次数。
【疑问:为什么隔短短一段时间socket就会断开且重连会失败,是否与环信那边有关,还是说抖音app进入后台之后进程就停止了,导致socket断开链接,断开之后为什么重连会失败。相同的代码段放在微信小程序中不会出现以上的所有问题,即使断开连接微信也能重新连接成功。附:字节跳动社区提问】
【解决方法:使用小程序中入口函数的onShow监听小程序回到前台时,断开连接,重新新建连接。(虽然解决了当前重连失败的问题,但是不论切换小程序相隔几秒都会断开之前的连接,会导致接受到消息有延迟。)】
/* app.js */ onShow() { if (JSON.stringify(this.globalData.conn) !== '{}') { WebIM.conn.close() // 关闭之前的socket this.conn.open(this.globalData.conn) // 连接socket } }
- 安卓图片消息发送失败:安卓端在发送图片时需要拉起相册,这个时候程序进入了后台,当选完图片时返回到小程序,socket已经断开了连接,导致图片发送失败,无论选择图片的速度多快,都会断开连接,而iOS端是在内部访问的相册,不存在切到后台的问题,所以不会断连。
【解决方法:上述点2中IM重连的解决方法也是为了解决安卓端图片发送问题设计的】 - 重连成功之前消息发送失败:由于点2中的解决方式,如果用户存停留于聊天室中,这时候切换引用或锁屏后重新回到小程序导致重连还未完成,在此之前的消息发送失败。
【解决方法:在小程序隐藏时(onHide)设置可发送消息标识设为flase,监听连接成功事件,可连接成功时可发送消息标识改为true,此期间发送的消息到存到消息队列中,等到连接成功时再将消息重新发送。】
// 全局监听事件参考环信提供的demo进行改写 /* app.js */ onLaunch() { WebIM.conn.listen({ // socket监听 onOpened(message){ disp.fire('im.opened', message) }, ... }) } onHide() { disp.fire("miniprogram.hide") // 监听小程序隐藏 } /* im.js 聊天室 */ // 监听im是否连接 disp.on('im.opened', () => { that.setData({ canSend: true }) that.sendWaitMsg() // 将消息队列里的消息重新发送 }) // 监听小程序进入后台 disp.on('miniprogram.hide', () => { that.setData({ canSend: false }) })
-
-
音频播放
- iOS端语音播放问题:在发送语音消息中发现,iOS端发送的语音下载下来后没办法播放的问题,本地播放是正常播放的,但是上传到服务器后下载下来却无法播放。
【解决方法:上传语音文件时,本地临时录音文件会带有一串query参数,将录音文件的带参去掉再上传,这样下载下来就能够正常播放了。】
// 全局唯一的录音管理器 const recorderManager = tt.getRecorderManager() ... recorderManager.onStop(res => { let { tempFilePath } = res tt.uploadFile({ url: '', filePath: tempFilePath.split('?')[0], name: 'file', header: { 'Content-Type': 'multipart/form-data' }, success: res => { ... } }) }) recorderManager.stop()
- 安卓端无法播放语音的问题:下载下来的音频格式小程序不支持播放,在下载头部中声明了’Accept’: 'audio/mp3’的格式,却没办法正常转换,后来去论坛问了一下,官方回复的结果是安卓端下载api头部声明没生效的问题导致的。附:字节跳动社区提问。
【暂时解决方法:由于api头部不生效,所以将下载链接发送给后端,后端通过添加头部将文件下载为mp3格式,存储到oss上再返回给前端,这个时候音频就是mp3格式能正常播放了。当然这不是最理想的方法,毕竟会占用oss存储空间,也只能等字节跳动官方修复了。】
/* tt.downloadFile({ url: '音频地址', header: { "X-Requested-With": "XMLHttpRequest", 'Accept': 'audio/mp3' // 该头部在安卓端中无法生效,下载的格式为非小程序支持的音频格式时无法播放。 }, success: res => { ... } }) */
- iOS端语音播放问题:在发送语音消息中发现,iOS端发送的语音下载下来后没办法播放的问题,本地播放是正常播放的,但是上传到服务器后下载下来却无法播放。
-
支付:由于小程序主要运营于抖音app中,所以这里对接的收银台功能。
- 微信小程序:在拉起微信支付时,无论是否支付成功,字节跳动api回调都只会返回给你code = 9,无法判断支付状态。
【解决方法:后端提供订单查询接口,支付回调时再去查询一次支付结果。】
- 微信小程序:在拉起微信支付时,无论是否支付成功,字节跳动api回调都只会返回给你code = 9,无法判断支付状态。
-
安卓端图片文件保存失败:官方文档上说明了tt.saveImageToPhotosAlbum不支持网络图片格式,通过tt.downloadFile将图片文件下载下来后本地是个文件流,导致非图片格式,保存失败。
【暂时解决方案:通过tt.setClipboardData帮用户复制文件下载链接,提示用户去浏览器下载。】
总结
这次接触字节跳动小程序也算是一个踩坑的过程,官方文档上的说明还是有所欠缺,社区上的活跃度也不高,靠自己慢慢摸索尝试,不过也锻炼了自己的思考能力。后面如果迭代遇到新的问题的话也会更新到文章上,希望能对也在开发字节跳动小程序的小伙伴有一点点帮助。