AR在Unity3D中实现扫描下载断点续传 — HttpWebRequest

1.使用AssetBundle压缩资源上传到服务器
使用AssetBundle压缩资源上传到服务器
由于测试需要,可以把需要的数据模型等,直接放到服务器上。本人直接将需要下载的视频资源放到七流云空间。
编写脚本,不需要挂在任何物体上,Unity3D会检测到打包脚本,打包方法如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;                             //导入系统相关类

public class BUNAssets : MonoBehaviour {

    [@MenuItem("Test/Build Asset Bundles")]         //添加菜单栏"Test”以及子菜 单"Build Asset Bundles”       
    //声明BuildAssetBundles方法
       // 打包位置到指定文件夹下
    static void BuildAssetBundles()
    {   
        BuildPipeline.BuildAssetBundles(Application.dataPath + "/Assetbundle", BuildAssetBundleOptions.UncompressedAssetBundle,BuildTarget.iOS);
    }
}

2.个人最近研究的是EasyAR的官方SDK ,其中主要脚本官方已经给出,个人开发可以根据官方给的脚本进行操作实施,脚本编程如下

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.IO;
using System.Net;
using UnityEngine.UI;
using System.Threading;
//using UnityEngine.UI;
namespace EasyAR
{
    public class EasyImageTargetBehaviour : ImageTargetBehaviour
    {

        bool isDone;
//      Image image;
         Text text;
        float localprogress ;
        HttpDownLoad http;


        public string BundleURL;
        public string AssetName ; // 预控件名称
        // strat 方法
        protected override void Awake()
        {
            BundleURL = Application.dataPath + "/Assetbundle/workroom.mp4";
            text = GameObject.Find ("Canvas/Text").gameObject.GetComponent (); //进度条文字 拿到项目上悬挂的脚本找到Text控件
            base.Awake();
            TargetFound += OnTargetFound;
            TargetLost += OnTargetLost;
            TargetLoad += OnTargetLoad;
            TargetUnload += OnTargetUnload;
        }
            
        protected void Update()
        {
//          if (System.IO.File.Exists (Application.dataPath + "/Assetbundle/workroom.mp4") == true) {
//              return;
//          }
            text.text = "资源加载中" + (http.progress * 100).ToString ("0.00") + "%";    

            if(http.progress == 1)
            {
                if (System.IO.File.Exists (Application.dataPath + "/Assetbundle/1164.mov") == true) {
                    Debug.Log ("Update 中 拿到下载完毕----");
                    isDone = false;
                    Destroy(GameObject.Find("Canvas/Text")); //销毁资源
                    http.Close ();
                }
            }
        }
        void OnTargetFound(TargetAbstractBehaviour behaviour)
        {
            Debug.Log("OnTargetFound: " + Target.Id +Target.Name);
                if (System.IO.File.Exists (Application.dataPath +"/Assetbundle/1164.mov") == false) {
//                  StartCoroutine (progress1.DownloadVideo (@"http://ot24avzj3.bkt.clouddn.com/1164.mov", Application.dataPath +"/Assetbundle/1164.mov"));
//                  判断异步对象并且异步对象没有加载完毕,显示进度    
                    http = new HttpDownLoad();
    http.DownLoad(@"http://ot24avzj3.bkt.clouddn.com/1164.mov", Application.dataPath +"/Assetbundle/1164.mov", LoadLevel);
//                  Down_List ();

                return;
            }

//  该处需根据个人需要加载个人所需要的资源
//          AssetBundle modelBundle = AssetBundle.LoadFromFile (BundleURL); //根据文本路径找到打包的数据
//          GameObject model = modelBundle.LoadAsset (AssetName) as GameObject;//根据预控件的名字加载模型
//          if (model != null) {
//              Instantiate (model); //实例化模型
//          }
//          model.transform.position = new Vector3 (-10f, 0f, 0f); // 设置位置
//          modelBundle.Unload (false);//卸载资源
        }

        void LoadLevel()
        {
            isDone = true;
        }


        void OnTargetLost(TargetAbstractBehaviour behaviour)
        {
            Debug.Log("Lost: " + Target.Id);
            if (Target.Name == "koala") {
                text.text = "";
                http.Close ();
            }
        }

        void OnTargetLoad(ImageTargetBaseBehaviour behaviour, ImageTrackerBaseBehaviour tracker, bool status)
        {
            Debug.Log("Load target (" + status + "): " + Target.Id + " (" + Target.Name + ") " + " -> " + tracker);
        }

        void OnTargetUnload(ImageTargetBaseBehaviour behaviour, ImageTrackerBaseBehaviour tracker, bool status)
        {
            Debug.Log("Unload target (" + status + "): " + Target.Id + " (" + Target.Name + ") " + " -> " + tracker);
        }
    
}

3.下载脚本,编程如下。
涉及的知识点有

1. 线程的使用 Thread
2. 流文件的操作 FileStream
3. 网络下载 HttpWebRequest(同理也可以使用官方在推崇的WWW方式,个人使用过之后觉得大多已被封装,可扩展操作性空间较小)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.IO;
using System;
using System.Threading;

public class HttpDownLoad{

    //下载进度
    public float progress{get; private set;} //C#私有属性,set 前面加private 告诉编译器属性是只读的,外部不能给属性赋值,只能读取其值
    //涉及子线程要注意,Unity关闭的时候子线程不会关闭,所以要有一个标识
    private bool isStop;
    //子线程负责下载,否则会阻塞主线程,Unity界面会卡主
    public Thread thread;
    //表示下载是否完成
    public bool isDone{get; private set;}

    const int oneReadLen = 16384;           // 一次读取长度 16384 = 16*kb
    const int ReadWriteTimeOut = 2 * 1000;  // 超时等待时间
    const int TimeOutWait = 5 * 1000;       // 超时等待时间
    const int MaxTryTime = 3;

    /// 
    /// 下载方法(断点续传)
    /// 
    /// URL下载地址
    /// Save path保存路径
    /// Call back回调函数
    public void DownLoad(string downUrl, string savePath, Action callBack)
    {
        if (System.IO.File.Exists (savePath) == true  ) { //如果本地文件存在储存路劲则
            return;
        }
        isStop = false;
        //开启子线程下载,使用匿名方法

        thread = new Thread(delegate() {
            //打开上次下载的文件
            long startPos = 0;
            string tempFile = savePath+".temp";
            FileStream fs = null; // 文件
            //使用流操作文件
            if (File.Exists(tempFile))
            {
                fs = File.OpenWrite(tempFile);
                startPos = fs.Length;

            }
            else
            {
                string direName = Path.GetDirectoryName(tempFile); //返回指定路径字符串的目录信息
                if (!Directory.Exists(direName)) Directory.CreateDirectory(direName); //在direName目录下创建目录
                fs = new FileStream(tempFile, FileMode.Create);//创建流文件
            }
            //获取文件现在的长度
            long fileLength = fs.Length;
            //获取下载文件的总长度
            long totalLength = GetLength(downUrl);
            //如果没下载完
            if(fileLength < totalLength)
            {
                //断点续传核心,设置本地文件流的起始位置
                fs.Seek(fileLength, SeekOrigin.Begin);
                //创建网络请求
                HttpWebRequest request = HttpWebRequest.Create(downUrl) as HttpWebRequest;

                //断点续传核心,设置远程访问文件流的起始位置
                request.AddRange((int)fileLength);
                Stream  stream = request.GetResponse().GetResponseStream();
                byte[] buffer = new byte[1024];
                //使用流读取内容到buffer中
                //注意方法返回值代表读取的实际长度,并不是buffer有多大,stream就会读进去多少
                int length = stream.Read(buffer, 0, buffer.Length);
                while(length > 0)
                {
                    //如果Unity客户端关闭,停止下载
                    if(isStop) break;
                    //将内容再写入本地文件中
                    fs.Write(buffer, 0, length);
                    //计算进度
                    fileLength += length;

                    // 判断是否下载完成
                    if (fileLength == totalLength)
                    {
                        fs.Flush();// 清除该流的所有缓冲区,使得所有缓冲的数据都被写入到基础设备
                        fs.Close();// 关闭流
                        fs = null;
                        if (File.Exists(savePath)) File.Delete(savePath);
                        File.Move(tempFile, savePath);  // 下载完成将temp文件,改成正式文件
                    }
                    progress = (float)fileLength / (float)totalLength;
                    UnityEngine.Debug.Log(progress);
                    //类似尾递归
                    length = stream.Read(buffer, 0, buffer.Length); // 返回读入缓冲区的最大字节
                }
                stream.Close();    // 关闭链接
                stream.Dispose(); //  这个链接不需要了,可以释放资源

            }
            else
            {
                progress = 1;
                fs.Flush();
                fs.Close();
                fs = null;
                if (File.Exists(savePath)) File.Delete(savePath); //如果文件里存在了,就删了
                File.Move(tempFile, savePath);
            
            }
            fs.Close();
            fs.Dispose();
            //如果下载完毕,执行回调
            if(progress == 1)
            {
                isDone = true;
                if(callBack != null) callBack();
            }

        });
        //开启子线程
        thread.IsBackground = true;
        thread.Start();

    }


    /// 
    /// 获取下载文件的大小
    /// 
    /// The GetLength.
    /// URL.

    public static long GetLength(string url)
    {
        HttpWebRequest request = null;
        WebResponse respone = null;
        long length = 0;
        try
        {
            request = WebRequest.Create(url) as HttpWebRequest;
//          request.Timeout = TimeOutWait;
//          request.ReadWriteTimeout = ReadWriteTimeOut;
            //向服务器请求,获得服务器回应数据流
            respone = request.GetResponse();
            length = respone.ContentLength;
        }
        catch (WebException e)
        {
            throw e;
        }
        finally
        {
            if (respone != null) respone.Close();
            if (request != null) request.Abort();
        }
        return length;
    }

    public void Close()
    {
        isStop = true;
    }


}

Unity3D小白,研究过程主要参考技术博客如下:
Unity技术博客 - 客户端断点续传
转载合作相关事宜,请联系我的经纪人。额,还没有经纪人,联系本人,转载系出处,谢谢。

你可能感兴趣的:(AR在Unity3D中实现扫描下载断点续传 — HttpWebRequest)