需求點
- 語音播放不跟隨系統鈴聲模式,
- 語音播放支持揚聲器/聽筒播放,
- 揚聲器模式下播放檢測到距離接近需要息屏(防誤觸)并實時轉換為聽筒播放,距離遠離需亮屏并轉回揚聲器播放,
- 聽筒模式下播放檢測距離變化不需要切換播放聲道,但距離接近需要息屏(防誤觸),距離遠離需要亮屏,
分析需求
首先明確一點,語音播放支持揚聲器/聽筒播放,那就只能使用plus.audio.createPlayer來實作,而切換播放聲道,可以使用plus.audio.createPlayer創建出來實體的setRoute()方法,
由3.4點需求,明確在播放語音時需要添加距離監聽器,這里可以使用plus.proximity.watchProximity來實時監聽設備接近距離,
最后一個接近息屏,遠離亮屏的需求,先把前面的做了,再看看如何實作吧,
實作
this.playMode:播放聲道(揚聲器 0,聽筒 1)
this.playState:play回呼中播放引數
- 距離監聽器
this.watchProximity = plus.proximity.watchProximity((distance) => {
/**
* iOS端接近為0,遠離為Infinity
* Android端接近為0,遠離為5
*/
if (this.playMode === 0) {
// 揚聲器模式下,需要對聲道進行實時修改
this.voicePlayer.pause();
if (distance !== 0) {
// 揚聲器
this.voicePlayer.setRoute(0);
} else {
// 聽筒
this.voicePlayer.setRoute(1);
}
this.voicePlayer.resume();
}
});
- 初始化播放器
this.voicePlayer = plus.audio.createPlayer({ src: 'xxx' });
this.voicePlayer.setRoute(this.playMode);
// 監聽自然播放完成
this.voicePlayer.addEventListener('ended', () => {
// 銷毀正在監聽設備距離的監聽器
if (this.watchProximity) {
plus.proximity.clearWatch(this.watchProximity);
this.watchProximity = null;
}
console.log('播放完畢了');
});
// 監聽音頻可以開始播放事件
this.voicePlayer.addEventListener('play', () => {
// 首次播放時會執行兩次回呼
if (this.playState !== 2) {
// plus.audio.ROUTE_SPEAKER:揚聲器 0
// plus.audio.ROUTE_EARPIECE:聽筒 1
this.voicePlayer.setRoute(this.playMode);
this.playState++;
}
});
// 監聽音頻播放錯誤事件
this.voicePlayer.addEventListener('error', (err) => {
console.log('報錯err', err);
// 銷毀正在監聽設備距離的監聽器
if (this.watchProximity) {
plus.proximity.clearWatch(this.watchProximity);
this.watchProximity = null;
}
});
- 播放
// 在正確的地方呼叫播放
this.voicePlayer.play();
播放后,發現語音在iOS端,是默認存在接近息屏,遠離亮屏的現象(默認行為);但是Android端在播放的時候,始終是亮屏的,看來Android端還需要自己實作,
播放時,初始播放模式為揚聲器模式,接近切換為聽筒,遠離切換回揚聲器,在iOS端是能完美表現的,切換無延遲;Android端切換是存在延遲的,好在延遲不影響播放,
播放時,初始播放模式為聽筒模式,Android端第一次播放音頻會存在幾秒鐘的卡頓延遲,且該卡頓是占播放時間的,也就是說第一次播放時不完整的,目前也沒有什么比較好的方案解決(暫時擱置),
Android端實作播放時接近息屏,遠離亮屏
該如何下手呢?博主查閱了plus幾乎所有的API,都沒有能找到相關的內容,看來又只能上Android官網找了,
直接上Android官網找跟電源相關的API,發現了PowerManager,在其中找到了一個電平模式PROXIMITY_SCREEN_OFF_WAKE_LOCK,具體如下:
這不就是我想要的答案嗎?事不宜遲,說干就干!
由于PowerManager電源管理類是屬于全域唯一的,故使用也不能像播放音頻那樣隨隨便便new一個實體出來,他需要借助Android的主實體物件plus.android.runtimeMainActivity()來呼叫獲取,
this.platform: 當前手機平臺
this.wakeLock:喚醒鎖
// Android端需要設定喚醒模式才能在接近傳感器激活時關閉螢屏,iOS端自帶了
if (this.platform === 'android') {
let main = plus.android.runtimeMainActivity();
let Context = plus.android.importClass('android.content.Context');
let PowerManager = plus.android.importClass('android.os.PowerManager');
let pm = main.getSystemService(Context.POWER_SERVICE);
// 32代表PROXIMITY_SCREEN_OFF_WAKE_LOCK,喚醒鎖定電平:當接近傳感器激活時關閉螢屏
let status = pm.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK);
// 系統支持該喚醒模式
if (status) {
this.wakeLock = pm.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, 'TAG');
this.wakeLock.acquire();
}
}
在剛剛初始化播放器時添加的監聽事件中,增加對喚醒模式資源的釋放
// 監聽自然播放完成
this.voicePlayer.addEventListener('ended', () => {
// 銷毀正在監聽設備距離的監聽器
if (this.watchProximity) {
plus.proximity.clearWatch(this.watchProximity);
this.watchProximity = null;
}
// 釋放喚醒鎖
if (this.wakeLock) {
this.wakeLock.release();
this.wakeLock = null;
}
console.log('播放完畢了');
});
// 監聽音頻播放錯誤事件
this.voicePlayer.addEventListener('error', (err) => {
console.log('報錯err', err);
// 釋放喚醒鎖
if (this.wakeLock) {
this.wakeLock.release();
this.wakeLock = null;
}
// 銷毀正在監聽設備距離的監聽器
if (this.watchProximity) {
plus.proximity.clearWatch(this.watchProximity);
this.watchProximity = null;
}
});
至此,所有的需求都圓滿完成了!
總結
隨著對uniapp的深入了解,越來越多功能點的實作,開發人員不止需要把視角放在前端,還需要轉戰到Android、iOS官方查閱相關的API檔案才能實作,
按照這個趨勢,博主認為凡是手機系統底層實作了的功能,但uniapp未實作的,都可以通過plus.android或者plus.ios通過呼叫相關功能類來實作,這泥潭算是越陷越深了,
總而言之,Keep learning…
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/296631.html
標籤:其他
