微信小程式背景播放接入說明
微信小程式背景播放接入說明
本文介紹保利威直播在微信小程式中的背景小視窗播放對接方式,涵蓋以下兩種觀看場景:
- 原生小程式觀看頁:由觀看頁播放器直接請求背景小視窗播放。
- 小程式 WebView 觀看頁:H5 觀看頁跳轉到小程式原生中轉頁,由中轉頁建立原生
<video>並請求背景小視窗播放。
背景小視窗始終由微信小程式原生 <video> 或 <live-player> 元件承載。requestBackgroundPlayback() 不接收播放位址,直播流或回放位址必須先繫結到當前正在播放的原生元件,再透過對應的 Context 請求背景播放。
微信小程式核心 API
微信小程式實現背景播放的核心是播放器 Context 上的 requestBackgroundPlayback()。Polyv SDK 提供的 watchCore.player.requestBackgroundPlayback() 是對微信原生 Context API 的統一封裝,不是另一套系統小視窗能力。
進入背景小視窗
| 微信原生 API | 官方說明 | 最低基礎庫 | 適用元件 |
|---|---|---|---|
VideoContext.requestBackgroundPlayback() |
進入背景小視窗播放模式 | 2.14.3 |
<video> |
LivePlayerContext.requestBackgroundPlayback() |
進入背景小視窗播放模式 | 2.14.3 |
<live-player> |
兩個 API 均無參數、回傳 void。使用方式如下:
// video
const videoContext = wx.createVideoContext('videoId', this);
videoContext.requestBackgroundPlayback();
// live-player
const livePlayerContext = wx.createLivePlayerContext('livePlayerId', this);
livePlayerContext.requestBackgroundPlayback();
Context 的建立方式可參考微信官方文件:
在 Polyv 原生觀看頁中,業務程式碼只需要呼叫:
watchCore.player.requestBackgroundPlayback();
SDK 會根據當前實際播放節點,向下轉發到 VideoContext.requestBackgroundPlayback() 或 LivePlayerContext.requestBackgroundPlayback()。
退出背景小視窗
| 微信原生 API | 官方說明 | 最低基礎庫 | 適用元件 |
|---|---|---|---|
VideoContext.exitBackgroundPlayback() |
退出背景小視窗播放模式 | 2.14.3 |
<video> |
LivePlayerContext.exitBackgroundPlayback() |
退出背景小視窗播放模式 | 2.14.3 |
<live-player> |
WebView 中轉頁返回 H5 前使用的是 VideoContext.exitBackgroundPlayback():
const videoContext = wx.createVideoContext('polyvLiveVideo', this);
videoContext.exitBackgroundPlayback();
wx.navigateBack({ delta: 1 });
原生控制欄按鈕
video 元件的 show-background-playback-button 用於控制原生控制欄是否展示背景播放按鈕。該屬性只控制按鈕展示,不代替 Context API;使用自訂按鈕時仍需主動呼叫 requestBackgroundPlayback()。
接入前準備
接入前請確認:
- 已在保利威直播管理後台開啟對應的小視窗播放設定。
- 微信小程式基礎庫需要為
2.14.3或以上,低版本必須做相容處理。 - 使用 iOS、Android 真機驗證。開發者工具不能替代應用切背景場景的真機結果。
- 呼叫時播放器已經完成初始化並進入播放狀態,原生播放器節點仍然掛載在頁面中。
- 當前微信版本和作業系統支援背景小視窗播放。
該方案不依賴 app.json 的 requiredBackgroundModes。requiredBackgroundModes 中的 audio 是背景音訊能力,不是影片背景小視窗開關。
管理後台設定
在直播管理後台的頻道小程式設定中,可以看到以下配置:
| 設定項 | 作用 | 當前適用範圍 |
|---|---|---|
| 小程式原生小視窗播放 | 控制原生小程式觀看頁是否展示小視窗入口 | 直播、回放 |
| 小程式 WebView 小視窗播放 | 控制 WebView H5 觀看頁是否展示小視窗入口 | 直播 |
| 小程式原生中間頁路徑 | WebView 觀看頁點選小視窗後跳轉的原生小程式頁面路徑 | 僅 WebView 方案 |
中轉頁路徑
當前 Polyv 觀看端提供的參考中轉頁是:
/pages-other/pages/window/window
實現可參考 Polyv 觀看端原始碼中的:
src/pages-other/pages/window/
中轉頁必須在小程式 app.json 的 pages 或分包頁面中完成註冊。WebView 觀看頁必須使用 wx.miniProgram.navigateTo 開啟該頁面,以保留上一層 WebView 頁面;不要使用 redirectTo 替換 WebView 頁面,否則中轉頁無法透過 navigateBack 返回原觀看頁。
截圖中的配置範例為:
/pages-other/pages/window/window?appId=xxxx&appSecret=xxxx&accountId=xxxx
當前參考頁實際需要以下四個參數:
| 參數 | 必填 | 說明 |
|---|---|---|
channelId |
是 | 當前直播頻道 ID,通常由 H5 觀看頁在點選時追加 |
accountId |
是 | 保利威帳號 ID,不是觀眾 userId |
appId |
是 | 當前驗證實現使用的播放器鑑權 App ID |
appSecret |
是 | 僅當前驗證實現用於前端計算簽名 |
參數名區分大小寫。accountId 表示保利威帳號 ID,觀眾 userId 表示觀看使用者識別,二者是完全不同的業務欄位,不能互相替代,也不能把觀眾 userId 作為 accountId 傳入。所有動態參數都應執行 encodeURIComponent。
安全提示:截圖展示的是當前驗證環境的配置方式。生產環境禁止把長期
appSecret放在管理後台頁面路徑、H5 JavaScript、小程式路由參數或小程式程式碼中。正式接入應由業務服務端保管金鑰,只向前端簽發短時、最小權限的播放憑證。中轉頁可接收一次性ticket,再向業務服務端換取短時sign + timestamp或播放 token。採用該方式前,需要同步改造當前 Polyvwindow參考頁的鑑權入參。
原生小程式觀看頁實現
實現流程
當前 Polyv 觀看端只在豎屏觀看頁展示小視窗按鈕。按鈕位於頻道資訊膠囊旁,顯示條件為:
- 後台已開啟「小程式原生小視窗播放」。
- 當前頻道狀態為直播中或回放中。
呼叫鏈如下:
sequenceDiagram
participant User as 用户
participant Page as 原生观看页
participant SDK as watchCore.player
participant Controller as 播放器控制器
participant Context as VideoContext 或 LivePlayerContext
participant System as 微信或系统小窗
User->>Page: 点击小窗按钮
Page->>SDK: requestBackgroundPlayback()
SDK->>Controller: 转发到当前直播或点播控制器
Controller->>Context: requestBackgroundPlayback()
Context->>System: 请求进入后台小窗
對應的核心呼叫是:
watchCore.player.requestBackgroundPlayback();
SDK 會根據當前播放器類型轉發呼叫:
- 直播播放器:獲取當前播放器元件暴露的
getVideoContext(),最終呼叫VideoContext或LivePlayerContext。 - 點播播放器:呼叫點播播放器上下文的
requestBackgroundPlayback()。
當前本地播放器會根據媒體類型選擇原生節點:
- 普通直播流優先使用
<live-player>。 .m3u8、回放、暖場影片或開啟forceVideo時使用<video>。
推薦呼叫時機
應在播放器真正開始播放後開放小視窗按鈕。觀看頁 SDK 可以監聽 PlayerEvents.PlayerPlaying:
import { PlayerEvents } from '@polyv/live-watch-miniprogram-sdk';
let canRequestBackgroundPlayback = false;
watchCore.player.eventEmitter.on(PlayerEvents.PlayerPlaying, () => {
canRequestBackgroundPlayback = true;
});
function onTapBackgroundPlayback() {
if (!canRequestBackgroundPlayback) {
wx.showToast({
title: '请先开始播放',
icon: 'none',
});
return;
}
try {
watchCore.player.requestBackgroundPlayback();
} catch (error) {
wx.showToast({
title: '小窗打开失败',
icon: 'none',
});
}
}
requestBackgroundPlayback() 無參數、回傳 void。呼叫沒有回傳成功回呼,因此不能把「方法未拋錯」直接等同於「系統小視窗已經開啟」。
直接使用原生 video
如果沒有使用觀看頁 SDK,也可以直接對原生 <video> 建立 Context:
<video
id="liveVideo"
src="{{ videoSrc }}"
autoplay
show-background-playback-button="{{ true }}"
bindplay="onVideoPlay"
/>
<button bind:tap="onTapBackgroundPlayback">小窗播放</button>
Page({
data: {
isPlaying: false,
},
onVideoPlay() {
this.setData({ isPlaying: true });
},
onTapBackgroundPlayback() {
if (!this.data.isPlaying) {
wx.showToast({ title: '请先开始播放', icon: 'none' });
return;
}
const videoContext = wx.createVideoContext('liveVideo', this);
if (typeof videoContext.requestBackgroundPlayback !== 'function') {
wx.showToast({ title: '当前环境不支持小窗播放', icon: 'none' });
return;
}
try {
videoContext.requestBackgroundPlayback();
} catch (error) {
wx.showToast({ title: '小窗打开失败', icon: 'none' });
}
},
});
show-background-playback-button 只控制原生控制欄是否顯示背景播放按鈕;使用自訂按鈕時仍需主動呼叫 Context API。
頁面生命週期
系統小視窗依賴原播放器頁面和原生節點存活。背景播放期間不要執行以下操作:
navigateBack、redirectTo或其他會卸載播放器頁面的路由操作。- 銷毀觀看頁 SDK 或播放器實例。
- 透過
wx:if移除<video>/<live-player>。 - 清空
src或切換到另一個播放器 Context。
當前 Polyv 原生觀看頁針對 iOS 返回頁面後的恢復問題做了相容處理:觸發過背景播放後,頁面再次顯示會立即呼叫一次 play(),並在 1 秒後再次呼叫。該處理可以緩解 <video> 播放 m3u8 時第一次 play() 無效的問題;當前 <live-player> 在系統小視窗中暫停後返回,仍可能無法透過 play() 恢復,需要結合真機結果繼續處理。
WebView 觀看頁實現
方案定位
WebView 頁面不能直接獲取小程式原生 VideoContext。當前方案透過一個可見的原生中轉頁接管播放:
sequenceDiagram
participant User as 用户
participant H5 as WebView 观看页
participant Window as 原生 window 中转页
participant Core as wx-live-player-core
participant Video as 原生 video
participant System as 微信或系统小窗
User->>H5: 点击小窗播放
H5->>Window: wx.miniProgram.navigateTo
Window->>Core: 创建播放器并请求媒体信息
Core-->>Window: 返回 mediaInfo.src
Window->>Video: 设置 src 并自动播放
Video-->>Window: bindplay
Window->>System: requestBackgroundPlayback()
System-->>Window: 用户返回微信
Window->>Video: exitBackgroundPlayback()
Window->>H5: navigateBack 返回 WebView
當前完整流程是:
- 小程式登入頁透過
redirectTo開啟承載 H5 觀看頁的 WebView 頁面。 - H5 根據後台的「小程式 WebView 小視窗播放」開關決定是否展示小視窗按鈕。
- 使用者點選後,H5 暫停自身播放器,並使用
wx.miniProgram.navigateTo開啟後台配置的原生中轉頁。 - 中轉頁獲取直播流位址,掛載原生
<video>。 <video>觸發bindplay後,中轉頁呼叫requestBackgroundPlayback()。- 使用者從系統小視窗返回微信時,中轉頁在後續
onShow中退出背景播放,再navigateBack返回原 WebView 頁面。 - 中轉頁
onUnload時銷毀播放器。
因此該方案的播放歸屬會發生切換:進入中轉頁後由原生播放器播放;返回 WebView 前會結束原生系統小視窗並銷毀中轉播放器。它不支援「已經返回 WebView 頁面,但原生系統小視窗仍繼續播放」的並行狀態。
H5 跳轉中轉頁
WebView 網頁需要引入微信 JSSDK,並在使用者點選時呼叫:
<script src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script>
function openBackgroundPlayback(options) {
const intermediatePagePath = options.intermediatePagePath;
const channelId = options.channelId;
const separator = intermediatePagePath.includes('?') ? '&' : '?';
const targetUrl =
intermediatePagePath +
separator +
'channelId=' +
encodeURIComponent(channelId);
// 跳转前暂停 H5 播放器,避免双音频和重复统计。
options.pauseWebPlayer();
wx.miniProgram.navigateTo({
url: targetUrl,
fail(error) {
console.error('打开小窗中转页失败', error);
options.resumeWebPlayer();
},
});
}
intermediatePagePath 使用管理後台返回的中轉頁路徑。當前截圖中的路徑已經包含 appId、appSecret 和 accountId,H5 在點選時追加當前 channelId。正式環境應改為追加短時 ticket,不要傳遞長期 appSecret。
Polyv window 中轉頁邏輯
Polyv 觀看端的 pages-other/pages/window/window 當前使用原生 Page({...}) 生命週期,核心邏輯如下:
- 解析並校驗
channelId、accountId、appId、appSecret。 - 生成時間戳和 MD5 簽名,建立
@polyv/wx-live-player-core播放器。 - 設定
forceVideo: true,確保直播由原生<video>承載。 - 監聽
UPDATE_MEDIA_INFO,把mediaInfo.src寫入頁面的videoSrc。 - 原生
<video>起播後建立VideoContext,並且只發起一次requestBackgroundPlayback()。 - 後續
onShow檢查上一頁是否為 WebView;滿足條件時先退出背景播放,再返回 WebView。 onUnload銷毀PolyvLive,避免播放器和事件監聽殘留。
參考頁會把 accountId 傳給 PolyvLive 的 uid 配置,並用於 statistics.param1。這裡的 accountId 仍然是保利威帳號 ID,不代表觀眾 userId。
中轉頁的原生節點應保持可見和掛載:
<video
wx:if="{{ videoSrc }}"
id="polyvLiveVideo"
src="{{ videoSrc }}"
autoplay
controls="{{ false }}"
enable-progress-gesture="{{ false }}"
show-fullscreen-btn="{{ false }}"
object-fit="contain"
bindplay="onVideoPlay"
binderror="onVideoError"
/>
不要對播放器使用 display: none、visibility: hidden、opacity: 0,也不要在發起背景播放後立即卸載中轉頁。
生產鑑權改造
當前參考頁把 appSecret 帶到前端並在小程式中計算簽名,只能用於內部驗證。推薦的生產流程是:
- H5 向業務服務端申請一次性、短有效期的
ticket。 - H5 只把
channelId和ticket傳給原生中轉頁;如果業務還需要觀眾userId,應使用獨立欄位傳遞,不能覆蓋accountId。 - 中轉頁用
ticket向業務服務端換取短時播放器鑑權資訊。 - 業務服務端持有
appSecret並完成簽名,前端永遠不接觸長期金鑰。 - 中轉頁使用返回的短時
appId + sign + timestamp或播放 token 建立播放器。
ticket 應綁定頻道、觀眾、過期時間和使用次數,並在服務端校驗,避免被複製到其他頻道或重複使用。
使用者互動與呼叫時機
微信官方對 requestBackgroundPlayback() 的介面說明沒有標註「只能由使用者點選呼叫」,但這不等於進入頁面後可以無條件立即呼叫:
- 原生媒體可能尚未建立 Context 或尚未開始播放。
- 自動播放可能受終端、系統或媒體策略影響。
- 背景小視窗是否出現仍由微信和作業系統共同決定。
推薦做法:
- 原生觀看頁由使用者點選小視窗按鈕觸發。
- WebView 方案由使用者點選 H5 小視窗按鈕進入中轉頁,並等原生
<video>的bindplay後呼叫。 - 不要在
onLoad中建立 Context 後立即呼叫。 - 不要在呼叫後緊接著執行
wx.exitMiniProgram()。微信沒有保證這組呼叫的組合時序。
狀態判斷與錯誤處理
建議同時使用以下方式維護狀態:
- 呼叫前檢查
requestBackgroundPlayback是否存在,並捕獲同步異常。 - 提供手動重試入口,不要只依賴自動呼叫一次。
- 在頁面生命週期中記錄是否已經發起背景播放請求,避免重複呼叫。
當前 Polyv window 參考頁中的 backgroundPlaybackRequested 只表示「已經發起呼叫且未同步拋錯」,不代表背景小視窗真實進入。業務側需要保留失敗提示和手動重試入口。
背景播放限制
- 微信沒有提供直接把流位址傳給背景小視窗的全域 API。
- 必須先讓微信原生
<video>或<live-player>播放,再呼叫對應 Context。 - 強制結束微信程序、卸載播放器頁面、銷毀播放器或清空媒體源後,背景播放無法繼續。
- 使用者把微信切到背景後小視窗立即消失時,應優先
