更新记录
1.0.3(2022-01-15)
- 修复暂停后状态未改变问题
1.0.2(2021-11-25)
支持添加请求头
1.0.1(2021-11-23)
优化高性能手机
查看更多平台兼容性
Android | Android CPU类型 | iOS |
---|---|---|
适用版本区间:4.4 - 11.0 | armeabi-v7a:未测试,arm64-v8a:未测试,x86:未测试 | 适用版本区间:9 - 14 |
原生插件通用使用流程:
- 购买插件,选择该插件绑定的项目。
- 在HBuilderX里找到项目,在manifest的app原生插件配置中勾选模块,如需要填写参数则参考插件作者的文档添加。
- 根据插件作者的提供的文档开发代码,在代码中引用插件,调用插件功能。
- 打包自定义基座,选择插件,得到自定义基座,然后运行时选择自定义基座,进行log输出测试。
- 开发完毕后正式云打包
付费原生插件目前不支持离线打包。
Android 离线打包原生插件另见文档 https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/android
iOS 离线打包原生插件另见文档 https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/ios
注意事项:使用HBuilderX2.7.14以下版本,如果同一插件且同一appid下购买并绑定了多个包名,提交云打包界面提示包名绑定不一致时,需要在HBuilderX项目中manifest.json->“App原生插件配置”->”云端插件“列表中删除该插件重新选择
前言
wrs-download下载m3u8视频,开始下载、暂停、下载进度,多个TS切换视频同时下载,加快下载速度,支持加密key,包含播放下载后的m3u8视频,通过开启本地http server和支持m3u8的播放器实现
功能
- 开始下载、暂停、下载进度
- 多个TS视频同时下载,加快下载速度
- 支持加密key
- 播放下载后的m3u8视频
wrs-download组件
var wrsDownload = uni.requireNativePlugin("wrs-download");
var video = {
url:'xxx',
saveDir:'xxx',
sameTimeDownloadTSCount: 2,
headers:{ // 请求头,没有需要可以不传
token:"544asfaf"
}
}
wrsDownload.startDownload(video, resp => {
console.log('m3u8 downloadProgress:' + JSON.stringify(resp) + ' url:' + video.url);
video.progress = resp.progress;
}, resp => {
console.log('m3u8 downloadFinish:' + JSON.stringify(resp));
if (resp.suc) {
console.log('m3u8 下载成功 url:' + video.url);
} else {
console.log('m3u8 下载失败 url:' + video.url);
}
});
方法
-
wrsDownload.startDownload(params, progressCallback, finishCallback)函数
- params: 下载参数,包含
- url: m3u8地址
- saveDir: m3u8下载后保存到本地的目录,需要为每个视频单独指定一个文件夹来保存,不能把多个视频下载到同一个文件夹里,下载后的本地m3u8文件路径就在saveDir文件夹下的index.m3u8,所有的TS文件也在此文件夹下
- sameTimeDownloadTSCount: 支持同时下载的TS个数,受限于手机线程性能,所有的视频加起来的TS个数最好不要超过20,否则可能某些视频下载进度会特别慢,如果没有特别需要快速下载的需求,sameTimeDownloadTSCount指定为1就可以
- progressCallback: 下载进度回调
- finishCallback: 下载成功或下载失败回调
-
wrsDownload.pauseDownload(params) 暂停下载
var video = this.videos[index];
var params = {};
params.url = "xxx";
wrsDownload.pauseDownload(params);
- wrsDownload.deleteDownload(params) 删除
var video = this.videos[index];
var params = {};
params.url = video.url;
wrsDownload.deleteDownload(video);
- wrsDownload.getVideoInfo(params) 获取某个视频信息
var video = this.videos[index];
var params = {};
params.url = video.url;
var resp = wrsDownload.getVideoInfo(video);
- wrsDownload.getVideoInfos() 获取所有视频信息
var resp = wrsDownload.getVideoInfos();
resp 数据:
- videoHomePath: 视频保存路径
- url:下载地址
- videoDownloadState: 下载状态, 0:没下载完 1:下载中 2:暂停中 3:下载完成
- sameTimeDownloadTSCount: 一次可以同时下载TS的数量
- wrsDownload.saveDownloadProgress() 下载进度实时同步到本地,一般在退出下载界面或app从前台切换到后台时调用
完整demo
index.nvue
<template>
<div>
<text>M3u8Demo</text>
<view v-for="(item, index) in videos" :key="index">
<text class="title"> m3u8视频{{index + 1}}</text>
<button @click="download(index)">下载</button>
<button @click="pauseDownload(index)">暂停</button>
<button @click="deleteDownload(index)">删除</button>
<button @click="getVideoInfo(index)">获取视频信息</button>
<button @click="play(index)">播放本地下载的m3u8视频</button>
下载进度:<text>{{item.progress}}</text>
视频信息:<text>{{item.fileInfo}}</text>
</view>
<button @click="startHttpServer">开启本地http server</button>
<button @click="getVideoInfos()">获取本地所有视频信息</button>
所有视频信息:{{videoInfos}}
</div>
</template>
<script>
// import cmdProgress from "@/components/cmd-progress/cmd-progress.vue"
var wrsDownload = uni.requireNativePlugin("wrs-download");
// httpServer本地服务插件,用于在app内生成http服务,这样就可以在本地播放下载好的m3u8视频了,参考:https://ext.dcloud.net.cn/plugin?id=5491
var httpServer = uni.requireNativePlugin("wrs-httpserver");
String.prototype.endWith = function(endStr) {
var d = this.length - endStr.length;
return (d >= 0 && this.lastIndexOf(endStr) == d)
}
export default {
data() {
var videoSaveDir = "";
var absPath = plus.io.convertLocalFileSystemURL('_documents');
// Android获取的absPath以/结尾,iOS获取的absPath不是/结尾
if (absPath.endWith('/')) {
absPath = absPath.substring(0, absPath.length - 1);
}
videoSaveDir = absPath;
console.log("videoSaveDir:" + videoSaveDir);
return {
videoSaveDir: videoSaveDir,
videoInfos: '',
webUrlPath:"videoSys",
webPort: 8030,
videos: [{
url: 'https://vod3.buycar5.cn/20210411/AS69NX6j/1000kb/hls/index.m3u8',
saveDir: videoSaveDir + '/testVideo1',
sameTimeDownloadTSCount: 5,
progress: 0,
fileInfo: ''
},
{
url: 'http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8',
saveDir: videoSaveDir + '/testVideo2',
sameTimeDownloadTSCount: 5,
progress: 0,
fileInfo: ''
},
{
url: 'http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8',
saveDir: videoSaveDir + '/testVideo3',
sameTimeDownloadTSCount: 5,
progress: 0,
fileInfo: ''
}
]
}
},
onLoad() {
// 设置播放器宽高,一般宽度铺满全屏,宽高比是16:9
},
onUnload() {
wrsDownload.saveDownloadProgress();
},
methods: {
download: function(index) {
var video = this.videos[index];
wrsDownload.startDownload(video, resp => {
console.log('m3u8 downloadProgress:' + JSON.stringify(resp) + ' url:' + video.url);
video.progress = resp.progress;
}, resp => {
console.log('m3u8 downloadFinish:' + JSON.stringify(resp));
if (resp.suc) {
console.log('m3u8 下载成功 url:' + video.url);
} else {
console.log('m3u8 下载失败 url:' + video.url);
}
});
},
pauseDownload: function(index) {
var video = this.videos[index];
var params = {};
params.url = video.url;
wrsDownload.pauseDownload(params);
},
deleteDownload: function(index) {
var video = this.videos[index];
var params = {};
params.url = video.url;
wrsDownload.deleteDownload(video);
},
getVideoInfo: function(index) {
var video = this.videos[index];
var params = {};
params.url = video.url;
var resp = wrsDownload.getVideoInfo(video);
video.fileInfo = JSON.stringify(resp);
},
getVideoInfos: function() {
var resp = wrsDownload.getVideoInfos();
this.videoInfos = JSON.stringify(resp);
},
startHttpServer: function() {
var staticWebs = [];
staticWebs.push({
urlPath: '/' + this.webUrlPath, // 站点请求的url
directoryPath: this.videoSaveDir, // web站点文件绝对路径,这个路径是绝对路径
});
var params = {
port: this.webPort, // 端口
staticWebs: staticWebs
};
// 启动http service
httpServer.startServer(params, (resp) => {
if (resp.code == 0) {
console.log("httpServer启动成功:" + resp.serverHost);
} else {
console.log("httpServer启动失败:" + resp.msg);
}
});
},
play: function(index) {
var video = this.videos[index];
var saveDir = video.saveDir;
var videoSaveDir = this.videoSaveDir;
var path = saveDir.substr(videoSaveDir.length + 1, saveDir.length);
// http://192.168.0.93:8030/videosSys/testVideo1/index.m3u8
var url = "http://127.0.0.1:"+this.webPort+"/"+this.webUrlPath+"/" + path + "/index.m3u8";
console.log("url:" + url);
uni.navigateTo({
url: "./player?url=" + url
});
},
showMsg: function(msg) {
this.msg = msg;
}
}
}
</script>
<style>
.title {
text-align: center;
}
.btn {
margin-top: 25rpt;
}
</style>
player.nvue:
<template>
<div>
<!-- wrs-videoplayer视频播放器插件,用于播放m3u8视频,参考:https://ext.dcloud.net.cn/plugin?id=4998
-->
<wrs-videoplayer :config="config" :coverImage="coverImage" ref='videoPlayer' :url="url"
:style="'width:'+width+'px;height:'+height+'px;'" @onBarrageTypeChange="onBarrageTypeChange"
@playerPrepareToPlay="playerPrepareToPlay" @playerReadyToPlay="playerReadyToPlay"
@playerPlayTimeChanged="playerPlayTimeChanged" @playerPlayFailed="playerPlayFailed"
@playerDidToEnd="playerDidToEnd"></wrs-videoplayer>
</div>
</template>
<script>
export default {
data() {
return {
url: '',
coverImage: 'https://t7.baidu.com/it/u=2604797219,1573897854&fm=193&f=GIF',
index: 0,
urls: [],
height: 300,
width: 300,
msg: "",
danmuTime: null,
barrageType: 'all',
config: {
autoPlay: true
}
}
},
onLoad:function(option) {
// 设置播放器宽高,一般宽度铺满全屏,宽高比是16:9
const {
windowWidth,
windowHeight
} = uni.getSystemInfoSync();
this.width = windowWidth;
this.height = this.width / (16.0 / 9.0);
this.url = option.url;
console.log("url:" + this.url);
},
methods: {
playerPrepareToPlay: function(resp) {
var str = JSON.stringify(resp.detail);
},
playerReadyToPlay: function(resp) {
var str = JSON.stringify(resp.detail);
},
playerPlayTimeChanged: function(resp) {
var str = JSON.stringify(resp.detail);
},
playerBufferTimeChanged: function(resp) {
var str = JSON.stringify(resp.detail);
},
playerPlayFailed: function(resp) {
var str = JSON.stringify(resp.detail);
},
playerDidToEnd: function(resp) {
var str = JSON.stringify(resp.detail);
}
}
}
</script>
<style>
</style>