BaseTaskWebViewController.swift 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. //
  2. // BaseTaskWebViewController.swift
  3. // O2Platform
  4. //
  5. // Created by 刘振兴 on 2017/3/13.
  6. // Copyright © 2017年 zoneland. All rights reserved.
  7. //
  8. import UIKit
  9. import WebKit
  10. import Alamofire
  11. import AlamofireObjectMapper
  12. import SwiftyJSON
  13. import QuickLook
  14. import ObjectMapper
  15. import BSImagePicker
  16. import Photos
  17. import CocoaLumberjack
  18. enum TaskAttachmentOperationType {
  19. case upload(String)
  20. case download(String,String)
  21. case replace(String)
  22. }
  23. protocol O2WorkFormLoadedDelegate {
  24. func workFormLoaded()
  25. }
  26. class BaseTaskWebViewController: UIViewController {
  27. var qlController = TaskAttachmentPreviewController()
  28. //是否是已办
  29. open var isWorkCompeleted:Bool = false
  30. open var workId:String?
  31. var loadedDelegate: O2WorkFormLoadedDelegate?
  32. var webView:WKWebView!
  33. override open func viewDidLoad() {
  34. super.viewDidLoad()
  35. qlController.dataSource = qlController
  36. qlController.delegate = qlController
  37. // Do any additional setup after loading the view.
  38. }
  39. deinit {
  40. }
  41. override open func didReceiveMemoryWarning() {
  42. super.didReceiveMemoryWarning()
  43. // Dispose of any resources that can be recreated.
  44. }
  45. open func theWebView(){
  46. setupWebView()
  47. }
  48. public func setupWebView() {
  49. let userContentController = WKUserContentController()
  50. //cookie脚本
  51. if let cookies = HTTPCookieStorage.shared.cookies {
  52. let script = getJSCookiesString(cookies: cookies)
  53. let cookieScript = WKUserScript(source: script, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: false)
  54. userContentController.addUserScript(cookieScript)
  55. }
  56. let webViewConfig = WKWebViewConfiguration()
  57. webViewConfig.userContentController = userContentController
  58. //加入js-app message appFormLoaded
  59. userContentController.add(self, name: "appFormLoaded")
  60. userContentController.add(self, name: "uploadAttachment")
  61. userContentController.add(self, name: "downloadAttachment")
  62. userContentController.add(self, name: "replaceAttachment")
  63. self.webView = WKWebView(frame: self.view.frame, configuration: webViewConfig)
  64. }
  65. //上传附件
  66. open func uploadAttachment(_ site:String){
  67. //选择附件上传
  68. let updloadURL = AppDelegate.o2Collect.generateURLWithAppContextKey(TaskContext.taskContextKey, query: TaskContext.todoTaskUploadAttachmentQuery, parameter: ["##workId##":workId as AnyObject])
  69. self.uploadAttachment(site, uploadURL: updloadURL!)
  70. //回调layout.appForm.uploadedAttachment(site, attachmentId)
  71. }
  72. private func uploadAttachment(_ site:String,uploadURL url:String){
  73. let vc = FileBSImagePickerViewController()
  74. bs_presentImagePickerController(vc, animated: true,
  75. select: { (asset: PHAsset) -> Void in
  76. // User selected an asset.
  77. // Do something with it, start upload perhaps?
  78. }, deselect: { (asset: PHAsset) -> Void in
  79. // User deselected an assets.
  80. // Do something, cancel upload?
  81. }, cancel: { (assets: [PHAsset]) -> Void in
  82. // User cancelled. And this where the assets currently selected.
  83. }, finish: { (assets: [PHAsset]) -> Void in
  84. for asset in assets {
  85. switch asset.mediaType {
  86. case .audio:
  87. DDLogDebug("Audio")
  88. case .image:
  89. let options = PHImageRequestOptions()
  90. options.isSynchronous = true
  91. options.deliveryMode = .fastFormat
  92. options.resizeMode = .none
  93. PHImageManager.default().requestImageData(for: asset, options: options, resultHandler: { (imageData, result, imageOrientation, dict) in
  94. //DDLogDebug("result = \(result) imageOrientation = \(imageOrientation) \(dict)")
  95. let fileURL = dict?["PHImageFileURLKey"] as! URL
  96. DispatchQueue.main.async {
  97. ProgressHUD.show("上传中...", interaction: false)
  98. }
  99. DispatchQueue.global(qos: .userInitiated).async {
  100. Alamofire.upload(multipartFormData: { (mData) in
  101. //mData.append(fileURL, withName: "file")
  102. mData.append(imageData!, withName: "file", fileName: fileURL.lastPathComponent, mimeType: "application/octet-stream")
  103. let siteData = site.data(using: String.Encoding.utf8, allowLossyConversion: false)
  104. mData.append(siteData!, withName: "site")
  105. }, to: url, encodingCompletion: { (encodingResult) in
  106. switch encodingResult {
  107. case .success(let upload, _, _):
  108. debugPrint(upload)
  109. upload.responseJSON {
  110. respJSON in
  111. switch respJSON.result {
  112. case .success(let val):
  113. let attachId = JSON(val)["data"]["id"].string!
  114. DispatchQueue.main.async {
  115. //ProgressHUD.showSuccess("上传成功")
  116. let callJS = "layout.appForm.uploadedAttachment(\"\(site)\", \"\(attachId)\")"
  117. self.webView.evaluateJavaScript(callJS, completionHandler: { (result, err) in
  118. ProgressHUD.showSuccess("上传成功")
  119. })
  120. }
  121. case .failure(let err):
  122. DispatchQueue.main.async {
  123. DDLogError(err.localizedDescription)
  124. ProgressHUD.showError("上传失败")
  125. }
  126. break
  127. }
  128. }
  129. case .failure(let errType):
  130. DispatchQueue.main.async {
  131. DDLogError(errType.localizedDescription)
  132. ProgressHUD.showError("上传失败")
  133. }
  134. }
  135. })
  136. }
  137. })
  138. case .video:
  139. let options = PHVideoRequestOptions()
  140. options.deliveryMode = .fastFormat
  141. options.isNetworkAccessAllowed = true
  142. options.progressHandler = { (progress,err, stop,dict) in
  143. DDLogDebug("progress = \(progress) dict = \(dict)")
  144. }
  145. PHImageManager.default().requestAVAsset(forVideo: asset, options: options, resultHandler: { (avAsset, avAudioMx, dict) in
  146. })
  147. case .unknown:
  148. DDLogDebug("Unknown")
  149. }
  150. }
  151. }, completion: nil)
  152. }
  153. //下载预览附件
  154. open func downloadAttachment(_ attachmentId:String){
  155. //生成两个URL,一个获取附件信息,一个链接正式下载
  156. var infoURL:String?,downURL:String?
  157. if isWorkCompeleted {
  158. infoURL = AppDelegate.o2Collect.generateURLWithAppContextKey(TaskedContext.taskedContextKey, query: TaskedContext.taskedGetAttachmentInfoQuery, parameter: ["##attachmentId##":attachmentId as AnyObject,"##workcompletedId##":workId as AnyObject])
  159. downURL = AppDelegate.o2Collect.generateURLWithAppContextKey(TaskedContext.taskedContextKey, query: TaskedContext.taskedGetAttachmentQuery, parameter:["##attachmentId##":attachmentId as AnyObject,"##workcompletedId##":workId as AnyObject])
  160. }else{
  161. infoURL = AppDelegate.o2Collect.generateURLWithAppContextKey(TaskContext.taskContextKey, query: TaskContext.todoTaskGetAttachmentInfoQuery, parameter: ["##attachmentId##":attachmentId as AnyObject,"##workId##":workId as AnyObject])
  162. downURL = AppDelegate.o2Collect.generateURLWithAppContextKey(TaskContext.taskContextKey, query: TaskContext.todoTaskGetAttachmentQuery, parameter:["##attachmentId##":attachmentId as AnyObject,"##workId##":workId as AnyObject])
  163. }
  164. self.showAttachViewInController(infoURL!, downURL!)
  165. }
  166. //替换附件
  167. open func replaceAttachment(_ attachmentId:String, _ site:String){
  168. //替换结束后回调js名称
  169. let replaceURL = AppDelegate.o2Collect.generateURLWithAppContextKey(TaskContext.taskContextKey, query: TaskContext.todoTaskUpReplaceAttachmentQuery, parameter: ["##attachmentId##":attachmentId as AnyObject,"##workId##":workId as AnyObject])!
  170. self.replaceAttachment(site, attachmentId, replaceURL: replaceURL)
  171. //layout.appForm.replacedAttachment(site , attachmentId)
  172. }
  173. private func replaceAttachment(_ site:String,_ attachmentId:String,replaceURL url:String){
  174. let vc = FileBSImagePickerViewController()
  175. bs_presentImagePickerController(vc, animated: true,
  176. select: { (asset: PHAsset) -> Void in
  177. // User selected an asset.
  178. // Do something with it, start upload perhaps?
  179. }, deselect: { (asset: PHAsset) -> Void in
  180. // User deselected an assets.
  181. // Do something, cancel upload?
  182. }, cancel: { (assets: [PHAsset]) -> Void in
  183. // User cancelled. And this where the assets currently selected.
  184. }, finish: { (assets: [PHAsset]) -> Void in
  185. for asset in assets {
  186. switch asset.mediaType {
  187. case .audio:
  188. DDLogDebug("Audio")
  189. case .image:
  190. let options = PHImageRequestOptions()
  191. options.isSynchronous = true
  192. options.deliveryMode = .fastFormat
  193. options.resizeMode = .none
  194. PHImageManager.default().requestImageData(for: asset, options: options, resultHandler: { (imageData, result, imageOrientation, dict) in
  195. //DDLogDebug("result = \(result) imageOrientation = \(imageOrientation) \(dict)")
  196. let fileURL = dict?["PHImageFileURLKey"] as! URL
  197. DispatchQueue.main.async {
  198. ProgressHUD.show("上传中...", interaction: false)
  199. }
  200. DispatchQueue.global(qos: .userInitiated).async {
  201. Alamofire.upload(multipartFormData: { (mData) in
  202. //mData.append(fileURL, withName: "file")
  203. mData.append(imageData!, withName: "file", fileName: fileURL.lastPathComponent, mimeType: "application/octet-stream")
  204. let siteData = site.data(using: String.Encoding.utf8, allowLossyConversion: false)
  205. mData.append(siteData!, withName: "site")
  206. }, usingThreshold: SessionManager.multipartFormDataEncodingMemoryThreshold, to: url, method: .put, headers: nil, encodingCompletion: { (encodingResult) in
  207. switch encodingResult {
  208. case .success(let upload, _, _):
  209. debugPrint(upload)
  210. upload.responseJSON {
  211. respJSON in
  212. switch respJSON.result {
  213. case .success( _):
  214. //let attachId = JSON(val)["data"]["id"].string!
  215. DispatchQueue.main.async {
  216. //ProgressHUD.showSuccess("上传成功")
  217. let callJS = "layout.appForm.replacedAttachment(\"\(site)\", \"\(attachmentId)\")"
  218. self.webView.evaluateJavaScript(callJS, completionHandler: { (result, err) in
  219. ProgressHUD.showSuccess("替换成功")
  220. })
  221. }
  222. case .failure(let err):
  223. DispatchQueue.main.async {
  224. DDLogError(err.localizedDescription)
  225. ProgressHUD.showError("替换失败")
  226. }
  227. break
  228. }
  229. }
  230. case .failure(let errType):
  231. DispatchQueue.main.async {
  232. DDLogError(errType.localizedDescription)
  233. ProgressHUD.showError("替换失败")
  234. }
  235. }
  236. })
  237. }
  238. })
  239. case .video:
  240. let options = PHVideoRequestOptions()
  241. options.deliveryMode = .fastFormat
  242. options.isNetworkAccessAllowed = true
  243. options.progressHandler = { (progress,err, stop,dict) in
  244. DDLogDebug("progress = \(progress) dict = \(String(describing: dict))")
  245. }
  246. PHImageManager.default().requestAVAsset(forVideo: asset, options: options, resultHandler: { (avAsset, avAudioMx, dict) in
  247. })
  248. case .unknown:
  249. DDLogDebug("Unknown")
  250. }
  251. }
  252. }, completion: nil)
  253. }
  254. fileprivate func showAttachViewInController(_ infoURL:String,_ downURL:String){
  255. ProgressHUD.show("下载中...", interaction: false)
  256. Alamofire.request(infoURL).responseJSON { (response) in
  257. switch response.result {
  258. case .success(let val):
  259. //DDLogDebug(JSON(val).description)
  260. let info = Mapper<O2TaskAttachmentInfo>().map(JSONString: JSON(val).description)
  261. //执行下载
  262. let destination: DownloadRequest.DownloadFileDestination = { _, _ in
  263. let documentsURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
  264. let fileURL = documentsURL.appendingPathComponent((info?.data?.name)!)
  265. return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
  266. }
  267. Alamofire.download(downURL, to: destination).response(completionHandler: { (response) in
  268. if response.error == nil , let fileurl = response.destinationURL?.path {
  269. //打开文件
  270. ProgressHUD.dismiss()
  271. self.previewAttachment(fileurl)
  272. }else{
  273. DispatchQueue.main.async {
  274. ProgressHUD.showError("预览文件出错")
  275. }
  276. }
  277. })
  278. break
  279. case .failure(let err):
  280. DDLogError(err.localizedDescription)
  281. DispatchQueue.main.async {
  282. ProgressHUD.showError("预览文件出错")
  283. }
  284. break
  285. }
  286. }
  287. }
  288. private func previewAttachment(_ url:String){
  289. let currentURL = NSURL(fileURLWithPath: url)
  290. if QLPreviewController.canPreview(currentURL) {
  291. qlController.currentFileURLS.removeAll(keepingCapacity: true)
  292. qlController.currentFileURLS.append(currentURL)
  293. qlController.reloadData()
  294. if #available(iOS 10, *) {
  295. let navVC = ZLNormalNavViewController(rootViewController: qlController)
  296. qlController.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "关闭", style: .plain, target: qlController, action: #selector(qlController.qlCloseWindow))
  297. self.presentVC(navVC)
  298. }else{
  299. //if #available(iOS 9, *){
  300. self.pushVC(qlController)
  301. //}
  302. }
  303. }else{
  304. ProgressHUD.showError("此文件无法预览,请在PC端查看")
  305. }
  306. }
  307. private func downloadFile(_ attachmentId:String,_ completed:@escaping (_ localURLForFile:String) -> Void){
  308. }
  309. ///Generates script to create given cookies
  310. public func getJSCookiesString(cookies: [HTTPCookie]) -> String {
  311. var result = ""
  312. let dateFormatter = DateFormatter()
  313. dateFormatter.timeZone = NSTimeZone(abbreviation: "UTC") as TimeZone!
  314. dateFormatter.dateFormat = "EEE, d MMM yyyy HH:mm:ss zzz"
  315. for cookie in cookies {
  316. result += "document.cookie='\(cookie.name)=\(cookie.value); domain=\(cookie.domain); path=\(cookie.path); "
  317. if let date = cookie.expiresDate {
  318. result += "expires=\(dateFormatter.string(from: date)); "
  319. }
  320. if (cookie.isSecure) {
  321. result += "secure; "
  322. }
  323. result += "'; "
  324. }
  325. return result
  326. }
  327. }
  328. extension BaseTaskWebViewController:WKScriptMessageHandler{
  329. func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
  330. let name = message.name
  331. switch name {
  332. case "appFormLoaded":
  333. self.loadedDelegate?.workFormLoaded()
  334. break
  335. case "uploadAttachment":
  336. ZonePermissions.requestImagePickerAuthorization(callback: { (zoneStatus) in
  337. if zoneStatus == ZoneAuthorizationStatus.zAuthorizationStatusAuthorized {
  338. let site = (message.body as! NSDictionary)["site"]
  339. self.uploadAttachment(site as! String)
  340. }else {
  341. //显示
  342. let alertController = UIAlertController(title: "上传提示", message: "请设置照片允许访问权限", preferredStyle: UIAlertController.Style.alert)
  343. alertController.addAction(UIAlertAction(title: "去设置", style: .destructive, handler: { (action) in
  344. let setURL = URL(string: UIApplication.openSettingsURLString)!
  345. if UIApplication.shared.canOpenURL(setURL) {
  346. UIApplication.shared.openURL(setURL)
  347. }
  348. }))
  349. alertController.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (action) in
  350. }))
  351. self.presentVC(alertController)
  352. }
  353. })
  354. break
  355. case "downloadAttachment":
  356. let attachmentId = (message.body as! NSDictionary)["id"]
  357. self.downloadAttachment(attachmentId as! String)
  358. break
  359. case "replaceAttachment":
  360. let attachmentId = (message.body as! NSDictionary)["id"] as! String
  361. let site = (message.body as! NSDictionary)["site"] as? String
  362. self.replaceAttachment(attachmentId, site ?? "")
  363. break
  364. default: break
  365. }
  366. }
  367. }