更新记录
1.0.1(2020-09-12)
第一版暂时支持进度显示 暂停 播放 恢复 以及删除功能,后期会继续完善此插件,因为工作中用到,敬请关注
平台兼容性
Android | Android CPU类型 | iOS |
---|---|---|
适用版本区间:6.0 - 11.0 | armeabi-v7a:支持,arm64-v8a:支持,x86:未测试 | × |
原生插件通用使用流程:
- 购买插件,选择该插件绑定的项目。
- 在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原生插件配置”->”云端插件“列表中删除该插件重新选择
欢迎使用UniAPP m3u8下载原生插件 支持进度显示 支持下载速度显示 暂停 恢复 以及删除功能 有详细DEMO 插件优惠中
此插件目前支持android端的m3u8文件下载功能,后期会增加加密播放,加密下载等功能敬请期待,目前初级版本优惠中,需要的可以试用,如果觉得可以就可以付费进行云打包试用
插件使用说明
//先引入原生插件
// #ifdef APP-PLUS
const dHttp = uni.requireNativePlugin('Wind-Hls');
// #endif
//调用API
dHttp.initM3u8Downloader({
url:plus.io.convertLocalFileSystemURL('_downloads'),
duration:10000,//每次连接时长
retry:3,//重试次数
timeout:10000, //超时时间
debug:true, //是否开启调试模式
encrypt:true,//是否对下载文件进行加密并且移除后缀名乱序等功能
},(data)=>{
//onDownloadItem
},(data)=>{
//onDownloadSuccess
},(data)=>{
//onDownloadPending
},(data)=>{
//onDownloadPrepare
console.log(data);
},(data)=>{
//onDownloadError
console.log(data);
},(res)=>{
//初始化成功
console.log(res);
});
API文档
接口 | 接口说明 |
---|---|
initM3u8Downloader(options:Object,onDownloadItem:function,onDownloadSuccess:function,onDownloadPending:function,onDownloadPrepare:function,onDownloadError:function,callback:function) | 初始化m3u8插件,callback初始化成功后出发的回掉函数 |
pause(options:Object,callback:function) | 暂停任务 |
download(options:Object,callback:function) | 下载任务 |
isDownloading(options:Object,callback:function) | 任务是否在下载 |
cancelAndDelete(options:Object,callback:function) | 取消并且删除已经下载的文件 |
cancel(options:Object,callback:function) | 取消任务 |
其他使用方式
//请注意务必开启以下权限否则无法初始化
/**
*
* <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REORDER_TASKS"/>
*/
const dHttp = uni.requireNativePlugin('Wind-Http');
import downloadItem from './downloadItem.vue'
//引入数据库操作类
import Db from './db.js';
export default {
components:{
downloadItem
},
data() {
return {
downloadList:[],//上传列表
statusText:"",//上传状态信息
maxUploadNum:1,//每次最大上传数量默认为1
curUpload:0,//当前正在上传的个数,
downloadList:[],//这里是下载列表
};
},
onReady() {
//首先往sqlite写入测试数据
Db.insert({
id:1,
title:"测试视频1",
url:"https://dco4urblvsasc.cloudfront.net/811/81095_ywfZjAuP/game/index.m3u8",
cover:"https://ossweb-img.qq.com/images/lol/web201310/skin/big3900",
progress:0,
status:""
},'video_download')
Db.insert({
id:2,
title:"测试视频2",
url:"http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8",
cover:"https://ossweb-img.qq.com/images/lol/web201310/skin/big3900",
progress:0,
status:""
},'video_download')
Db.insert({
id:3,
title:"测试视频3",
url:"http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8",
cover:"https://ossweb-img.qq.com/images/lol/web201310/skin/big3900",
progress:0,
status:""
},'video_download')
//初始化
this.init();
//这里暂时做一个延迟获取sqlite数据
setTimeout(()=>{
//获取数据
this.queryAll().then(res=>{
this.queneUpload()
})
},1000)
},
computed:{
taskList(){
return this.downloadList.sort((a,b)=>{
return a.progress -b.progress;
})
}
},
methods:{
init(){
console.log('init.....',dHttp.initM3u8Downloader);
dHttp.initM3u8Downloader({
url:plus.io.convertLocalFileSystemURL('_downloads'),
duration:10000,//每次连接时长
retry:3,//重试次数
timeout:10000, //超时时间
debug:true, //是否开启调试模式
encrypt:true,//是否对下载文件进行加密并且移除后缀名乱序等功能
},(data)=>{
//onDownloadItem
/**
*
public static final int DEFAULT = 0;//默认状态
public static final int PENDING = -1;//下载排队
public static final int PREPARE = 1;//下载准备中
public static final int DOWNLOADING = 2;//下载中
public static final int SUCCESS = 3;//下载完成
public static final int ERROR = 4;//下载出错
public static final int PAUSE = 5;//下载暂停
public static final int ENOSPC = 6;//空间不足
*/
console.log(data);
switch(data.task.state){
case 0:
break;
case -1:
this.setPathInfo(data.task.url,'status',"Line Up");
break;
case 1:
this.setPathInfo(data.task.url,'status',"Download Ready");
break;
case 2:
this.setPathInfo(data.task.url,'status',"Downloading..."+data.task.formatSpeed);
break;
case 3:
this.setPathInfo(data.task.url,'status',"Download Success!");
break;
case 4:
this.setPathInfo(data.task.url,'status',"Download Fail!");
break;
case 5:
this.setPathInfo(data.task.url,'status',"Paused");
break;
case 6:
this.setPathInfo(data.task.url,'status',"Lack of space!");
break;
}
},(data)=>{
//onDownloadSuccess
Db.updateByPath(data.task.url,'video_download',{
field:"progress",
value:100
});
Db.updateByPath(data.task.url,'video_download',{
field:"status",
value:"Download Success"
});
this.setPathInfo(data.task.url,'progress',100+"%");
this.setPathInfo(data.task.url,'status',"Download Success");
//console.log(data);
//开启队列上传
//上传完了以后还要继续处理
this.queneUpload();//队列上传....
},(data)=>{
//onDownloadPending
console.log('onDownloadPending',data);
this.setPathInfo(data.task.url,'status',"Prepending....");
},(data)=>{
//onDownloadPause
console.log(data);
this.setPathInfo(data.task.url,'status',"Task Has Paused ");
this.setPathInfo(data.task.url,'progress',data.task.progress*100+"%");
},(data)=>{
//onDownloadProgress
console.log(data);
Db.updateByPath(data.task.url,'video_download',{
field:"progress",
value:parseInt(data.task.progress*100)
});
this.setPathInfo(data.task.url,'status',"Downloading... "+data.task.formatSpeed);
this.setPathInfo(data.task.url,'progress',parseInt(data.task.progress*100)+"%");
},(data)=>{
//onDownloadPrepare
console.log(data);
this.setPathInfo(data.task.url,'status',"Prepare....");
},(data)=>{
//onDownloadError
console.log(data);
this.setPathInfo(data.task.url,'status',"Download Error.... "+data.errorMsg);
},(res)=>{
//提示初始化成功
uni.showToast({
title:"初始化成功.....",
icon:"none"
});
console.log(res);
})
},
//开启下载
startDownload(num){
if(num == 1){
}else if(num == 2){
}else if(num == 3){
}
},
queryAll(){
return new Promise((resolve,reject)=>{
//这里的话
//获取数据
Db.select('select * from video_download',(data)=>{
console.log('downloadList....',data);
this.downloadList = data;
resolve(this.downloadList);
},(err)=>{
console.log(err);
resolve(false)
})
});
},
pause(url){
dHttp.pause({
url
},()=>{
uni.showToast({
title:"暂停成功!",
icon:"none"
})
});
},
resume(url){
dHttp.download({
url
},()=>{
uni.showToast({
title:"任务已开始!",
icon:"none"
})
});
},
del(url){
dHttp.isDownloading({url},(data)=>{
if(data.download){
dHttp.cancelAndDelete({
url
},()=>{
});
}
Db.deleteByPath(url,'video_download',()=>{
let curTaskIndex = this.downloadList.findIndex((task, index, arr) => {
return task.url == url;
})
this.downloadList.splice(curTaskIndex,1);
});
});
},
queneUpload(){
//队列上传,目前基于插件机制只支持一次性上传一个视频,上传完成以后
let len = this.downloadList.length;
if(len > 0){
for (let i=0;i<len; i++) {
let task = this.downloadList[i];
if(task.progress < 100){
if(this.curUpload <1){
console.log('开始上传....');
//调用原生插件进行上传
this.download(task.url);
break;
}
}
}
}
},
//下载
download(url){
console.log("正在下载的地址....",url);
dHttp.isDownloading({url},(data)=>{
if(data.download){
uni.showToast({
title:"该任务已在下载列表中!",
icon:"none"
});
}else{
dHttp.download({
url:url
},(data)=>{
uni.showToast({
title:"正在下载....."
})
});
}
});
},
insertInDb(insertData,shift){
Db.select(`select * from video_download where url='${insertData.url}'`,(item)=>{
//如果有数据就不添加到列表了
console.log('数据库中有么?',item.length);
if(item.length == 0){
Db.insert(insertData,'video_download',(data)=>{
//插入成功以后 push到上传列表
if(shift){
this.downloadList.unshift(insertData);
}else{
this.downloadList.push(insertData);
}
//提示初始化成功
uni.showToast({
title:"初始化成功.....",
icon:"none"
});
})
}
},(err)=>{
console.log(err);
resolve(false)
})
},
setStatusText(taskid,prop,value){
if(this.downloadList.length == 0){
return;
}
let curTaskIndex = this.downloadList.findIndex((task, index, arr) => {
return task.id == taskid;
})
if(curTaskIndex == -1){
return;
}
this.downloadList[curTaskIndex][prop] = value;
},
setPathInfo(url,prop,value){
if(this.downloadList.length == 0){
return;
}
let curTaskIndex = this.downloadList.findIndex((task, index, arr) => {
return task.url == url;
})
if(curTaskIndex == -1){
return;
}
this.downloadList[curTaskIndex][prop] = value;
},
checkHasPath(url){
if(this.downloadList.length == 0){
return false;
}
let curTaskIndex = this.downloadList.findIndex((task, index, arr) => {
return task.url == url;
})
if(curTaskIndex != -1){
return true;
}
return false;
}
}
}