《QQ音乐小电台》小程序开发

2022-06-29 17:17:37 浏览数 (2)

《QQ音乐小电台》主要分享在开发过程中核心功能实现和踩过的坑,希望对开发音频播放的同学有所帮助。

作者:任洋--腾讯web前端助理工程师

@IMWeb前端社区

QQ音乐电台小程序的核心功能

  1. 开启电台
  2. 好友卡片
  3. 引导页(引导用户用微信登录QQ音乐或开启冷启动)
  4. 冷启动
  5. 卡片详情(好友相似度,好友偏好,评论)
  6. 歌曲播放页(播放暂停,歌词滚动,收藏歌曲,切换歌曲,听歌流水上报,背景魔法色,适配)
  7. miniplayer (切换歌曲,状态同步)

核心功能实现

音频状态同步

涉及播放歌曲状态同步,不能使用audio组件。而音频播放API本质上是借助微信native的播放组件。

使用wx.navigateTo() 跳转到应用内的某个页面,会保留当前页面。点击左上角返回,之前页面会触发onShow监听页面显示,不会触发onLoad事件。播放页和首页miniplayer状态同步相关逻辑处理应该在onShow事件监听。

歌曲信息以及变更(包括歌曲列表,播放状态,切换音频,专辑图,歌曲名,歌手等)存储在小程序提供的storage下,方便不同页面数据同步

歌词滚动

音频组件API目前没有提供类似audio的onTimeUpdate事件,需要开了一个定时器做歌词滚动,缺点是定时器做歌词渲染有不太精准。好消息是:微信后期会支持OnTimeUpdate事件。 歌词处理相关逻辑如下:

歌词背景魔法色

根据专辑图拉取对应十六进制的魔法色。有些色值较亮,有点刺眼,这里需要对色值转为HSL通过降低饱和度S和亮度L来使得背景色看着柔和。

将后台返回十六进制,转为RGB值

RGB转为HSL

降低HSL 中S饱和度,L亮度让背景色不刺眼

将降低后HSL转为RGB

降低饱和度和亮度之后的效果图,背景变柔和

异常处理

image组件图片数据没有返回或图片加载失败异常处理

弱网络环境下cgi加载慢或cgi异常菊花提示,加载成功后隐藏菊花,wx.showToast最大延迟时间是10000

对网络异常或cgi逻辑处理失败做友好提示,且对cgi成功率做上报。

前端异常上报,当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并返回错误信息,获取设备信息,方便后期定位问题

音乐播放控制bug&fix

安卓下,暂停不能继续播放的问题

原因是暂停再播放时,微信旧版本安卓上会检测playBackgroundAudio的title和coverImgUrl参数,后来fix这个bug,为了兼容之前版本,还是将参数传入。

IOS、安卓播放暂停切歌

IOS,安卓机下播放过程中先暂停在切换歌曲,发现播放的歌曲为原先的歌曲。

解决方法:暂停场景下更换音频地址wx.playBackgroundAudio({dataUrl:’xxx’})之前需要调用wx.stopBackgroundAudio。

带来问题:音频播放完成以及播放音频文件有误403或500都会触发wx.onBackgroundAudioStop事件。好消息是微信之后会对播放音频API进行大的改动,用不同事件分别触发停止播放,播放结束,播放错误。

安卓同步播放状态

安卓机下播放一首歌曲且同时打开新页面(播放页),同步上一页面播放态,wx.getBackgroundAudioPlayerState在有歌曲播放的情况下status返回为2,且状态返回dataUrl和播放url对不上。(wx.getBackgroundAudioPlayerState的播放有三个状态:1是播放中,0是暂停,2是没有音乐播放。2状态是微信小程序后期加的。)

解决方法:将播放链接存在storage里面,获取storage链接作为播放链接。

小程序基础学习

小程序官方文档很详细,下面是对小程序一些关键知识提炼。

mina框架

js:逻辑层的开发

WXML:页面布局

WXSS:页面的样式

整个系统分为两块视图层(View)和逻辑层(App Service)。

页面js中,data数据是需要约定为只读。MINA是单向数据绑定,修改data中的数据不会自动更新View;更新view,需要使用setData()方法。setData()更新View时,与data中的数据进行Diff比较,不同才会更新。如果直接修改data,很容易造成data中的数据与View不一致。setData单次设置的数据不能超过1024kB,需要避免一次设置过多的数据。

每个小程序分为两个线程,view和appServer。其中view线程负责解析渲染页面(wxml和wxss),而appServer线程负责运行js。appServer线程运行在jsCore中(安卓下运行在X5中,开发工具中运行在nwjs中),所以js不跑在webview里,不能直接操纵DOM和BOM,这就是为什么小程序没有window全局变量。

目录结构(小程序包含一个描述整体程序的 app 和多个描述各自页面的 page) 小程序的框架程序包含一个描述整体程序的app 和多个描述页面的page。其中,app由三个文件构成,公共设置的app.json 、公共样式的app.wxss、主体逻辑的app.js 。每个page由四部分组成,页面设置page.json、页面文件page.wxml、页面样式page.wxss、页面主体逻辑page.js。

逻辑层

App() 函数用来注册一个小程序。接受一个 object 参数,其指定小程序的生命周期函数等

object参数说明:

Page object 参数说明:

一个page的生命周期从onLoad开始,整个生命周期内onLoad、onReady、onUnload这三个事件仅执行一次,而onHide和onShow在每次页面隐藏和显示时都会触发,执行顺序是onLoad,onShow,onReady。当用户手动触发左上角的退出箭头时,小程序仅触发app.onHide,下次进入小程序时会触发app.onShow以及当前page.onShow。仅当小程序在后台运行超过一定时间未被唤起、或者用户手动在小程序的控制栏里点击退出程序、或者小程序内存占用过大被关闭时,小程序被销毁,会触发app.onUnload事件。

一个完整的小程序执行的生命周期如下

模块化

将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。模块只有通过module.exports 或者 exports 才能对外暴露接口。在需要使用这些模块的文件中,使用 require(path) 将公共代码引入。框架对各个js的模块化,你编写的代码,执行之前会帮你AMD化处理

视图层

1、字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。

2、保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字

3、数据绑定

WXML 中的动态数据均来自对应 Page 的 data,数据绑定使用 Mustache 语法(双大括号)将变量包起来。支持组件属性,控制属性,关键字。支持多种运算如:三目运算,算数运算,字符串运算,逻辑判断

4、条件渲染

wx:if 有更高的切换消耗而 hidden 有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden 更好,如果在运行时条件不大可能改变则 wx:if 较好。

5、列表渲染

wx:key 当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。

wx:key 的值以两种形式提供

6、模版

WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用

7、事件

key 以bindcatch开头,然后跟上事件的类型,如bindtapcatchtouchstart

bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡

8、引用

WXML 提供两种文件引用方式importinclude。区别在于:import可以引入定义好的template模板,模板是有作用域的;而include就是拷贝一个公用的代码片段到目标文件中,适合做公共页面片的拆分

WXSS

1、WXSS新引入了一个rpx的概念来做自适应布局。rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在iPhone6上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。

2、本地资源无法通过WXSS获取,所以WXSS中的样式都是用的网络图片,或者base64

api

wx.request

wx.request发起的是 HTTPS 请求。

data 数据说明 最终发送给服务器的数据是 String 类型,如果传入的 data 不是 String 类型,会被转换成 String 。转换规则如下

content-type 默认为 ‘application/json’

要注意 method 的 value 必须为大写

request 的最大并发数是 5

网络请求的 referer 是不可以设置的,格式固定为https://servicewechat.com/{appid}/{version}/page-frame.html,其中 {appid} 为小程序的 appid,{version} 为小程序的版本号,版本号为 0 表示为开发版。

request 的默认超时时间和最大超时时间都是 60s

通讯域名配置:小程序可以跟指定的域名进行网络通信

1、对于 header[‘content-type’] 为 ‘application/json’ 的数据,会对数据进行 JSON 序列化

2、对于 header[‘content-type’] 为 ‘application/x-www-form-urlencoded’ 的数据,会将数据转换成 query string (encodeURIComponent(k)=encodeURIComponent(v)&encodeURIComponent(k)=encodeURIComponent(v)…)

音乐播放

wx.getBackgroundAduioPlayerState 获取后台音乐播放状态,(播放状态同步和歌词渲染)

wx.playBackrgoundAudio 使用后台播放器播放音乐,对于微信客户端来说,只能同时有一个后台音乐在播放。当用户离开小程序后,音乐将暂停播放;当用户点击“显示在聊天顶部”时,音乐不会暂停播放;当用户在其他小程序占用了音乐播放器,原有小程序内的音乐将停止播放。

wx.pauseBackgroundAudio() 暂停播放音乐

wx.seekBackgroundAudio()控制音乐播放进度

1、wx.stopBackgroundAudio() 停止播放音乐,会触发wx.onBackgroundAudioStop()

2、wx.onBackgroundAudioStop() 监听音乐停止

数据缓存

微信小程序没有Cookie、sessionStorage和localStorage,而是提供了一个app的本地存储,对存储的操作可以异步、同步的增删改查。

设备(用在手机适配,异常错误上报获取设备信息,以及不同微信版本做兼容)提供异步和同步二种方式wx.getSystemInfo() || wx.getSystemInfoSync()

success回调参数说明:

界面

交互反馈

wx.showToast() wx.hideToast(

wx.showModal()

1、wx.navigateTo() 保留当前页面,跳转到应用内的某个页面,使用wx.navigateBack可以返回到原页面

2、wx.redirectTo 关闭当前页面,跳转到应用内的某个页面。

一个应用同时只能打开5个页面,当已经打开了5个页面之后,wx.navigateTo不能正常打开新页面。请避免多层级的交互方式,或者使wx.redirectTo

开发接口

1、wx.login 调用接口获取登录凭证(code)进而换取用户登录态信息,包括用户的唯一标识(openid) 及本次登录的 会话密钥(session_key)。用户数据的加解密通讯需要依赖会话密钥完成。

2、wx.getUserInfo 获取用户信息,需要先调用 wx.login 接口。

3、分享图片不能自定义;会取当前页面,从顶部开始,高度为 80% 屏幕宽度的图像作为分享图片。

扫码下方二维码,

随时关注更多前端干货文章!

微信:IMWebTech

0 人点赞