更新记录

1.0.2(2024-08-28) 下载此版本

  • 修复新版编译器报错 activity 找不到的问题。
  • 新增 checkPermission API,用于检查是否获取了权限。
  • 新增 checkSupportPIP API,用于检查当前设备系统是否支持PIP画中画功能。
  • 错误码新增 1003,表示当前设备不支持PIP画中画功能。
  • 优化其他已知问题。

1.0.1(2024-03-08) 下载此版本

优化错误反馈,新增源错误返回

1.0.0(2024-03-06) 下载此版本

初始发布

查看更多

平台兼容性

Vue2 Vue3
App 快应用 微信小程序 支付宝小程序 百度小程序 字节小程序 QQ小程序
HBuilderX 3.6.8,Android:8.0,iOS:不确定,HarmonyNext:不确定 × × × × × ×
钉钉小程序 快手小程序 飞书小程序 京东小程序
× × × ×
H5-Safari Android Browser 微信浏览器(Android) QQ浏览器(Android) Chrome IE Edge Firefox PC-Safari
× × × × × × × × ×

kux-pip

kux-pip 是一个原生画中画的简单封装实现,可以实现简单类似视频软件的小窗播放效果。支持画中画窗口变化监听、自定义宽高比等。

开源地址:https://gitcode.com/kviewui/kux-pip

插件特色

  • 原生画中画实现
  • 窗口变化监听
  • 自定义宽高比
  •  同时支持 uniapp 项目和 uniapp x 项目

目录结构

  1. 基础
    1. 安装配置
    2. 入门使用
  2. API
    1. start
    2. checkPermission
    3. checkSupportPIP
  3. 自定义类型
    1. StartOptions
  4. 错误码

基础

安装配置

本插件为完全的 uni_modules 插件,所以直接在 插件市场 搜索 kux-pip 安装即可。

入门使用

注意

需要打包自定义基座方可正常使用

uniapp x项目示例

<template>
    <!-- #ifdef APP -->
    <scroll-view style="flex:1">
    <!-- #endif -->
        <!-- 状态栏 -->
        <view v-if="height == initHeight" class="status_bar"></view>
        <view>
            <video ref="videoRef" style="width: 100%;" :style="{height: height + 'px'}" :controls="true" src="http://www.runoob.com/try/demo_source/mov_bbb.mp4"></video>
        </view>
        <button @tap="enterPictureInPictureMode">开启画中画模式</button>
        <button @tap="onCheckPermission">检查权限是否被授予</button>
        <button @tap="onCheckSupportPIP">检查是否支持画中画</button>
    <!-- #ifdef APP -->
    </scroll-view>
    <!-- #endif -->
</template>

<script setup>
    import { start, StartOptions, StartSuccess, checkPermission, checkSupportPIP  } from '@/uni_modules/kux-pip';

    const videoRef = ref<UniVideoElement | null>(null);

    const initHeight = ref(200);
    const height = ref(initHeight.value);

    function enterPictureInPictureMode() {
        start({
            success(res: StartSuccess) {
                console.log(res, '成功回调');
            },
            fail(res: UniError) {
                console.log(res, '失败回调');
            },
            complete(res: any) {
                console.log(res, '完成回调');
            },
            stateChange(res) {
                if (res.height < initHeight.value) {
                    height.value = res.height;
                } else {
                    height.value = initHeight.value;
                }
            }
        } as StartOptions);
    }

    const modal = (message: string) => {
        uni.showModal({
            title: '提示',
            content: message,
            showCancel: false
        })
    }

    const onCheckPermission = () => {
        try {
            if (checkPermission()) {
                modal('权限已获取');
            } else {
                modal('权限未获取');
            }
        } catch (err: UniError) {
            modal(`检查权限失败:${err.errMsg}`);
        }
    }

    const onCheckSupportPIP = () => {
        if (checkSupportPIP()) {
            modal('支持画中画');
        } else {
            modal('不支持画中画');
        }
    }
</script>

<style>
    .status_bar {
        height: var(--status-bar-height);
        width: 100%;
        background-color: black;
    }
</style>

uniapp 项目示例

<template>
    <!-- #ifdef APP -->
    <scroll-view style="flex:1">
    <!-- #endif -->
        <!-- 状态栏 -->
        <view v-if="height == initHeight" class="status_bar"></view>
        <view>
            <video id="video" ref="videoRef" :style="{height: height + 'px', width: width}" :controls="true" src="http://www.runoob.com/try/demo_source/mov_bbb.mp4"></video>
        </view>
        <button @click="enterPictureInPictureMode">开启画中画模式</button>
        <button @tap="onCheckPermission">检查权限是否被授予</button>
        <button @tap="onCheckSupportPIP">检查是否支持画中画</button>
    <!-- #ifdef APP -->
    </scroll-view>
    <!-- #endif -->
</template>

<script lang="ts" setup>
    import { ref } from 'vue';
    import { start, StartOptions, StartSuccess, checkPermission, checkSupportPIP } from '@/uni_modules/kux-pip';
    import { onReady } from '@dcloudio/uni-app';

    // const videoRef = ref<UniVideoElement | null>(null);

    const initHeight = ref(200);
    const height = ref(initHeight.value);
    const width = ref('100%');

    const videoContext = ref(null);

    onReady(() => {
        videoContext.value = uni.createVideoContext('video');
    })

    function enterPictureInPictureMode() {
        start({
            success(res: StartSuccess) {
                console.log(res, '成功回调');
            },
            fail(res) {
                console.log(res, '失败回调');
            },
            complete(res: any) {
                console.log(res, '完成回调');
            },
            stateChange(res) {
                if (res.height < initHeight.value) {
                    height.value = res.height;
                    width.value = `${res.width}px`;
                    videoContext.value!.play();
                } else {
                    height.value = initHeight.value;
                    width.value = '100%';
                }
            }
        } as StartOptions);
    }

    const modal = (message: string) => {
        uni.showModal({
            title: '提示',
            content: message,
            showCancel: false
        })
    }

    const onCheckPermission = () => {
        try {
            if (checkPermission()) {
                modal('权限已获取');
            } else {
                modal('权限未获取');
            }
        } catch (err: UniError) {
            modal(`检查权限失败:${err.errMsg}`);
        }
    }

    const onCheckSupportPIP = () => {
        if (checkSupportPIP()) {
            modal('支持画中画');
        } else {
            modal('不支持画中画');
        }
    }
</script>

<style>
    .status_bar {
        height: var(--status-bar-height);
        width: 100%;
        background-color: black;
    }
</style>

注意

  • 因为uniapp项目的activity管理和uniapp x的有差异,所以uniapp项目小窗是把整个应用小窗了,这点要特别注意下

  • 需要小窗的页面建议禁用原生导航栏

  • uniapp项目下需要自己调整进入小窗和退出小窗时页面内容的样式布局,可以参考上面示例代码和uniapp x的是有少许的差异

  • 编译器 4.25 及以上版本测试有些问题,报错:uts.sdk.modules.kuxPipIndexKt.startByJs stateChange is not found,该问题后续找官方协助解决

API

start

  • 描述:开启画中画
  • 参数:StartOptions
  • 返回值:void

checkPermission

  • 描述:检查权限是否被授予

  • 参数:void

  • 返回值:boolean

  • 注意事项:

    • 该方法如果权限检查失败会抛出 UniError 异常,所以需要用 try...catch 捕获异常
    • v1.0.2 及以上版本支持
  • 示例:

    try {
        const permission = checkPermission();
        if (permission) {
            console.log('权限已获取');
        } else {
            console.log('权限未获取');
        }
    } catch (err: UniError) {
        console.log(`检查权限失败:${err.errMsg}`);
    }

checkSupportPIP

  • 描述:检查是否支持画中画

  • 参数:void

  • 返回值:boolean

  • 注意事项:

    • v1.0.2 及以上版本支持
  • 示例:

    const support = checkSupportPIP();
    if (support) {
        console.log('支持画中画');
    } else {
        console.log('不支持画中画');
    }

StartOptions

参数名 类型 是否必填 默认值 描述
numerator number 16 自定义像素比的分子或者长度比例
denominator number 9 自定义像素比的分母或者宽度比例
success (res: StartSuccess) => void - 成功回调
fail (res: UniError) => void - 失败回调
complete (res: any) => void - 完成回调
stateChange (res: StateChange) => void - 窗口变化监听回调

StartSuccess

参数名 类型 描述
errCode number 成功状态码
errMsg string 成功描述

StateChange

参数名 类型 描述
width number 画中画窗口宽度
height number 画中画窗口高度

自定义类型

StartSuccess

export type StartSuccess = {
    errCode: number;
    errMsg: string;
}

StateChange

export type StateChange = {
    width: number;
    height: number;
}

StartOptions

export type StartOptions = {
    numerator?: number;
    denominator?: number;
    success?: (res: StartSuccess) => void;
    fail?: (res: UniError) => void;
    complete?: (res: any) => void;
    stateChange?: (res: StateChange) => void;
}

Start

export type Start = (options: StartOptions) => void;

StartErrorCode

export type StartErrorCode = 1001 | 1002;

StartFail

export interface StartFail extends IUniError {
    errCode: StartErrorCode
}

错误码

错误码 描述
1001 开启画中画失败
1002 用户拒绝了画中画授权
1003 当前系统版本不支持画中画

友情推荐

隐私、权限声明

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

android.permission.FOREGROUND_SERVICE

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

插件不采集任何数据

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

许可协议

MIT协议

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问