| 
					
				 | 
			
			
				@@ -0,0 +1,539 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//  PQAliOssUtil.swift 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//  PQSpeed 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//  Created by SanW on 2020/12/9. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//  Copyright © 2020 BytesFlow. All rights reserved. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import UIKit 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import BFCommonKit 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import BFNetRequestKit 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// MARK: - 阿里OSS工具类 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/// 阿里OSS工具类 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+public class PQAliOssUtil: NSObject { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    static public let shared = PQAliOssUtil() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public var client: OSSClient? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 文件类型:materialType (1:PICTURE, 2:VIDEO, 3:VOICE, 4:FILE, 5:GIF) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public  var aliOssHander: ((_ isMatarialUpload: Bool, _ materialType: StickerType, _ fileExtensions: String, _ code: Int, _ objectKey: String?, _ contentMD5: String, _ width: CGFloat, _ height: CGFloat, _ duration: CGFloat, _ frameNumber: Int, _ netResourceUrl: String?, _ fileURL: URL?, _ data: Data?, _ msg: String?) -> Void)? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public  var aliOssProgressHander: ((_ bytesSent: Int64, _ totalBytesSent: Int64, _ totalBytesExpectedToSend: Int64, _ resttime: Int64, _ uploadSpeed: String?) -> Void)? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public  var lastInterfaceBytes: Int64 = 0 // 上次网速 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public var oldTime: Int = 0 // 上次进度时间S 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public var oloaded: Int64 = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public var dics: [String: Any] = [:] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public  var allTasks: [String: OSSMultipartUploadRequest] = [:] // add by ak 保存当前所有任务 用于取消某个任务使用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public  func startClient(accessKeyId: String, secretKeyId: String, securityToken: String, endpoint: String) -> PQAliOssUtil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if endpoint.count == 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            debugPrint("endpoint is nil xxxxxx \(endpoint)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let credential = OSSStsTokenCredentialProvider(accessKeyId: accessKeyId, secretKeyId: secretKeyId, securityToken: securityToken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let conf = OSSClientConfiguration() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        conf.timeoutIntervalForRequest = 60 // 连接超时,默认15秒 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        conf.maxRetryCount = 3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        conf.maxConcurrentRequestCount = 5 // 最大并发请求书,默认5个 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        client = OSSClient(endpoint: endpoint, credentialProvider: credential, clientConfiguration: conf) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return .shared 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// 图片上传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - Parameters: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - bucketName: <#bucketName description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - objectKey: <#objectKey description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - data: <#data description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - Returns: <#description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public  func uploadObjectAsync(bucketName: String, objectKey: String, data: Data, materialType: StickerType = .IMAGE, fileExtensions: String, isMatarialUpload: Bool = false, contentMD5: String = "", width: CGFloat = 0, height: CGFloat = 0, imageUploadBlock: @escaping (_ osstask: OSSTask<AnyObject>?, _ code: Int, _ objectKey: String, _ fileExtensions: String) -> Void) -> PQAliOssUtil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let putRequest: OSSPutObjectRequest = OSSPutObjectRequest() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        putRequest.bucketName = bucketName 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        putRequest.objectKey = objectKey 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        putRequest.uploadingData = data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        putRequest.uploadProgress = { [weak self] _, totalByteSent, totalBytesExpectedToSend in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            debugPrint("文件上传进度:totalByteSent = \(totalByteSent),totalBytesExpectedToSend = \(totalBytesExpectedToSend)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if totalBytesExpectedToSend > 0, totalByteSent == totalBytesExpectedToSend { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if isMatarialUpload, self?.aliOssHander != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    self?.aliOssHander!(isMatarialUpload, materialType, fileExtensions, 1, objectKey, contentMD5, width, height, 0, 0, nil, nil, data, "上传成功") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        putRequest.contentType = "application/octet-stream" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //        putRequest.contentMd5 = contentMD5 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        putRequest.contentEncoding = "" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        putRequest.contentDisposition = "" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let putTask: OSSTask = (client?.putObject(putRequest))! 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        putTask.continue(successBlock: { [weak self] (osstask) -> Any? in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if osstask.error == nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                let task = self?.client?.presignPublicURL(withBucketName: putRequest.bucketName, withObjectKey: putRequest.objectKey) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                debugPrint("图片原方法上传完成=\(objectKey)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                debugPrint("url == \(task?.result ?? "" as AnyObject)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                imageUploadBlock(osstask, 1, objectKey, fileExtensions) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if self?.aliOssHander != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    self?.aliOssHander!(isMatarialUpload, materialType, fileExtensions, 0, objectKey, contentMD5, width, height, 0, 0, nil, nil, data, "上传失败") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                debugPrint("图片原方法上传失败=\(objectKey),osstask.error = \(osstask.error ?? PQError(msg: "失败"))") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                imageUploadBlock(osstask, 0, objectKey, fileExtensions) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }).waitUntilFinished() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return .shared 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// 快速上传视频 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - Parameters: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - localPath: <#localPath description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - response: <#response description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - Returns: <#description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    class public  func multipartUpload(localPath: String, response: [String: Any]?,videoSource:String? = nil) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let accessKeyId: String = "\(response?["AccessKeyId"] ?? "")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let secretKeyId: String = "\(response?["AccessKeySecret"] ?? "")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let securityToken: String = "\(response?["SecurityToken"] ?? "")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let endpoint: String = "\(response?["Host"] ?? "")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let bucketName: String = "\(response?["Bucket"] ?? "")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let FileName: String = "\(response?["FileName"] ?? "")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let uploadID: String = "\(response?["Upload"] ?? "")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var endpoints: [String] = Array<String>.init() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if response?.keys.contains("Hosts") ?? false { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            endpoints = response?["Hosts"] as! [String] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            endpoints.append(endpoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        PQAliOssUtil.shared.PQOSSMultipartUpload(accessKeyId: accessKeyId, secretKeyId: secretKeyId, securityToken: securityToken, bucketName: bucketName, endpoints: endpoints, FileName: FileName, fileURL: URL(fileURLWithPath: localPath.replacingOccurrences(of: "file:///", with: "")), ossUploadID: uploadID, videoSource: videoSource) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// 重新上传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - Parameters: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - response: <#response description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - localPath: <#localPath description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - Returns: <#description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public  func reloadTask(response: [String: Any]?, localPath: String?,videoSource:String? = nil) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if response == nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let accessKeyId: String = "\(response?["AccessKeyId"] ?? "")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let secretKeyId: String = "\(response?["AccessKeySecret"] ?? "")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let securityToken: String = "\(response?["SecurityToken"] ?? "")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let endpoint: String = "\(response?["Host"] ?? "")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let bucketName: String = "\(response?["Bucket"] ?? "")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let FileName: String = "\(response?["FileName"] ?? "")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let uploadID: String = "\(response?["Upload"] ?? "")" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var endpoints: [String] = Array<String>.init() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if response?.keys.contains("Hosts") ?? false { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            endpoints = response?["Hosts"] as! [String] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            endpoints.append(endpoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        debugPrint("取我方服务器STS 返回数据 \(String(describing: response))") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        PQAliOssUtil.shared.PQOSSMultipartUpload(accessKeyId: accessKeyId, secretKeyId: secretKeyId, securityToken: securityToken, bucketName: bucketName, endpoints: endpoints, FileName: FileName, fileURL: URL(fileURLWithPath: (localPath ?? "").replacingOccurrences(of: "file:///", with: "")), ossUploadID: uploadID,videoSource: videoSource) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// 分片上传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - Parameters: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - accessKeyId: <#accessKeyId description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - secretKeyId: <#secretKeyId description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - securityToken: <#securityToken description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - bucketName: <#bucketName description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - endpoints: oss host域名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - FileName: oss 资源地址 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - fileURL: 文件本地地址 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - ossUploadID: oss 上传ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - contentType: 文件类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - materialType: 素材类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - isMatarialUpload: 是否是素材上传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - contentMD5: 素材内容MD5值 isMatarialUpload = true时传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - width: 视频宽 isMatarialUpload = true时传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - height: 视频高 isMatarialUpload = true时传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - Returns: <#description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public  func PQOSSMultipartUpload(accessKeyId: String, secretKeyId: String, securityToken: String, bucketName: String, endpoints: [String], FileName: String, fileURL: URL, ossUploadID: String, materialType: StickerType = .VIDEO, isMatarialUpload: Bool = false, contentMD5: String = "", width: CGFloat = 0, height: CGFloat = 0,videoSource:String? = nil) -> PQAliOssUtil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        debugPrint("上传数据 参数\n accessKeyId:\(accessKeyId)\n secretKeyId:\(secretKeyId)\n  securityToken:\(securityToken) \n bucketName:\(bucketName)\n endpoint:\(endpoints)\n FileName:\(FileName)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if endpoints.count <= 0 || (endpoints.first?.count ?? 0) <= 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            debugPrint("endpoints 为空") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return .shared 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        #if DEBUG 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 打开 oss 日志 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            OSSLog.enable() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        #endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 1,设置鉴权 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let url = PQENVUtil.shared.longvideoapi + (isMatarialUpload ? materialUploadStsTokenUrl : getStsTokenUrl) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let authServerUrl = url + "?appType=\(commonParams()["appType"] as? String ?? "")" + "&machineCode=" + getMachineCode() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            + "&token=" + (BFConfig.shared.token ?? "") + "&loginUid" + (BFConfig.shared.uid ?? "") + "&fileType=2" + "&uploadId=\(ossUploadID)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        debugPrint("authServerUrl is: \(authServerUrl)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        debugPrint("当前上传authServerUrl线程:\(Thread.isMainThread) ") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let provider = OSSAuthCredentialProvider(authServerUrl: authServerUrl) { (data) -> Data? in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            debugPrint("当前上传provider线程:\(Thread.isMainThread) ") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 在 OSSModel 代码中解析有自己的格式 所以接收到我方服务器后的数据要进行二次处理 AccessKeyId 等信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let str = String(data: data, encoding: .utf8) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let jsonDic = jsonStringToDictionary(str!) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var respDic: [String: Any] = [:] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if jsonDic?.keys.contains("code") ?? false, "\(jsonDic?["code"] ?? "")" == "0" { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                respDic = [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "StatusCode": "200", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "AccessKeyId": (jsonDic?["data"] as? [String: Any])?["AccessKeyId"] ?? accessKeyId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "AccessKeySecret": (jsonDic?["data"] as? [String: Any])?["AccessKeySecret"] ?? secretKeyId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "SecurityToken": (jsonDic?["data"] as? [String: Any])?["SecurityToken"] ?? securityToken, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "Expiration": (jsonDic?["data"] as? [String: Any])?["Expiration"] ?? securityToken, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let proStr = dictionaryToJsonString(respDic as [String: Any]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            debugPrint("处理后准备给 OSS SDK数据 \(String(describing: proStr))") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let decodedData = proStr?.data(using: .utf8) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if decodedData != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return decodedData 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 2 拼装 request 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let request = OSSMultipartUploadRequest() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // add by ak  set  contect type . doc https://help.aliyun.com/knowledge_detail/39522.html 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        request.contentType = fileURL.absoluteString.mimeType() // 媒体类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        request.uploadingFileURL = fileURL 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        request.bucketName = bucketName 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        request.objectKey = FileName 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 根据文件大小 设置 part size 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var fileSize: UInt64 = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        do { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let attr = try FileManager.default.attributesOfItem(atPath: fileURL.relativePath) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fileSize = attr[FileAttributeKey.size] as! UInt64 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } catch { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            debugPrint("取文件大小 Error: \(error)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if aliOssHander != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                DispatchQueue.main.async { [weak self] in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    self?.aliOssHander!(isMatarialUpload, materialType, fileURL.absoluteString.pathExtension, 260, FileName, contentMD5, width, height, 0, 0, nil, fileURL, nil, "文件已丢失") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        debugPrint("文件已经存在  \(fileURL) 文件大小 \(fileSize)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var partSize: Int = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // sdk中规定kClientMaximumOfChunks = 5000; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let defaultChunkSize: UInt64 = 1024 * 1024 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ceil(Float(fileSize / defaultChunkSize)) <= 1 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            partSize = 500 * 1024 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else if ceil(Float(fileSize / defaultChunkSize)) < 5000 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            partSize = Int(fileSize / UInt64(ceil(Float(fileSize / defaultChunkSize)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            partSize = Int(ceil(Float(fileSize / 5000))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        debugPrint("partSize \(partSize)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 除最后一片外 不能小于 102400(100kb) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        request.partSize = UInt(partSize) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        request.uploadId = ossUploadID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        request.uploadProgress = { [weak self] (bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) -> Void in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            debugPrint("当前上传uploadProgress线程:\(Thread.isMainThread) ") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self?.paraseSpeedAndRestTime(bytesSent: bytesSent, totalBytesSent: totalBytesSent, totalBytesExpectedToSend: totalBytesExpectedToSend) { uploadSpeed, resttime in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if self?.aliOssProgressHander != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    DispatchQueue.main.async { [weak self] in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        self?.aliOssProgressHander!(bytesSent, totalBytesSent, totalBytesExpectedToSend, resttime, uploadSpeed) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 多个界面都要处理上传进度 所以使用通知 ? 通知有回到主线? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // postNotification(name: cOSSUploadFileProgress,userInfo: ["bytesSent":bytesSent,"totalBytesSent":totalBytesSent,"totalBytesExpectedToSend":totalBytesExpectedToSend,"resttime":resttime]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 3,设置 config 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let conf = OSSClientConfiguration() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        conf.timeoutIntervalForRequest = 30 // 连接超时,默认15秒 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        conf.maxConcurrentRequestCount = 5 // 最大并发请求书,默认5个 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        conf.maxRetryCount = 3 // 失败后最大重试次数,默认2次 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 打开后台上传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        conf.enableBackgroundTransmitService = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        conf.backgroundSesseionIdentifier = getUniqueId(desc: "\(ossUploadID)\(fileURL.absoluteString)\(FileName)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 4,设置 clinet 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let client = OSSClient(endpoint: endpoints[0], credentialProvider: provider, clientConfiguration: conf) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if !isMatarialUpload { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            allTasks[FileName] = request 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 5,发起任务 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let task = client.multipartUpload(request) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        task.continue ({ [weak self] (osstask) -> Any? in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            debugPrint("当前上传线程:\(Thread.isMainThread) ") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if osstask.error == nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                debugPrint("上传成功") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // 文件URL的格式为:BucketName.Endpoint/ObjectName。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                debugPrint(" 上传成功注意使用时拼接域名 url == \(FileName)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                request.callbackParam = ["code": 1, "objectKey": FileName, "msg": "上传成功"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                DispatchQueue.main.async { [weak self] in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if self?.aliOssHander != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        self?.aliOssHander!(isMatarialUpload, materialType, fileURL.absoluteString.pathExtension, 1, FileName, contentMD5, width, height, 0, 0, nil, fileURL, nil, "上传成功") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // 如果在后台发送上传成功的本地通知 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if !isMatarialUpload { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    DispatchQueue.main.async { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if UIApplication.shared.applicationState == .background { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            sendUploadNotification(isSuccess: true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    postNotification(name: cUploadSuccessKey, userInfo: ["code": 1, "objectKey": FileName, "msg": "上传成功"]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // 上传完成 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var extParams:Dictionary<String,Any>? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if videoSource != nil && (videoSource?.count ?? 0) > 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    extParams = ["source":videoSource ?? ""] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                PQEventTrackViewModel.baseReportUpload(businessType: .bt_up_process, objectType: .ot_up_success, pageSource: nil,extParams: extParams, remindmsg: "上传相关") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                debugPrint("上传失败 \(osstask.error!)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                request.callbackParam = ["code": (osstask.error! as NSError).code, "objectKey": FileName, "msg": osstask.error?.localizedDescription ?? ""] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if self?.aliOssHander != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    DispatchQueue.main.async { [weak self] in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        self?.aliOssHander!(isMatarialUpload, materialType, fileURL.absoluteString.pathExtension, (osstask.error! as NSError).code, FileName, contentMD5, width, height, 0, 0, nil, fileURL, nil, osstask.error?.localizedDescription) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // 如果在后台发送上传失败的本地通知 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if !isMatarialUpload { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    DispatchQueue.main.async { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if UIApplication.shared.applicationState == .background { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            sendUploadNotification(isSuccess: false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // 上传失败 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var extParams:Dictionary<String,Any>? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if videoSource != nil && (videoSource?.count ?? 0) > 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    extParams = ["source":videoSource ?? ""] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                PQEventTrackViewModel.baseReportUpload(businessType: .bt_up_process, objectType: .ot_up_fail, pageSource: nil,extParams: extParams, remindmsg: "上传相关") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 开始上传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var extParams:Dictionary<String,Any>? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if videoSource != nil && (videoSource?.count ?? 0) > 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            extParams = ["source":videoSource ?? ""] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        PQEventTrackViewModel.baseReportUpload(businessType: .bt_up_process, objectType: .ot_up_start, pageSource: .sp_upload_coverSelect,extParams: extParams, remindmsg: "上传相关") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return .shared 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// add by ak  简单上传方式 本方法支持后台运行 设置支持后台时会把 DATA 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - Parameters: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - accessKeyId: <#accessKeyId description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - secretKeyId: <#secretKeyId description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - securityToken: <#securityToken description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - bucketName: <#bucketName description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - endpoint: oss host域名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - objectKey: oss 资源地址 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - fileURL: 文件本地地址 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - data: 文件数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - fileExtensions: 文件后缀名 mp4/mp3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - enableBackground: 是否支持后台下载 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - materialType: 素材类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - isMatarialUpload: 是否是素材上传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - contentMD5: 素材内容MD5值 isMatarialUpload = true时传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - width: 视频宽 isMatarialUpload = true时传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - height: 视频高 isMatarialUpload = true时传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - duration: 素材时长 isMatarialUpload = true时传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - frameNumber: gif素材帧数 isMatarialUpload = true时传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - netResourceUrl: 网络素材地址 isMatarialUpload = true时传 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - Returns: <#description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public  func putObjectAsync(accessKeyId: String, secretKeyId: String, securityToken: String, bucketName: String, endpoint: [String], objectKey: String, fileURL: URL?, data: Data?, fileExtensions: String, enableBackground: Bool, materialType: StickerType = .VIDEO, isMatarialUpload: Bool = false, contentMD5: String = "", width: CGFloat = 0, height: CGFloat = 0, duration: CGFloat, frameNumber: Int, netResourceUrl: String? = nil,videoSource:String? = nil) -> PQAliOssUtil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        #if DEBUG 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            OSSLog.enable() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        #endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        debugPrint("普通上传数据 参数 accessKeyId:\(accessKeyId) secretKeyId:\(secretKeyId) securityToken:\(securityToken) bucketName:\(bucketName) endpoint:\(endpoint) objectKey:\(objectKey) enableBackground:\(enableBackground) fileURL : \(fileURL!)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if endpoint.count <= 0 || (endpoint.first?.count ?? 0) <= 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            debugPrint("endpoints 为空") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return .shared 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let provider = OSSStsTokenCredentialProvider(accessKeyId: accessKeyId, secretKeyId: secretKeyId, securityToken: securityToken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//            let configuration = OSSClientConfiguration() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//            if enableBackground { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//                configuration.enableBackgroundTransmitService = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//                configuration.backgroundSesseionIdentifier = objectKey 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//            configuration.timeoutIntervalForRequest = 60 // 连接超时,默认15秒 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//            configuration.maxConcurrentRequestCount = 20 // 最大并发请求书,默认5个 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//            configuration.maxRetryCount = 3 // 失败后最大重试次数,默认2次 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        startClient(accessKeyId: accessKeyId, secretKeyId: secretKeyId, securityToken: securityToken, endpoint: endpoint.first ?? "") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let request = OSSPutObjectRequest() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if fileURL != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            request.uploadingFileURL = fileURL! 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            request.contentType = fileURL!.absoluteString.mimeType() // 媒体类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else if data != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            request.uploadingData = data! 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            request.contentType = materialType.mimeType() // 媒体类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        request.bucketName = bucketName 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        request.objectKey = objectKey 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // request.contentMd5 = contentMD5 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        request.uploadProgress = { (bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) -> Void in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var resttime: Int64 = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if self.oldTime == 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                self.oldTime = Int(Date().timeIntervalSince1970) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let nowTime = Int(Date().timeIntervalSince1970) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let pertime = Int(nowTime - self.oldTime) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if pertime != 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var speed = totalBytesSent / Int64(pertime) // 单位b/s 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if speed != 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    resttime = ((totalBytesExpectedToSend - totalBytesSent) / speed) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    var units = "b/s" // 单位名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if speed / 1024 > 1 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        speed = speed / 1024 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        units = "k/s" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if speed / 1024 > 1 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        speed = speed / 1024 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        units = "M/s" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    debugPrint("上传速度: \(speed)\(units)   还剩时间 \(resttime)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 多个界面都要处理上传进度 所以使用通知 ? 通知有回到主线? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            postNotification(name: cOSSUploadFileProgress, userInfo: ["bytesSent": bytesSent, "totalBytesSent": totalBytesSent, "totalBytesExpectedToSend": totalBytesExpectedToSend, "resttime": resttime]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let task = client?.putObject(request) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if fileURL?.absoluteString.contains("_noise_") ?? false { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            task?.continue ({ [weak self] (osstask) -> Any? in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                debugPrint("当前上传线程:\(Thread.isMainThread) ") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if osstask.error == nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    debugPrint("上传成功") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // 文件URL的格式为:BucketName.Endpoint/ObjectName。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    debugPrint(" 上传成功注意使用时拼接域名 url == \(objectKey)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    request.callbackParam = ["code": 1, "objectKey": objectKey, "msg": "上传成功"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    DispatchQueue.main.async { [weak self] in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if self?.aliOssHander != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            self?.aliOssHander!(isMatarialUpload, materialType, fileExtensions, 1, objectKey, contentMD5, width, height, duration, frameNumber, netResourceUrl, fileURL, data, "上传成功") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // 如果在后台发送上传成功的本地通知 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if !isMatarialUpload { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        DispatchQueue.main.async { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            if UIApplication.shared.applicationState == .background { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                sendUploadNotification(isSuccess: true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        postNotification(name: cUploadSuccessKey, userInfo: ["code": 1, "objectKey": objectKey, "msg": "上传成功"]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // 上传完成 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    var extParams:Dictionary<String,Any>? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if videoSource != nil && (videoSource?.count ?? 0) > 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        extParams = ["source":videoSource ?? ""] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // 上传完成 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    PQEventTrackViewModel.baseReportUpload(businessType: .bt_up_process, objectType: .ot_up_success, pageSource: nil,extParams: extParams, remindmsg: "上传相关") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    debugPrint("上传失败 \(osstask.error!)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    request.callbackParam = ["code": (osstask.error! as NSError).code, "objectKey": objectKey, "msg": osstask.error?.localizedDescription ?? ""] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if self?.aliOssHander != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        DispatchQueue.main.async { [weak self] in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            self?.aliOssHander!(isMatarialUpload, materialType, fileExtensions, (osstask.error! as NSError).code, objectKey, contentMD5, width, height, duration, frameNumber, netResourceUrl, fileURL, data, osstask.error?.localizedDescription) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // 如果在后台发送上传失败的本地通知 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if !isMatarialUpload { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        DispatchQueue.main.async { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            if UIApplication.shared.applicationState == .background { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                sendUploadNotification(isSuccess: false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // 上传失败 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    PQEventTrackViewModel.baseReportUpload(businessType: .bt_up_process, objectType: .ot_up_fail, pageSource: nil, remindmsg: "上传相关") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }).waitUntilFinished() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            task?.continue ({ [weak self] (osstask) -> Any? in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                debugPrint("当前上传线程:\(Thread.isMainThread) ") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if osstask.error == nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    debugPrint("上传成功") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // 文件URL的格式为:BucketName.Endpoint/ObjectName。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    debugPrint(" 上传成功注意使用时拼接域名 url == \(objectKey)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    request.callbackParam = ["code": 1, "objectKey": objectKey, "msg": "上传成功"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    DispatchQueue.main.async { [weak self] in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if self?.aliOssHander != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            self?.aliOssHander!(isMatarialUpload, materialType, fileExtensions, 1, objectKey, contentMD5, width, height, duration, frameNumber, netResourceUrl, fileURL, data, "上传成功") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // 如果在后台发送上传成功的本地通知 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if !isMatarialUpload { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        DispatchQueue.main.async { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            if UIApplication.shared.applicationState == .background { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                sendUploadNotification(isSuccess: true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        postNotification(name: cUploadSuccessKey, userInfo: ["code": 1, "objectKey": objectKey, "msg": "上传成功"]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // 上传完成 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    PQEventTrackViewModel.baseReportUpload(businessType: .bt_up_process, objectType: .ot_up_success, pageSource: nil, remindmsg: "上传相关") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    debugPrint("上传失败 \(osstask.error!)") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    request.callbackParam = ["code": (osstask.error! as NSError).code, "objectKey": objectKey, "msg": osstask.error?.localizedDescription ?? ""] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if self?.aliOssHander != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        DispatchQueue.main.async { [weak self] in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            self?.aliOssHander!(isMatarialUpload, materialType, fileExtensions, (osstask.error! as NSError).code, objectKey, contentMD5, width, height, duration, frameNumber, netResourceUrl, fileURL, data, osstask.error?.localizedDescription) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // 如果在后台发送上传失败的本地通知 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if !isMatarialUpload { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        DispatchQueue.main.async { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            if UIApplication.shared.applicationState == .background { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                sendUploadNotification(isSuccess: false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // 上传失败 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    PQEventTrackViewModel.baseReportUpload(businessType: .bt_up_process, objectType: .ot_up_fail, pageSource: nil, remindmsg: "上传相关") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return .shared 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// 取消某个任务 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - Parameter objectKey: 任务唯一标识 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public  func putObjectCancel(objectKey: String) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for key in allTasks.keys { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if key == objectKey { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                allTasks[key]!.cancel() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                allTasks.removeValue(forKey: key) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// 解析上传速度及剩余时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - Parameters: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - bytesSent: <#bytesSent description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - totalBytesSent: <#totalBytesSent description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - totalBytesExpectedToSend: <#totalBytesExpectedToSend description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ///   - complateHandle: <#complateHandle description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - Returns: <#description#> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public  func paraseSpeedAndRestTime(bytesSent _: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64, complateHandle: (_ uploadSpeed: String, _ resttime: Int64) -> Void) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let newInterfaceBytes = PQBridgeObject.getInterfaceBytes() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var interfaceBytes = abs(newInterfaceBytes - lastInterfaceBytes) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if interfaceBytes <= 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            interfaceBytes = 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        lastInterfaceBytes = newInterfaceBytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let resttime = (totalBytesExpectedToSend - totalBytesSent) / interfaceBytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        debugPrint("interfaceBytes = \(interfaceBytes),totalBytesExpectedToSend = \(totalBytesExpectedToSend),totalBytesSent = \(totalBytesSent),") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        complateHandle("\(PQBridgeObject.formatNetWork(interfaceBytes))", resttime) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    override private init() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        super.init() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public override func copy() -> Any { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return self 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public override func mutableCopy() -> Any { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return self 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |