更新记录

1.2.46(2026-06-25)

  • 修复 uni-app x 客户在业务工具文件中使用 const options: any = { loopMode: 'all' } 后调用 setLoopMode(options) 可能触发 UTS 参数类型不匹配的问题;根入口现在会把动态 options 归一化为 SetLoopModeOptions 后再调用平台层。
  • Android 平台公开入口同步放宽 setLoopMode(options) 入参,兼容误用平台深路径或 HBuilderX 生成层把参数标记为 Any 的场景。
  • uni-app x 示例新增 Any循环 all/off 测试按钮,用于真机验证客户同款 any 参数调用。
  • 兼容性说明:本版本不修改播放队列、媒体卡、原生 Kotlin/Swift 播放逻辑,也不删除 uni-app 的 web/mp/app-plus 兼容入口。

1.2.45(2026-06-23)

  • Android 回调桥接修复:pause / resume / stop / skipToNext / skipToPrev / getPlayerState / getCapabilities 等入口不再把 BridgeCallbacksImpl 强转为 ActionOptions 或其他接口 type,统一从动态 options 中提取 success / fail / complete 后构造真实回调对象,修复 uni-app x 自定义基座点击按钮被拦截的问题。
  • Android 播放控制链路修复:根入口与 utssdk/app-android 保持一致的动态 options 归一化策略,避免 BridgeCallbacksImpl cannot be cast to ActionOptionsBackgroundAudioEvent cannot be cast to UTSJSONObject 等运行时类型转换异常影响播放、暂停、继续、停止和切歌。
  • uni-app x 示例页兼容修复:示例调用改为动态 options 传参并增强运行时异常提示,避免 DemoOptions 与公开接口 type 不匹配导致编译错误,同时保留自定义基座缺少原生生成物时的可读诊断。
  • 验证结果:Android 自定义基座真机验证通过,initPlayer / setPlaylist / play / pause / resume / stop / skipToNext / getPlayerState / getCapabilities 均可正常回调;skipToPrev 在第一首时返回“没有上一首曲目”为预期业务失败。
  • 兼容性说明:本版本未删除 uni-app 的 web/mp/app-plus 兼容实现;共享根入口只增强动态回调归一化,已同步到 uni-app 与 uni-app x 两个验证项目,保持插件目录统一。

1.2.44(2026-06-17)

  • 发布整合版本:延续 1.2.43 的 iOS 云打包兼容修复和标准基座兜底能力,统一纳入本轮多插件发布批次。
  • 补充发布口径:README、package.jsonuni_modules.json 当前版本同步到 1.2.44,便于插件市场按本轮修复集合统一上架。
  • 验证提醒:iOS 原生背景音频、锁屏控制和媒体卡能力仍需重新制作自定义基座或正式包验证,避免继续运行旧基座。
  • 兼容性说明:本版本只更新发布元数据和修复日志,不改变 1.2.43 已验证的 uni-app / uni-app x 运行逻辑。
查看更多

平台兼容性

uni-app(4.84)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - -

uni-app x(4.84)

Chrome Safari Android iOS 鸿蒙 微信小程序

lizhao-bg-audio

lizhao-bg-audio 是一个纯 UTS 背景音频播放插件,统一封装初始化、播放控制、播放队列、系统媒体卡、锁屏/通知栏控制、播放进度、播放完成回调和错误码。

适合音乐、电台、有声书、课程音频、长音频播放等场景。

当前版本:1.2.46

先看最小接入

  1. 从插件根目录导入。
  2. 在页面生命周期或用户点击方法中调用 initPlayer() 初始化。
  3. 初始化成功后调用 setTrack() 设置音频,再调用 play() 播放。
<template>
  <view>
    <button @click="initAndPlay">初始化并播放</button>
  </view>
</template>

<script>
import * as BgAudio from "@/uni_modules/lizhao-bg-audio";

const  = (event) => {
  console.log("播放完成回调", event.payload);
};

export default {
  onLoad() {
    // 事件监听建议先注册,避免初始化或起播后立刻派发的事件被页面错过。
    BgAudio.on("ended", );
  },
  onUnload() {
    BgAudio.off("ended", );
  },
  methods: {
    initAndPlay() {
      const track = {
        id: "demo-1",
        url: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3",
        title: "SoundHelix Song 1",
        singer: "SoundHelix"
      };

      BgAudio.initPlayer({
        success: () => {
          BgAudio.setTrack({
            track,
            success: () => {
              BgAudio.play({
                startPosition: 0,
                fail: (err) => {
                  console.log("播放失败", err.errCode, err.errMsg);
                }
              });
            },
            fail: (err) => {
              console.log("设置音频失败", err.errCode, err.errMsg);
            }
          });
        },
        fail: (err) => {
          console.log("初始化失败", err.errCode, err.errMsg);
        }
      });
    }
  }
};
</script>

只能 import 插件根目录:@/uni_modules/lizhao-bg-audio。不要 import 到 utssdk/index.uts。 App 端建议使用 success: () => {} / fail: (err) => {} 这种字段箭头函数写法,并把调用放在页面方法或生命周期内;不要在 <script> 顶层直接执行 initPlayer()。 iOS 端同样支持各 API options 内的 success / fail / complete 回调,也支持在 BgAudio.on() 事件回调里继续写日志、查询状态或触发业务逻辑;更新插件 iOS UTS 原生逻辑后,需要重新打 iOS 自定义基座后再验证这些回调。 uni-app x 的 iOS 标准基座不包含本插件原生 UTS 生成物,运行示例或调用 App-iOS 原生能力时请先制作自定义基座或正式包;标准基座只能用于看到缺少原生插件时的提示,不代表插件能力不可用。

插件内置示例页

插件包内已提供可直接复制使用的示例页面:

文件 说明
uni_modules/lizhao-bg-audio/example/index.vue 最小接入示例,适合快速看初始化、播放、暂停和下一首。
uni_modules/lizhao-bg-audio/example/backgroundAudio.vue 完整演示页,包含三键媒体卡、加载歌单、播放控制、倍速、循环、能力探测、智能下一曲预加载和日志输出。

客户下载插件后,如需使用完整演示页,可以把 uni_modules/lizhao-bg-audio/example/backgroundAudio.vue 复制到项目的 pages/backgroundAudio/backgroundAudio.vue,并在 pages.json 中加入:

{
  "path": "pages/backgroundAudio/backgroundAudio",
  "style": {
    "navigationBarTitleText": "背景音频演示"
  }
}

示例页已按插件根目录导入:import * as BgAudio from '@/uni_modules/lizhao-bg-audio';。如果要验证 Android 通知栏媒体卡、后台播放、iOS 锁屏控制或 Harmony 后台音频,请使用包含插件原生配置的新自定义基座或正式包。

支持平台

平台 是否支持 说明
uni-app Vue2 / Vue3 可用
uni-app x App / Web / 小程序按平台能力适配
Android 原生 MediaPlayer + MediaSession + AudioFocus + 前台服务 + 通知栏媒体控制
iOS 原生 AVPlayer + AVAudioSession + MPRemoteCommandCenter + MPNowPlayingInfoCenter,最低 iOS 12.0
Harmony HBuilderX 5.07 已验证 AVPlayer + AVSession,支持播放控制、队列、媒体卡、跳转、倍速和后台音频连续任务
Web HTMLAudioElement,支持浏览器 MediaSession 时同步媒体信息
微信小程序 优先后台音频管理器,不可用时降级
支付宝小程序 优先后台音频管理器,不可用时降级

常用能力

能力 API
初始化播放器 initPlayer(options)
设置单曲 setTrack(options)
设置歌单 setPlaylist(options)
播放 / 暂停 / 继续 / 停止 play(options) / pause(options) / resume(options) / stop(options)
跳转进度 seek(options)
倍速 / 音量 / 循环 setPlaybackRate(options) / setVolume(options) / setLoopMode(options)
上一首 / 下一首 / 指定下标 skipToPrev(options) / skipToNext(options) / skipToIndex(options)
状态 / 队列 / 能力探测 getPlayerState(options) / getQueueState(options) / getCapabilities(options)
事件监听 on(eventName, callback) / off(eventName, callback)
智能下一曲预加载 initPlayer({ preloadNext: true }) + on("preloadNext") + appendTrack(options)
iOS 诊断 getDebugTrace() / clearDebugTrace() / getCrashReports() / clearCrashReports()

推荐调用顺序

on 绑定事件
  -> initPlayer
  -> setTrack 或 setPlaylist
  -> play
  -> pause / resume / seek / skipToNext
  -> stop
  -> off 解绑事件

完整示例

下面示例同时适用于 uni-app 和 uni-app x。页面可以直接复制使用,再替换成自己的音频地址。

<template>
  <view class="page">
    <view class="title">背景音频示例</view>
    <view class="state">{{ stateText }}</view>
    <view class="track">{{ trackText }}</view>
    <view class="time">{{ timeText }}</view>

    <view class="buttons">
      <button type="primary" @click="initAndLoad">初始化并加载歌单</button>
      <button @click="play">播放</button>
      <button @click="pause">暂停</button>
      <button @click="resume">继续</button>
      <button @click="stop">停止</button>
      <button @click="seek30">跳转 30 秒</button>
      <button @click="prev">上一首</button>
      <button @click="next">下一首</button>
      <button @click="rate15">1.5 倍速</button>
      <button @click="volume80">音量 80%</button>
      <button @click="loopAll">列表循环</button>
      <button @click="readState">读取状态</button>
      <button @click="readQueue">读取队列</button>
      <button @click="readCapabilities">能力探测</button>
    </view>

    <scroll-view class="logs" scroll-y>
      <text>{{ logsText }}</text>
    </scroll-view>
  </view>
</template>

<script>
import * as BgAudio from "@/uni_modules/lizhao-bg-audio";

export default {
  data() {
    return {
      inited: false,
      stateText: "未初始化",
      trackText: "未加载曲目",
      currentTime: 0,
      duration: 0,
      logs: [],
      progressHandler: null,
      stateHandler: null,
      endedHandler: null,
      errorHandler: null,
      remoteHandler: null
    };
  },
  computed: {
    logsText() {
      return this.logs.join("\n");
    },
    timeText() {
      return `${this.formatTime(this.currentTime)} / ${this.formatTime(this.duration)}`;
    }
  },
  onUnload() {
    this.unbindEvents();
  },
  methods: {
    initAndLoad() {
      BgAudio.initPlayer({
        // 调试时开启插件内部日志,正式包建议保持默认关闭。
        debug: false,
        // iOS:允许系统音频中断结束后自动恢复。
        autoRecover: true,
        // iOS:注册锁屏、控制中心、耳机线控等远程控制。
        autoRegisterRemoteCommand: true,
        // Android:通知栏媒体按钮,默认推荐三键。
        notificationActions: ["prev", "playPause", "next"],
        success: (res) => {
          this.inited = true;
          this.stateText = "初始化成功";
          this.log("初始化成功 " + JSON.stringify(res));
          this.bindEvents();
          this.setPlaylist();
        },
        fail: (err) => {
          this.handleFail("初始化", err);
        }
      });
    },
    setPlaylist() {
      BgAudio.setPlaylist({
        tracks: [
          {
            id: "demo-1",
            url: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3",
            title: "SoundHelix Song 1",
            singer: "SoundHelix",
            album: "Demo",
            cover: ""
          },
          {
            id: "demo-2",
            url: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3",
            title: "SoundHelix Song 2",
            singer: "SoundHelix",
            album: "Demo",
            cover: ""
          }
        ],
        startIndex: 0,
        success: (res) => {
          this.log("歌单加载成功 " + JSON.stringify(res));
          this.readState();
        },
        fail: (err) => {
          this.handleFail("加载歌单", err);
        }
      });
    },
    play() {
      if (!this.ensureReady()) return;
      BgAudio.play({
        startPosition: 0,
        success: () => {
          this.stateText = "播放中";
          this.log("播放成功");
        },
        fail: (err) => {
          this.handleFail("播放", err);
        }
      });
    },
    pause() {
      if (!this.ensureReady()) return;
      BgAudio.pause({
        success: () => {
          this.stateText = "已暂停";
          this.log("暂停成功");
        },
        fail: (err) => {
          this.handleFail("暂停", err);
        }
      });
    },
    resume() {
      if (!this.ensureReady()) return;
      BgAudio.resume({
        success: () => {
          this.stateText = "继续播放";
          this.log("继续播放成功");
        },
        fail: (err) => {
          this.handleFail("继续播放", err);
        }
      });
    },
    stop() {
      if (!this.ensureReady()) return;
      BgAudio.stop({
        success: () => {
          this.currentTime = 0;
          this.stateText = "已停止";
          this.log("停止成功");
        },
        fail: (err) => {
          this.handleFail("停止", err);
        }
      });
    },
    seek30() {
      if (!this.ensureReady()) return;
      BgAudio.seek({
        position: 30,
        success: () => {
          this.currentTime = 30;
          this.log("已跳转到 30 秒");
        },
        fail: (err) => {
          this.handleFail("跳转进度", err);
        }
      });
    },
    prev() {
      if (!this.ensureReady()) return;
      BgAudio.skipToPrev({
        success: (res) => {
          this.log("上一首成功 " + JSON.stringify(res));
          this.readState();
        },
        fail: (err) => {
          this.handleFail("上一首", err);
        }
      });
    },
    next() {
      if (!this.ensureReady()) return;
      BgAudio.skipToNext({
        success: (res) => {
          this.log("下一首成功 " + JSON.stringify(res));
          this.readState();
        },
        fail: (err) => {
          this.handleFail("下一首", err);
        }
      });
    },
    rate15() {
      if (!this.ensureReady()) return;
      BgAudio.setPlaybackRate({
        playbackRate: 1.5,
        success: () => {
          this.log("倍速已设置为 1.5");
        },
        fail: (err) => {
          this.handleFail("设置倍速", err);
        }
      });
    },
    volume80() {
      if (!this.ensureReady()) return;
      BgAudio.setVolume({
        volume: 0.8,
        success: () => {
          this.log("音量已设置为 80%");
        },
        fail: (err) => {
          this.handleFail("设置音量", err);
        }
      });
    },
    loopAll() {
      if (!this.ensureReady()) return;
      BgAudio.setLoopMode({
        loopMode: "all",
        success: () => {
          this.log("已设置为列表循环");
        },
        fail: (err) => {
          this.handleFail("设置循环", err);
        }
      });
    },
    readState() {
      if (!this.ensureReady()) return;
      BgAudio.getPlayerState({
        success: (state) => {
          this.applyState(state);
          this.log("状态 " + JSON.stringify(state));
        },
        fail: (err) => {
          this.handleFail("读取状态", err);
        }
      });
    },
    readQueue() {
      if (!this.ensureReady()) return;
      BgAudio.getQueueState({
        success: (state) => {
          this.log("队列 " + JSON.stringify(state));
        },
        fail: (err) => {
          this.handleFail("读取队列", err);
        }
      });
    },
    readCapabilities() {
      BgAudio.getCapabilities({
        success: (res) => {
          this.log("能力 " + JSON.stringify(res));
        },
        fail: (err) => {
          this.handleFail("能力探测", err);
        }
      });
    },
    bindEvents() {
      this.unbindEvents();

      this.progressHandler = (event) => {
        const payload = event.payload || {};
        this.currentTime = Number(payload.currentTime || 0);
        this.duration = Number(payload.duration || this.duration || 0);
      };

      this.stateHandler = (event) => {
        const payload = event.payload || {};
        this.log("状态回调 " + JSON.stringify(payload));
      };

      this.endedHandler = (event) => {
        this.stateText = "播放完成";
        this.log("播放完成回调 " + JSON.stringify(event.payload || {}));
      };

      this.errorHandler = (event) => {
        this.log("错误回调 " + JSON.stringify(event.payload || {}));
      };

      this.remoteHandler = (event) => {
        this.log("媒体卡控制回调 " + JSON.stringify(event.payload || {}));
      };

      BgAudio.on("progress", this.progressHandler);
      BgAudio.on("stateChange", this.stateHandler);
      BgAudio.on("ended", this.endedHandler);
      BgAudio.on("error", this.errorHandler);
      BgAudio.on("remoteCommand", this.remoteHandler);
    },
    unbindEvents() {
      if (this.progressHandler != null) BgAudio.off("progress", this.progressHandler);
      if (this.stateHandler != null) BgAudio.off("stateChange", this.stateHandler);
      if (this.endedHandler != null) BgAudio.off("ended", this.endedHandler);
      if (this.errorHandler != null) BgAudio.off("error", this.errorHandler);
      if (this.remoteHandler != null) BgAudio.off("remoteCommand", this.remoteHandler);
      this.progressHandler = null;
      this.stateHandler = null;
      this.endedHandler = null;
      this.errorHandler = null;
      this.remoteHandler = null;
    },
    applyState(state) {
      if (state == null) return;
      this.currentTime = Number(state.currentTime || 0);
      this.duration = Number(state.duration || 0);
      this.stateText = "当前状态:" + (state.status || "unknown");
      if (state.currentTrack != null) {
        this.trackText = `${state.currentTrack.title || ""} ${state.currentTrack.singer || ""}`;
      }
    },
    ensureReady() {
      if (this.inited) return true;
      this.log("请先初始化播放器");
      return false;
    },
    handleFail(action, err) {
      const code = err && err.errCode ? err.errCode : "";
      const msg = err && err.errMsg ? err.errMsg : "";
      this.log(`${action}失败 ${code} ${msg}`);
    },
    log(text) {
      this.logs.unshift(new Date().toLocaleTimeString() + " " + text);
      if (this.logs.length > 40) this.logs.pop();
    },
    formatTime(second) {
      const value = Math.max(0, Math.floor(Number(second || 0)));
      const minute = Math.floor(value / 60);
      const remain = value % 60;
      return minute + ":" + (remain < 10 ? "0" + remain : remain);
    }
  }
};
</script>

<style>
.page {
  padding: 28rpx;
}

.title {
  font-size: 36rpx;
  font-weight: 600;
  margin-bottom: 16rpx;
}

.state,
.track,
.time {
  margin-bottom: 12rpx;
  color: #333;
}

.buttons button {
  margin-top: 16rpx;
}

.logs {
  height: 320rpx;
  margin-top: 24rpx;
  padding: 20rpx;
  background: #f7f7f7;
  border-radius: 12rpx;
  font-size: 24rpx;
  white-space: pre-wrap;
}
</style>

单曲播放示例

import * as BgAudio from "@/uni_modules/lizhao-bg-audio";

const track = {
  id: "single-1",
  url: "https://download.samplelib.com/mp3/sample-3s.mp3",
  title: "Sample 3s"
};

BgAudio.initPlayer({
  success: () => {
    BgAudio.setTrack({
      track,
      success: () => {
        BgAudio.play({
          startPosition: 0,
          fail: (err) => {
            console.log("播放失败", err.errCode, err.errMsg);
          }
        });
      },
      fail: (err) => {
        console.log("设置音频失败", err.errCode, err.errMsg);
      }
    });
  },
  fail: (err) => {
    console.log("初始化失败", err.errCode, err.errMsg);
  }
});

歌单播放示例

import * as BgAudio from "@/uni_modules/lizhao-bg-audio";

const tracks = [
  {
    id: "track-1",
    url: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3",
    title: "第一首"
  },
  {
    id: "track-2",
    url: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3",
    title: "第二首"
  }
];

function appendTracks(index) {
  if (index >= tracks.length) {
    return;
  }
  BgAudio.appendTrack({
    track: tracks[index],
    success: () => {
      appendTracks(index + 1);
    },
    fail: (err) => {
      console.log("追加队列失败", err.errCode, err.errMsg);
    }
  });
}

BgAudio.initPlayer({
  success: () => {
    BgAudio.setTrack({
      track: tracks[0],
      success: () => {
        appendTracks(1);
        BgAudio.play({
          startPosition: 0,
          fail: (err) => {
            console.log("播放失败", err.errCode, err.errMsg);
          }
        });
      },
      fail: (err) => {
        console.log("设置首曲失败", err.errCode, err.errMsg);
      }
    });
  },
  fail: (err) => {
    console.log("初始化失败", err.errCode, err.errMsg);
  }
});

Android / Harmony / Web / 小程序等非 iOS 平台推荐优先使用 setPlaylist({ tracks, startIndex }) 一次性加载完整歌单,避免依赖多次 appendTrack 回调链导致尾曲未入队。仅当旧 iOS 自定义基座存在数组桥接兼容问题时,再使用上面的 setTrack + appendTrack 逐首追加写法。

播放完成与媒体卡事件示例

import * as BgAudio from "@/uni_modules/lizhao-bg-audio";

const  = (event) => {
  console.log("播放完成", event.payload);
};

const onRemote = (event) => {
  console.log("系统媒体控制", event.payload);
};

BgAudio.on("ended", );
BgAudio.on("remoteCommand", onRemote);

// 页面销毁时解绑,避免重复进入页面后回调触发多次。
BgAudio.off("ended", );
BgAudio.off("remoteCommand", onRemote);

API 说明

initPlayer(options)

初始化播放器。App 端会创建原生音频会话、媒体卡或远程控制能力。

参数 类型 必填 说明 默认值 可选参数
options object 初始化参数对象 debug / preloadNext / preloadNextTime / nextTrackTimeout / autoRecover / autoRegisterRemoteCommand / notificationActions / success / fail / complete
options.debug boolean 是否开启插件内部控制台日志;开启后 Android / iOS / Harmony 根入口会打印诊断日志 false true / false
options.preloadNext boolean 是否开启智能下一曲预加载;开启后队列末尾临近结束会触发 preloadNext 事件 false true / false
options.preloadNextTime number 距离当前曲结束多少秒触发 preloadNext 15 大于 0 的数值
options.nextTrackTimeout number 当前曲播完后等待业务追加下一曲的超时时间,单位毫秒;0 表示不自动超时 0 大于等于 0 的数值
options.autoRecover boolean iOS 音频中断结束后是否自动恢复播放 true true / false
options.autoRegisterRemoteCommand boolean iOS 是否注册锁屏、控制中心、耳机线控命令 true true / false
options.notificationActions string[] Android 通知栏媒体按钮顺序 prev / playPause / next prev / rewind / playPause / forward / next
options.success function 初始化成功回调
options.fail function 初始化失败回调
options.complete function 初始化完成回调,成功失败都会触发

setTrack(options)

设置当前单曲和媒体元数据。

参数 类型 必填 说明 默认值 可选参数
options object 设置曲目参数对象 track / tracks / tracksPayloadJson / success / fail / complete
options.track object 曲目信息 id / url / title / singer / album / cover / durationHint / headers / extras
options.tracks array 兼容字段:调用方把完整队列随 setTrack 一起传入时,插件会同步为播放队列;推荐新代码优先使用 setPlaylist BackgroundAudioTrack[]
options.tracksPayloadJson string tracks 的 JSON 快照兜底字段,用于桥接层对象数组读取不稳定时恢复队列
options.success function 设置成功回调
options.fail function 设置失败回调
options.complete function 设置完成回调

setPlaylist(options)

设置播放队列。

参数 类型 必填 说明 默认值 可选参数
options object 设置队列参数对象 tracks / startIndex / success / fail / complete
options.tracks array 曲目数组 BackgroundAudioTrack[]
options.startIndex number 起始播放下标 0 大于等于 0 的整数
options.success function 设置成功回调
options.fail function 设置失败回调
options.complete function 设置完成回调

play(options)

开始播放。

参数 类型 必填 说明 默认值 可选参数
options object 播放参数对象 startPosition / success / fail / complete
options.startPosition number 从指定秒数开始播放 当前进度 大于等于 0 的数值
options.success function 播放成功回调
options.fail function 播放失败回调
options.complete function 播放完成回调,成功失败都会触发

pause(options) / resume(options) / stop(options)

暂停、继续、停止播放。

参数 类型 必填 说明 默认值 可选参数
options object 控制参数对象 success / fail / complete
options.success function 成功回调
options.fail function 失败回调
options.complete function 完成回调

seek(options)

跳转到指定播放进度。

参数 类型 必填 说明 默认值 可选参数
options object 跳转参数对象 position / success / fail / complete
options.position number 目标秒数 大于等于 0 的数值
options.success function 跳转成功回调
options.fail function 跳转失败回调
options.complete function 跳转完成回调

setPlaybackRate(options)

设置播放倍速。Harmony 真机不再写入 BackgroundAudioManager.playbackRate,改由 AVPlayer.setSpeed() 执行;系统只支持固定档位时会按最近档位归一化。

参数 类型 必填 说明 默认值 可选参数
options object 倍速参数对象 playbackRate / success / fail / complete
options.playbackRate number 播放倍速 大于 0 的数值
options.success function 成功回调
options.fail function 失败回调
options.complete function 完成回调

setVolume(options)

设置播放音量。部分平台由系统音量控制,可能返回不支持。

参数 类型 必填 说明 默认值 可选参数
options object 音量参数对象 volume / success / fail / complete
options.volume number 音量值 0 ~ 1
options.success function 成功回调
options.fail function 失败回调
options.complete function 完成回调

setLoopMode(options)

设置循环模式。

参数 类型 必填 说明 默认值 可选参数
options object 循环参数对象 loopMode / success / fail / complete
options.loopMode string 循环模式 off / single / all
options.success function 成功回调
options.fail function 失败回调
options.complete function 完成回调

appendTrack(options)

向当前队列追加曲目。

开启智能下一曲预加载并且播放器处于 waitingNext 状态时,业务接口拿到下一曲后调用 appendTrack(),插件会自动切到刚追加的下一曲并继续播放,成功回调会额外返回 autoPlay: true

参数 类型 必填 说明 默认值 可选参数
options object 追加参数对象 track / success / fail / complete
options.track object 要追加的曲目信息 BackgroundAudioTrack
options.success function 成功回调
options.fail function 失败回调
options.complete function 完成回调

removeTrack(options)

从队列移除指定曲目。

参数 类型 必填 说明 默认值 可选参数
options object 移除参数对象 trackId / success / fail / complete
options.trackId string 要移除的曲目 ID
options.success function 成功回调
options.fail function 失败回调
options.complete function 完成回调

skipToNext(options) / skipToPrev(options) / skipToIndex(options)

切换上一首、下一首或指定队列下标。

skipToIndexsuccess / complete 表示目标曲目已装载并同步队列下标;插件会随后自动尝试播放,避免 iOS 因播放二级回调未返回而丢失本次切歌回调。

参数 类型 必填 说明 默认值 可选参数
options object 切歌参数对象 index / success / fail / complete
options.index number 目标队列下标,仅 skipToIndex 必填 大于等于 0 的整数
options.success function 成功回调
options.fail function 失败回调
options.complete function 完成回调

getPlayerState(options) / getQueueState(options) / getCapabilities(options)

读取播放器状态、队列状态和平台能力。

参数 类型 必填 说明 默认值 可选参数
options object 查询参数对象 success / fail / complete
options.success function 成功回调
options.fail function 失败回调
options.complete function 完成回调

on(eventName, callback) / off(eventName, callback)

订阅和取消订阅播放器事件。

参数 类型 必填 说明 默认值 可选参数
eventName string 事件名称 stateChange / progress / buffer / error / ended / preloadNext / waitingNext / nextTrackTimeout / remoteCommand / interruption
callback function 事件回调

事件说明:

事件 触发时机
stateChange 播放状态变化
progress 播放进度更新,频率较高
buffer 缓冲状态变化
error 播放器错误
ended 当前曲目播放完成
preloadNext 当前曲接近结束且队列暂无下一曲,提示业务提前请求下一曲
waitingNext 当前曲已播完且业务下一曲尚未追加,播放器进入等待下一曲状态
nextTrackTimeout 等待业务追加下一曲超过 nextTrackTimeout
remoteCommand 系统媒体卡、锁屏、耳机线控命令
interruption iOS 音频中断等系统事件

智能下一曲预加载

适合“下一曲需要先请求业务接口”的场景,例如有声书、课程音频、付费内容鉴权或动态推荐。开启后,插件会在当前曲快结束且队列里还没有下一曲时提前触发 preloadNext;如果当前曲播完接口还没返回,会进入 waitingNext 状态等待。业务拿到下一曲后调用 appendTrack(),插件会自动续播。

import * as BgAudio from "@/uni_modules/lizhao-bg-audio";

BgAudio.initPlayer({
  preloadNext: true,
  preloadNextTime: 20,
  nextTrackTimeout: 15000,
  success() {
    console.log("背景音频初始化成功");
  }
});

BgAudio.on("preloadNext", async (event) => {
  const currentTrack = event.payload.currentTrack;
  // 这里换成你的接口请求,例如根据 currentTrack.extras 或 currentTrack.id 获取下一集。
  const nextTrack = await requestNextTrack(currentTrack);
  if (nextTrack != null) {
    BgAudio.appendTrack({
      track: nextTrack,
      success(res) {
        console.log("下一曲已追加", res);
      }
    });
  }
});

BgAudio.on("waitingNext", () => {
  console.log("当前曲已播完,正在等待下一曲接口返回");
});

BgAudio.on("nextTrackTimeout", (event) => {
  console.log("等待下一曲超时", event.payload);
});

注意事项:

  • preloadNext 只在 loopMode = "off" 且当前播放到队列末尾时触发;队列里已经有下一曲时,插件会直接续播已有下一曲。
  • 如果业务先调用 setPlaylist() 或连续 appendTrack() 把下一曲提前放进队列,当前曲临近结束时不会触发 preloadNext,这是正常行为;只有“当前曲就是队列最后一首、插件确实缺少下一曲”时才需要通知业务请求接口。
  • 测试 preloadNext 时请确保队列只有当前这一首,例如先调用 setPlaylist({ tracks: [currentTrack], startIndex: 0 }) 清掉旧队列;如果之前加载过完整歌单,旧的下一曲仍在队列中,会导致看不到 preloadNext 回调。
  • Harmony 真机调试时建议参考示例页“加载单曲预加载测试”:示例页会用唯一 id 和唯一 url 调用 setTrack(),确保当前曲就是队列最后一首。若设备或基座中 setPlaylist() 的数组桥接不稳定,也可以采用这种方式重置为单曲队列。
  • “跳到预加载触发点”只是把进度移动到阈值附近,真正触发还需要已经开启 preloadNext、当前曲有有效 durationloopMode = "off",并且队列里没有下一曲;满足条件后事件可能在 seek 完成或后续播放进度回调中立即触发。
  • preloadNext 对同一首曲目只触发一次,避免进度频繁上报导致接口重复请求。
  • nextTrackTimeout 默认 0,表示一直等待;业务希望超时展示重试按钮时可设置为 1000015000
  • 如果业务主动切歌、重新设置歌单、停止播放或移除等待中的曲目,插件会清理本次等待状态。

getDebugTrace() / clearDebugTrace() / getCrashReports() / clearCrashReports()

iOS 诊断 API,用于读取和清理持久化调试轨迹。正常业务一般不需要调用。

参数 类型 必填 说明 默认值 可选参数
无参数

类型说明

BackgroundAudioTrack

字段 类型 说明
id string 曲目唯一 ID
url string 音频地址,支持远程地址和平台支持的本地地址
title string 曲目标题
singer string 歌手名称,可选
album string 专辑名称,可选
cover string 封面图地址,可选
durationHint number 时长兜底值,单位秒,可选
headers object 请求头扩展,按平台支持情况透传
extras object 业务扩展字段,插件不解释

BackgroundAudioPlayerState

字段 类型 说明
initialized boolean 是否已初始化
status string idle / ready / playing / paused / stopped / ended / waitingNext / buffering
currentTrack object/null 当前曲目
currentTime number 当前播放秒数
duration number 总时长秒数
buffered number 已缓冲秒数
playbackRate number 当前倍速
volume number 当前音量
loopMode string off / single / all
queueIndex number 当前队列下标
queueLength number 队列长度
backgroundActive boolean 是否处于后台活跃播放态

BackgroundAudioCapabilities

字段 类型 说明
supported boolean 当前平台是否支持
sessionLevel string native / manager / fallback / none
backgroundAudio boolean 是否支持后台音频
mediaSession boolean 是否支持媒体会话元数据
remoteCommand boolean 是否支持系统媒体控制命令
queue boolean 是否支持队列
playbackRate boolean 是否支持倍速
volume boolean 是否支持音量
platform string 平台标识
adapter string 适配器标识
requiresCustomBase boolean 是否建议自定义基座

错误码

错误码 含义 说明
9012001 当前平台不支持 当前平台没有可用播放能力
9012002 参数不合法 缺少必填参数或参数范围错误
9012003 运行时未初始化 调用播放 API 前未先调用 initPlayer()
9012004 音源不可用 曲目缺失、URL 为空或音源不可访问
9012005 播放失败 原生播放器启动或播放失败
9012006 跳转位置非法 seek 秒数不合法
9012007 能力不支持 当前平台或当前环境不支持该能力,例如倍速、音量或远程控制
9012008 缺少后台音频能力 原生音频会话或后台能力不可用

权限与配置

平台 是否支持 说明
Android 需要网络权限;使用前台服务、媒体通知、Android 13+ 通知权限时建议自定义基座
iOS 最低 iOS 12.0;建议配置 UIBackgroundModes: audio,Windows 标准基座真机运行无法使用 iOS UTS 插件
Harmony 使用 AVPlayer + AVSession 启用播放、跳转、倍速、系统媒体卡和后台音频连续任务;需要声明 backgroundModes: ["audioPlayback"]ohos.permission.KEEP_BACKGROUND_RUNNING,缺失后台管理器、AVPlayer 或媒体会话时返回错误
Web 受浏览器自动播放和后台策略限制
微信小程序 建议配置 requiredBackgroundModes: ["audio"]
支付宝小程序 按支付宝小程序后台音频规则配置

Harmony 后台音频连续任务配置

Harmony 息屏后仍要保持播放和系统媒体卡可用时,必须在鸿蒙工程 harmony-configs/entry/src/main/module.json5EntryAbility 中配置 backgroundModes: ["audioPlayback"],并在 requestPermissions 中声明 ohos.permission.INTERNETohos.permission.KEEP_BACKGROUND_RUNNING

示例(只展示关键字段):

{
  "module": {
    "abilities": [
      {
        "name": "EntryAbility",
        "backgroundModes": [
          "audioPlayback"
        ]
      }
    ],
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      },
      {
        "name": "ohos.permission.KEEP_BACKGROUND_RUNNING"
      }
    ]
  }
}

INTERNET 用于网络音频访问;KEEP_BACKGROUND_RUNNINGaudioPlayback 用于配合插件内部后台音频连续任务申请,让息屏播放和媒体卡控制在系统后台策略下继续可用。修改该配置后必须重新打鸿蒙自定义基座或运行包。

Harmony 短音/瞬态音频焦点策略

Harmony 上架检测会检查短音、瞬态音播放场景是否使用 share / duck / pause 等不会永久打断后台音乐的焦点策略。插件的 Harmony 原生链路会在 AVPlayer 首次 prepare() / play() 前激活 AudioSessionManagerCONCURRENCY_MIX_WITH_OTHERS 并发策略,同时显式设置 audioInterruptMode = SHARE_MODEaudioRendererInfo.usage = STREAM_USAGE_MUSIC,让后台音乐按系统策略并发播放或在短暂暂停后自动恢复,避免被识别为 stop 独占焦点策略。

是否需要自定义基座

场景 是否需要 说明
Android 原生媒体通知、前台服务、通知权限 建议 自定义基座或云打包能确保 Manifest 配置完整生效
iOS 后台音频、锁屏媒体卡、控制中心 建议 最低 iOS 12.0;需要后台音频能力配置,标准基座能力有限
Harmony 后台音频连续任务 需要 Harmony 工程在 EntryAbility 声明 backgroundModes: ["audioPlayback"],并声明 ohos.permission.KEEP_BACKGROUND_RUNNING;更新后必须重新打自定义基座或运行包
Web / 小程序基础播放 主要受平台策略限制
新增三方 SDK、原生资源、权限声明 需要重新打自定义基座

目录结构

uni_modules/
└─ lizhao-bg-audio/
   ├─ package.json
   ├─ readme.md
   ├─ changelog.md
   ├─ example/
   │  ├─ index.vue
   │  ├─ backgroundAudio.vue
   │  └─ readme.md
   └─ utssdk/
      ├─ interface.uts
      ├─ unierror.uts
      ├─ index.uts
      ├─ app-android/index.uts
      ├─ app-ios/index.uts
      ├─ app-harmony/index.uts
      ├─ web/index.uts
      ├─ mp-weixin/index.uts
      └─ mp-alipay/index.uts

注意事项

  1. initPlayer(),再调用播放、队列、状态 API。
  2. progress 事件频率较高,页面日志建议采样展示。
  3. on()off() 需要使用同一个回调函数引用。
  4. iOS 中文 URL 会做安全编码归一化,但仍建议业务侧使用可直接访问的 HTTPS 音频地址。
  5. setVolume()setPlaybackRate() 在部分平台可能受系统策略限制,建议先用 getCapabilities() 判断;Harmony 通过 AVPlayer.setSpeed() 支持常见固定倍速档位。
  6. Harmony 后台保活依赖 module.json5 中的 backgroundModes: ["audioPlayback"]ohos.permission.KEEP_BACKGROUND_RUNNING;配置变化后必须重新打鸿蒙自定义基座或运行包。

联系方式

信-微:l-z-1-8-7-1512-5421(-去掉,不这样写会被和谐)

作者系列UTS插件

以下为已在 DCloud 插件市场上架的作者系列 UTS 插件,可按业务场景组合使用。未列出的插件表示当前未确认公开市场页,后续上架后再补充。

插件 能力方向 插件市场
lizhao-nfc-pro NFC 标签读写、NDEF、IsoDep 与诊断 查看插件
lizhao-float-window 悬浮窗、画中画、权限与诊断 查看插件
lizhao-device-id 设备标识、隐私策略与诊断 查看插件
lizhao-scan-pro 原生扫码、连续扫码、相册识别 查看插件
lizhao-choose-file 原生文件选择、上传、进度与取消 查看插件
lizhao-bg-audio 背景音频播放、队列、倍速与事件 查看插件
lizhao-smart-tts 系统 TTS、云端合成、听书方案 查看插件
lizhao-share-plus 系统分享、远程文件下载后分享 查看插件
lizhao-sqlite-pro 原生 SQLite、迁移、备份与诊断 查看插件
lizhao-icon-pro SVG 图标组件、多主题与缓存 查看插件
lizhao-cast-screen DLNA 投屏、AirPlay 路由入口 查看插件
lizhao-call-kit 电话、短信、通讯录原生能力 查看插件
lizhao-app-keepalive 应用保活、唤醒、自愈与报告 查看插件
lizhao-doc-corrector 文档扫描、矫正、增强与识别 查看插件
lizhao-emu-detect 模拟器环境检测、风险评分与证据 查看插件

隐私、权限声明

1. 本插件需要申请的系统权限列表:

后台音频、媒体会话、通知权限、Harmony audioPlayback 后台模式与 KEEP_BACKGROUND_RUNNING 连续任务权限按平台配置

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率: