更新记录

1.0.0(2026-03-22)

  • 支持 Android overlay、iOS in-app float、Android system video PiP 和 iOS out-app PiP。
  • 新增 playVideopauseVideoseekVideo 视频控制接口。
  • video-url 支持 isMutedallowsExternalPlaybackstartPositionMsautoEnteraspectRatio
  • 新增 appearance.showTitleBar,支持隐藏 overlay / in-app float 的自绘标题栏。

平台兼容性

uni-app(4.87)

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

uni-app x(4.87)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - - -

hans-pip

hans-pip 是一个用于 uni-app / uni-app x App 端的小窗口 / 悬浮窗 UTS 插件,统一提供 Android overlay、iOS in-app float 和系统视频 PiP 的管理接口。

安装与导入

统一从插件入口导入,不要直接引用 utssdk/*

import {
  getFloatingWindowManager,
  isLogEnabled,
  setLogEnabled,
  type FloatingWindowOpenOptions,
} from '@/uni_modules/hans-pip'

const windowManager = getFloatingWindowManager()

联调阶段建议开启日志:

setLogEnabled(true)
console.log(`hans-pip log enabled=${isLogEnabled()}`)

支持范围

mode Android iOS Harmony contentType
android-overlay-window 支持 - - webview
android-system-video-pip 支持 - - video-url
ios-in-app-float - 支持 - webview
ios-out-app-pip - 支持 - video-url
harmony-stub - - stub -

说明:

  • android-system-video-pipios-out-app-pip 只允许 video-url
  • webview 只用于 android-overlay-windowios-in-app-float
  • Harmony 当前仅提供 stub,不提供实际窗口宿主。

使用流程

建议在调用 open(...) 前先做支持检查和参数校验:

const support = windowManager.checkSupportSync('android-overlay-window', 'webview')
const validation = windowManager.validateOpenOptionsSync(openOptions)

推荐顺序:

  1. checkSupportSync(mode, contentType?) 判断平台、权限和宿主能力是否满足。
  2. validateOpenOptionsSync(options) 判断当前 payload 是否合法。
  3. 校验通过后再调用 open(...)

核心 API

  • checkSupportSync(mode, contentType?)
  • validateOpenOptionsSync(options)
  • getWindowStateSync(tag)
  • getActiveWindowTagsSync()
  • open(options)
  • refresh(options)
  • close({ tag, ownerPage?, ownerPageId? })
  • updateFrame({ tag, ownerPage?, ownerPageId?, frame })
  • callJS({ tag, ownerPage?, ownerPageId?, script })
  • playVideo({ tag, ownerPage?, ownerPageId? })
  • pauseVideo({ tag, ownerPage?, ownerPageId? })
  • seekVideo({ tag, ownerPage?, ownerPageId?, positionMs })
  • cleanupPageOwnedWindows({ ownerPage?, ownerPageId?, reason? })
  • canDrawOverlaysSync()
  • openOverlayPermissionSettings()
  • bringAppToFront()
  • onWindowEvent(callback) / offWindowEvent(listenerId?)
  • onError(callback) / offError(listenerId?)

open 参数

type FloatingWindowOpenOptions = {
  requestId?: string | null
  tag: string
  mode: FloatingWindowMode
  contentType: FloatingWindowContentType
  ownerPage?: any | null
  ownerPageId?: string | null
  frame?: { x?: number | null; y?: number | null; width?: number | null; height?: number | null } | null
  appearance?: {
    cornerRadius?: number | null
    showTitleBar?: boolean | null
    showCloseButton?: boolean | null
    backgroundColor?: string | null
  } | null
  behavior?: {
    canDrag?: boolean | null
    autoRestoreToApp?: boolean | null
    replaceExisting?: boolean | null
  } | null
  webview?: FloatingWindowWebViewContent | null
  video?: FloatingWindowVideoContent | null
  extra?: UTSJSONObject | null
}

webview

至少提供以下其中一组:

  • url
  • html + baseUrl?
  • assetPath

示例:

webview: {
  assetPath: '/static/pip/demo.html',
  jsBridgeEnabled: true,
}

video-url

video: {
  url: 'https://example.com/demo.mp4',
  title: 'Hans PiP Demo',
  subtitle: 'video host',
  aspectRatio: '16:9',
  autoEnter: true,
  isMuted: false,
  allowsExternalPlayback: true,
  startPositionMs: 5000,
}

示例

Overlay / In-App Float

const openOptions: FloatingWindowOpenOptions = {
  tag: 'demo-primary',
  mode: 'android-overlay-window',
  contentType: 'webview',
  ownerPage,
  ownerPageId,
  frame: { x: 24, y: 160, width: 300, height: 220 },
  appearance: {
    cornerRadius: 20,
    showTitleBar: true,
    showCloseButton: true,
    backgroundColor: '#FFFDF6',
  },
  '/static/pip/demo.html',
    jsBridgeEnabled: true,
  },
}

windowManager.open(openOptions)

System PiP

windowManager.open({
  tag: 'demo-system-pip',
  mode: 'android-system-video-pip',
  contentType: 'video-url',
  video: {
    url: 'https://example.com/demo.mp4',
    title: 'Hans PiP Demo',
    autoEnter: true,
  },
})

ownerPage 约定

ios-in-app-floatpage-owned 模式,页面侧需要复用稳定的 ownerPageownerPageId,并在页面卸载时主动清理:

const pages = getCurrentPages()
const ownerPage = pages.length > 0 ? pages[pages.length - 1] : null
const ownerPageId = `page:${Date.now()}`

onUnload(() => {
  windowManager.cleanupPageOwnedWindows({
    ownerPage,
    ownerPageId,
    reason: 'page-unload',
  })
})

如果同一窗口的 ownerPage / ownerPageId 不一致,应预期收到 9012011

JS Bridge

callJS(...) 只对 contentType = 'webview' 可用。

桥对象:

  • window.HansPipBridge.postMessage(payload)

推荐消息格式:

type FloatingWindowJSBridgeMessage = {
  event: string
  callbackId?: string | null
  data?: UTSJSONObject | null
}

宿主侧通过 onWindowEvent(...) 接收 js-callback 事件。跨端最低保证是 data.rawMessage 会回流到宿主。

常见事件

  • 通用:openedrefreshedframe-updatedclosed
  • WebView:webview-readywebview-errorjs-callback
  • Overlay:native-close-requestrestore-requestedframe-dragged
  • Android system PiP:pip-host-readypip-enteredpip-refreshedvideo-readyvideo-rendering-startvideo-completedvideo-errorrestored-to-app
  • iOS out-app PiP:video-readypip-refreshedvideo-playedvideo-pausedvideo-seekedvideo-error

平台限制

Android

  • overlay 模式需要系统授予悬浮窗权限。
  • canDrawOverlaysSync() 仅 Android 可用。
  • openOverlayPermissionSettings() 仅 Android 可用。

iOS

  • ios-out-app-pip 依赖宿主具备对应后台音视频能力。
  • ios-in-app-float 必须正确传递并复用 ownerPage / ownerPageId
  • bringAppToFront() 在 iOS 不保证可用。

错误码

errCode 含义
9012001 当前平台不支持该模式
9012002 权限或宿主配置缺失
9012003 参数非法
9012004 宿主未就绪
9012005 当前状态不允许此操作
9012006 原生调用失败
9012007 系统版本不足
9012008 能力尚未实现
9012009 tag 冲突
9012010 目标窗口不存在
9012011 页面作用域或宿主上下文无效

排障建议

  • 先看 checkSupportSync(...).issues
  • 再看 validateOpenOptionsSync(...).issues
  • WebView 场景优先确认是否收到 webview-ready
  • iOS in-app float 场景优先检查 ownerPage / ownerPageId 是否稳定。
  • Android overlay 场景优先检查权限。

隐私、权限声明

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

Android overlay 模式需要 SYSTEM_ALERT_WINDOW;Android system PiP 依赖宿主与 ROM 对 picture-in-picture 的实际支持;iOS out-app PiP 依赖宿主开启 UIBackgroundModes(audio) 等对应后台音视频能力;Harmony 当前仅提供编译期 stub。

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

插件用于创建和管理小窗口 / 悬浮窗实例,业务方可透传 WebView URL 或视频地址等展示数据;当前阶段不包含账号体系和远程数据上传。

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

暂无用户评论。