在微信小程序開發中,將圖片或者視頻保存到用戶手機是常見的業務需求之一。通過調用小程序的下載文件以及保存文件到相冊的API才能完成,后者會向用戶申請權限,一旦用戶不小心拒絕,那么下次保存文件的時候將不再彈出權限申請窗口,顯然這對用戶會造成困擾。
提示:如果用戶在首次權限申請中拒絕,則必須在小程序的設置模塊打開該權限,不再彈窗操作。
因此,作為開發者如何通過代碼去引導用戶正確操作呢?
首先我們可以通過API(wx.getSetting)獲取當前小程序的設置信息,查看當前的權限狀態。
wx.getSetting({ success: res => { console.log(res.authSetting) } })
提示:authSetting 是一個對象,保存當權用戶的所有權限設置,對象的 Key 為具體權限別名,Value 為授權狀態,即 true 已經授權;false 為拒絕該權限,如果沒有申請過授權,則不保存在該對象中。
權限別名請參考:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/authorize.html
如果沒有授權,可以調用授權API(wx.authorize)向用戶發起授權,同樣只有第一次授權限才會彈窗,如果被拒絕過,返回失敗。
wx.getSetting({ success: res => { // 保存到相冊的授權別名 res.scope = 'scope.writePhotosAlbum' if (!res.authSetting[res.scope]) { // 申請授權 wx.authorize({ scope: res.scope, success: res => { // 同意或已經授權 }, fail() { // 用戶拒絕授權 } }) } } })
因此,當用戶拒絕過授權后,只能引導用戶打開設置界面,開啟相關權限。打開設置的API(wx.openSetting)返回當前新的設置信息。
需要注意的是,wx.openSetting 無法直接調用,但可以在彈窗 wx.showModal 回調中打開。
梳理一下,先獲取設置信息,判斷是否授權,如果沒有或者拒絕過,然后引導用戶打開設置界面開啟相關權限。當然,即使如此,用戶可能仍然選擇不開啟權限,那只能提示用戶沒用權限,無法保存圖片或視頻,否則我們進行下一步操作。
整個過程完全是一個異步的操作,所以在封裝的代碼的時候,可以用 Promise 去完成。
分解一下操作,先下載視頻,然后判斷是否有權限保存圖片視頻文件(包括引導用戶開啟相關權限),最后才是去保存,這一步難點在獲取異步的操作,你得先知道用戶最后有沒有打開權限。
重點來了,業務代碼封裝。
下載圖片視頻,調用下載文件的API(wx.downloadFile)
function downloadFile(url, listener) { listener = listener || {} return new Promise((resolve, reject) => { listener.onStart && listener.onStart() const downloadTask = wx.downloadFile({ url, success: res => { // 下載狀態正常 if (res.statusCode == 200) { resolve(res) } else { reject(res) } } }) if (listener.onProgress) { downloadTask.onProgressUpdate(listener.onProgress) } }) }
上面封裝的 downloadFile 函數接受兩個參數,url 下載地址,listener 下載監聽回調,對象類型,listener.onStart 開始下載回調,listener.onProgress 下載進度回調
保存到相冊,繼續封裝,API(wx.saveVideoToPhotosAlbum)
調用很簡單,如下
const url = 'http://example.com/xxx.mp4' saveMediaToPhotosAlbum(url, { onStart() { wx.showToast({ title: '開始下載', }) }, onComplete(res) { wx.showToast({ title: '下載完成', }) }, onProgress(res) { // 下載進度回調 wx.showLoading({ title: res.progress + "%", }) } })
測試一下,你會發現,開始下載=》下載中=》進度在走,下載完成會彈出保存到相冊權限彈窗,當你點擊允許后提示已經保存到xxx(安卓)。好像挺完美,按照預想的過程走完,但別忘了,上面提到的授權問題,一旦拒絕,再調用就無法成功保存。
所以,在下載完成后還要進行授權操作,如果授權成功再保存到相冊,否則提示沒有權限無法保存。
同樣用 Promise 封裝
因為是要在文件下載完成后先判斷授權狀態,所以調用授權的代碼應該放在 downloadFile 函數中,繼續改造
function downloadFile(url, listener) { listener = listener || {} return new Promise((resolve, reject) => { listener.onStart && listener.onStart() const downloadTask = wx.downloadFile({ url, success: res => { // 下載狀態正常 if (res.statusCode == 200) { resolve(res) } else { reject(res) } } }) if (listener.onProgress) { downloadTask.onProgressUpdate(listener.onProgress) } }).then(res => { return authorize().then(() => res).catch(() => { listener.onComplete() return Promise.reject(null) }) }) }
到處就大功告成,趕緊去試試。