更新记录

1.0.1(2020-09-12)

第一版暂时支持进度显示 暂停 播放 恢复 以及删除功能,后期会继续完善此插件,因为工作中用到,敬请关注


平台兼容性

Android Android CPU类型 iOS
适用版本区间:6.0 - 11.0 armeabi-v7a:支持,arm64-v8a:支持,x86:未测试 ×

原生插件通用使用流程:

  1. 购买插件,选择该插件绑定的项目。
  2. 在HBuilderX里找到项目,在manifest的app原生插件配置中勾选模块,如需要填写参数则参考插件作者的文档添加。
  3. 根据插件作者的提供的文档开发代码,在代码中引用插件,调用插件功能。
  4. 打包自定义基座,选择插件,得到自定义基座,然后运行时选择自定义基座,进行log输出测试。
  5. 开发完毕后正式云打包

付费原生插件目前不支持离线打包。
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;
            }
        }
    }

如果在插件使用过过程中遇到什么问题,欢迎发送邮件到924462390@qq.com 空了会一一回复消息。

隐私、权限声明

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

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

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

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