1***@qq.com
1***@qq.com
  • 发布:2025-09-28 13:33
  • 更新:2025-09-28 13:33
  • 阅读:23

【报Bug】getBackgroundAudioManager在鸿蒙系统下onWaiting不会执行

分类:鸿蒙Next

产品分类: uniapp/App

PC开发环境操作系统: Windows

PC开发环境操作系统版本号: win11

HBuilderX类型: 正式

HBuilderX版本号: 4.76

手机系统: HarmonyOS NEXT

手机系统版本号: HarmonyOS 5.1.0

手机厂商: 模拟器

手机机型: 模拟器api19

页面类型: vue

vue版本: vue3

打包方式: 云端

项目创建方式: HBuilderX

示例代码:

    <view class="listen">  
        <view class="header">  
            <text class="title">Listening</text>  
            <view class="right">  
                <text class="book-icon">?</text>  
                <text class="link">绘本馆</text>  
            </view>  
        </view>  

        <image :src="cover" class="cover"></image>  
        <text class="book">{{ title }}</text>  

        <view class="slider-wrap">  
            <slider   
                :value="progress"   
                :disabled="totalSeconds===0"   
                @changing="onChanging"   
                @change="onSeek"   
                activeColor="#0E4B3B"   
                backgroundColor="#e0e0e0"  
                block-size="20"   
                step="1"  
                min="0"  
                max="100"  
            />  
            <view class="time-row">  
                <text class="t">{{ displayCurrentLabel }}</text>  
                <view class="rate-pill" @tap="changeRate">{{ rateLabel }}</view>  
                <text class="t">{{ displayDurationLabel }}</text>  
            </view>  
        </view>  

        <view class="controls">  
            <text class="ctrl" @tap="toggleShuffle">?</text>  
            <text class="ctrl" @tap="prev15">⏮️</text>  
            <view class="play" @tap="togglePlay">  
                <view v-if="showSpinner" class="loading-spinner"></view>  
                <text v-else class="play-icon">{{ playing ? '⏸️' : '▶️' }}</text>  
            </view>  
            <text class="ctrl" @tap="next15">⏭️</text>  
            <text class="ctrl" @tap="toggleLoop">?</text>  
        </view>  
    </view>  
</template>  

<script>  
    export default {  
        data(){  
            return {  
                cover: '/static/images/sample-cover.jpg',  
                title: 'Sample Story',  
                src: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3',  
                playing: false,  
                loading: false,  
                progress: 0,  
                currentLabel: '00:00',  
                durationLabel: '03:45',  
                totalSeconds: 225,  
                currentSeconds: 0,  
                loop: false,  
                rates: [0.75, 1, 1.5],  
                rateIdx: 1,  
                timer: null,  
                audioManager: null,  
                useRealAudio: true,  
                isHarmony: false,  
                supportRate: true,  
                isDragging: false,  
                previewSeconds: 0  
            }  
        },  
        computed:{  
            rate(){ return this.rates[this.rateIdx] },  
            rateLabel(){ return this.rate + 'x' },  
            displayCurrentLabel(){   
                if(this.isDragging) {  
                    return this.formatTime(this.previewSeconds) + ' ?'  
                }  
                if(this.loading) {  
                    return this.currentLabel + ' ⏳'  
                }  
                return this.currentLabel   
            },  
            displayDurationLabel(){   
                return this.formatTime(this.totalSeconds)   
            },  
            showSpinner() {  
                return this.loading  
            }  
        },  
        onLoad(query){  
            if(query && query.title){   
                this.title = decodeURIComponent(query.title)   
            }  
            console.log('熏听页面加载,标题:', this.title)  

            // 延迟初始化音频,避免启动时崩溃  
            setTimeout(() => {  
                this.initAudio()  
            }, 500)  
        },  
        onUnload() {  
            this.cleanup()  
        },  
        methods: {  
            initAudio() {  
                try {  
                    // 检测平台  
                    const sys = uni.getSystemInfoSync && uni.getSystemInfoSync()  
                    if((sys && /harmony/i.test(sys.osName||'')) || (typeof plus!=='undefined' && plus.os && /harmony/i.test(plus.os.name||''))){  
                        this.isHarmony = true  
                        this.supportRate = false  
                    }  

                    // 尝试创建背景音频管理器  
                    this.audioManager = uni.getBackgroundAudioManager()  
                    this.audioManager.title = this.title  
                    this.audioManager.src = this.src  

                    // 设置加载状态  
                    this.loading = true  

                    // 绑定音频事件  
                    this.audioManager.onWaiting(() => {  
                        console.log('音频缓冲中,设置loading状态')  
                        this.loading = true  
                        // loading状态会由onCanplay或onPlay事件清除  
                    })  

                    this.audioManager.onCanplay(() => {  
                        console.log('音频可以播放')  
                        this.loading = false  
                    })  

                    this.audioManager.onPlay(() => {  
                        console.log('音频开始播放')  
                        this.playing = true  
                        this.loading = false  
                        this.startProgressTimer()  
                    })  

                    this.audioManager.onPause(() => {  
                        console.log('音频暂停')  
                        this.playing = false  
                        this.loading = false  
                        this.clearTimer()  
                    })  

                    this.audioManager.onStop(() => {  
                        console.log('音频停止')  
                        this.playing = false  
                        this.loading = false  
                        this.progress = 0  
                        this.currentSeconds = 0  
                        this.updateDisplay()  
                        this.clearTimer()  
                    })  

                    this.audioManager.onEnded(() => {  
                        console.log('音频播放结束')  
                        this.loading = false  
                        if(this.loop) {  
                            this.loading = true  
                            this.audioManager.seek(0)  
                            this.audioManager.play()  
                        } else {  
                            this.playing = false  
                            this.clearTimer()  
                        }  
                    })  

                    this.audioManager.onTimeUpdate(() => {  
                        if(this.audioManager.duration > 0) {  
                            this.totalSeconds = this.audioManager.duration || 0  
                            this.currentSeconds = this.audioManager.currentTime || 0  
                            this.updateDisplay()  
                        }  
                    })  

                    this.audioManager.onError((e) => {  
                        console.warn('音频播放出错:', e)  
                        this.loading = false  
                        this.fallbackToSimulation()  
                    })  

                    console.log('音频管理器初始化成功')  

                } catch(e) {  
                    console.warn('音频管理器初始化失败,使用模拟播放:', e)  
                    this.loading = false  
                    this.fallbackToSimulation()  
                }  
            },  

            fallbackToSimulation() {  
                console.log('切换到模拟播放模式')  
                this.useRealAudio = false  
                this.audioManager = null  
            },  

            formatTime(seconds) {  
                if(!seconds || seconds < 0) return '00:00'  
                const mins = Math.floor(seconds / 60) || 0  
                const secs = Math.floor(seconds % 60) || 0  
                return `${mins.toString().padStart(2,'0')}:${secs.toString().padStart(2,'0')}`  
            },  

            updateDisplay() {  
                this.currentLabel = this.formatTime(this.currentSeconds || 0)  
                this.durationLabel = this.formatTime(this.totalSeconds || 0)  

                // 拖拽时不更新progress,避免冲突  
                if(!this.isDragging) {  
                    if(this.totalSeconds > 0) {  
                        this.progress = Math.floor((this.currentSeconds / this.totalSeconds) * 100) || 0  
                    } else {  
                        this.progress = 0  
                    }  
                }  
            },  

            startProgressTimer() {  
                this.clearTimer()  
                if(!this.useRealAudio) {  
                    this.timer = setInterval(() => {  
                        if(this.playing && this.currentSeconds < this.totalSeconds) {  
                            this.currentSeconds += this.rate  
                            this.updateDisplay()  
                        } else if(this.currentSeconds >= this.totalSeconds) {  
                            if(this.loop) {  
                                this.currentSeconds = 0  
                                this.updateDisplay()  
                            } else {  
                                this.playing = false  
                                this.clearTimer()  
                            }  
                        }  
                    }, 1000)  
                }  
            },  

            togglePlay(){   
                if(this.loading) {  
                    uni.showToast({   
                        title: '音频加载中,请稍候',   
                        icon: 'none'   
                    })  
                    return  
                }  

                if(this.useRealAudio && this.audioManager) {  
                    try {  
                        if(this.playing) {  
                            this.audioManager.pause()  
                        } else {  
                            this.loading = true  
                            this.audioManager.play()  
                        }  
                    } catch(e) {  
                        console.warn('音频操作失败,切换到模拟模式:', e)  
                        this.loading = false  
                        this.fallbackToSimulation()  
                        this.togglePlaySimulation()  
                    }  
                } else {  
                    this.togglePlaySimulation()  
                }  
            },  

            togglePlaySimulation() {  
                this.playing = !this.playing  
                uni.showToast({   
                    title: this.playing ? '开始播放(模拟)' : '暂停播放',   
                    icon: 'none'   
                })  

                if(this.playing) {  
                    this.startProgressTimer()  
                } else {  
                    this.clearTimer()  
                }  
            },  

            clearTimer() {  
                if(this.timer) {  
                    clearInterval(this.timer)  
                    this.timer = null  
                }  
            },  

            onChanging(e) {  
                console.log('滑块拖拽中:', e.detail.value)  
                this.isDragging = true  
                const value = Number(e.detail.value) || 0  

                // 计算预览时间  
                if(this.totalSeconds > 0) {  
                    this.previewSeconds = Math.max(0, (this.totalSeconds * value) / 100)  
                } else {  
                    this.previewSeconds = 0  
                }  

                // 注意:不需要手动设置progress,slider组件会自动处理  
                console.log('预览时间:', this.previewSeconds, '秒')  
            },  

            onSeek(e) {  
                console.log('滑块拖拽结束:', e.detail.value)  

                const value = Number(e.detail.value) || 0  

                if(this.totalSeconds <= 0) {  
                    this.isDragging = false  
                    return  
                }  

                const targetSeconds = Math.max(0, (this.totalSeconds * value) / 100)  
                console.log('跳转到目标时间:', targetSeconds, '秒')  

                // 立即更新currentSeconds,确保界面同步  
                this.currentSeconds = targetSeconds  

                if(this.useRealAudio && this.audioManager) {  
                    try {  
                        console.log('真实音频跳转')  
                        this.loading = true  
                        this.audioManager.seek(targetSeconds)  
                    } catch(e) {  
                        console.warn('音频跳转失败:', e)  
                    }  
                } else {  
                    console.log('模拟音频跳转')  
                    // 模拟音频直接更新  
                }  

                // 更新显示并清除拖拽状态  
                this.updateDisplay()  
                this.isDragging = false  
            },  

            prev15(){   
                const newTime = Math.max(0, (this.currentSeconds || 0) - 15)  

                if(this.useRealAudio && this.audioManager) {  
                    try {  
                        this.audioManager.seek(newTime)  
                    } catch(e) {  
                        console.warn('跳转失败:', e)  
                        this.currentSeconds = newTime  
                        this.updateDisplay()  
                    }  
                } else {  
                    this.currentSeconds = newTime  
                    this.updateDisplay()  
                }  

                uni.showToast({ title: '后退15秒', icon: 'none' })  
            },  

            next15(){   
                const newTime = Math.min((this.totalSeconds || 0), (this.currentSeconds || 0) + 15)  

                if(this.useRealAudio && this.audioManager) {  
                    try {  
                        this.audioManager.seek(newTime)  
                    } catch(e) {  
                        console.warn('跳转失败:', e)  
                        this.currentSeconds = newTime  
                        this.updateDisplay()  
                    }  
                } else {  
                    this.currentSeconds = newTime  
                    this.updateDisplay()  
                }  

                uni.showToast({ title: '快进15秒', icon: 'none' })  
            },  

            changeRate(){   
                if(!this.supportRate) {  
                    uni.showToast({ title:'当前平台不支持倍速', icon:'none' })  
                    return  
                }  

                this.rateIdx = (this.rateIdx + 1) % this.rates.length  

                if(this.useRealAudio && this.audioManager) {  
                    try {  
                        this.audioManager.playbackRate = this.rate  
                    } catch(e) {  
                        console.warn('设置倍速失败:', e)  
                        this.supportRate = false  
                    }  
                }  

                uni.showToast({ title: '倍速 ' + this.rate + 'x', icon:'none' })   
            },  

            toggleLoop(){   
                this.loop = !this.loop  
                uni.showToast({ title: this.loop ? '循环播放' : '关闭循环', icon:'none' })   
            },  

            toggleShuffle(){   
                uni.showToast({ title:'随机播放(占位)', icon:'none' })   
            },  

            cleanup() {  
                this.clearTimer()  
                if(this.audioManager) {  
                    try {  
                        this.audioManager.stop()  
                    } catch(e) {  
                        console.warn('停止音频失败:', e)  
                    }  
                }  
            }  
        }  
    }  
</script>  

<style scoped>  
    .listen{  
        padding: 12rpx;   
        background: #f5f7f9;   
        height: 100vh;   
        display: flex;   
        flex-direction: column;   
        justify-content: space-between;   
        box-sizing: border-box;  
    }  

    .header{   
        display: flex;   
        justify-content: space-between;   
        align-items: center;   
        margin-bottom: 6rpx;   
        flex-shrink: 0;   
    }  

    .title{   
        font-size: 40rpx;   
        font-weight: 800;   
        color: #333;   
    }  

    .right{   
        display: flex;   
        align-items: center;   
        color: #0E4B3B;   
    }  

    .book-icon{   
        margin-right: 6rpx;   
    }  

    .link{   
        color: #0E4B3B;   
    }  

    .cover{   
        width: 280rpx;   
        height: 320rpx;   
        border-radius: 8rpx;   
        display: block;   
        margin: 12rpx auto 6rpx;   
        flex-shrink: 0;   
    }  

    .book{   
        text-align: center;   
        font-size: 24rpx;   
        font-weight: 700;   
        color: #333;   
        margin-bottom: 12rpx;   
        flex-shrink: 0;   
    }  

    .slider-wrap{   
        padding: 0 16rpx;   
        margin: 6rpx 0;   
        flex-shrink: 0;  
    }  

    .time-row{   
        display: flex;   
        justify-content: space-between;   
        align-items: center;   
        color: #7a7f7d;   
        font-size: 20rpx;   
        margin-top: 4rpx;   
    }  

    .t{   
        min-width: 70rpx;   
        text-align: center;   
    }  

    .rate-pill{   
        padding: 4rpx 8rpx;   
        border-radius: 12rpx;   
        background: #e8f3ef;   
        color: #0E4B3B;   
        font-size: 18rpx;   
    }  

    .controls{   
        display: flex;   
        justify-content: space-around;   
        align-items: center;   
        margin: 12rpx 0;   
        flex-shrink: 0;   
    }  

    .ctrl{   
        font-size: 32rpx;   
        color: #0E4B3B;   
    }  

    .play{   
        width: 100rpx;   
        height: 100rpx;   
        border-radius: 50rpx;   
        background: #0E4B3B;   
        display: flex;   
        align-items: center;   
        justify-content: center;  
    }  

    .play-icon{   
        color: white;   
        font-size: 40rpx;   
    }  

    .loading-spinner {  
        width: 40rpx;  
        height: 40rpx;  
        border: 4rpx solid rgba(255, 255, 255, 0.3);  
        border-top: 4rpx solid white;  
        border-radius: 50%;  
        animation: spin 1s linear infinite;  
    }  

    @keyframes spin {  
        0% { transform: rotate(0deg); }  
        100% { transform: rotate(360deg); }  
    }  
</style>  ``` 

操作步骤:

直接点播放音频,安卓上可以有loading效果,鸿蒙就没有

预期结果:

onWaiting执行,出现loading

实际结果:

onWaiting并没有执行

bug描述:

鸿蒙系统下使用getBackgroundAudioManager,onWaiting监听不会执行,onWaiting之后的onPlay也不会执行,onPlay只会执行第一次

2025-09-28 13:33 负责人:无 分享
已邀请:

要回复问题请先登录注册