BaseWebViewUIViewController.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. //
  2. // BaseWebViewUIViewController.swift
  3. // O2Platform
  4. //
  5. // Created by 刘振兴 on 2016/10/11.
  6. // Copyright © 2016年 zoneland. All rights reserved.
  7. //
  8. import UIKit
  9. import WebKit
  10. import CocoaLumberjack
  11. import QuickLook
  12. protocol BaseWebViewUIViewControllerJSDelegate {
  13. func closeUIViewWindow()
  14. func actionBarLoaded(show: Bool)
  15. }
  16. protocol O2WKScriptMessageHandlerImplement {
  17. func userController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
  18. }
  19. class BaseWebViewUIViewController: O2BaseForRotateUIViewController {
  20. var webView:WKWebView!
  21. var delegate: BaseWebViewUIViewControllerJSDelegate?
  22. var o2WKScriptHandlers: [String : O2WKScriptMessageHandlerImplement] = [:]
  23. //定位用
  24. var locationCallBack: (String?) -> Void = {(result) in }
  25. private var locService: BMKLocationManager?
  26. private var searchAddress: BMKGeoCodeSearch?
  27. //继承的子类如果要添加MessageHandler必须在theWebView方法前使用
  28. func addScriptMessageHandler(key: String, handler: O2WKScriptMessageHandlerImplement) {
  29. o2WKScriptHandlers[key] = handler
  30. }
  31. open func theWebView(){
  32. let baseJsHandler = O2BaseJsMessageHandler(viewController: self)
  33. // bbs 回复
  34. addScriptMessageHandler(key: "ReplyAction", handler: baseJsHandler)
  35. // protal已经存在ActionBar
  36. addScriptMessageHandler(key: "actionBarLoaded", handler: baseJsHandler)
  37. // 打开工作 {"work":"", "workCompleted":"", "title":""}
  38. addScriptMessageHandler(key: "openO2Work", handler: baseJsHandler)
  39. // 4个分类 task taskCompleted read readCompleted
  40. addScriptMessageHandler(key: "openO2WorkSpace", handler: baseJsHandler)
  41. // 打开cms appId
  42. addScriptMessageHandler(key: "openO2CmsApplication", handler: baseJsHandler)
  43. // 打开cms docId docTitle
  44. addScriptMessageHandler(key: "openO2CmsDocument", handler: baseJsHandler)
  45. // 打开meeting
  46. addScriptMessageHandler(key: "openO2Meeting", handler: baseJsHandler)
  47. // 打开 calendar
  48. addScriptMessageHandler(key: "openO2Calendar", handler: baseJsHandler)
  49. // 打开扫一扫
  50. addScriptMessageHandler(key: "openScan", handler: baseJsHandler)
  51. addScriptMessageHandler(key: "openO2Alert", handler: baseJsHandler)
  52. // 打开钉钉
  53. addScriptMessageHandler(key: "openDingtalk", handler: baseJsHandler)
  54. // 关闭当前UIViewController
  55. addScriptMessageHandler(key:"closeNativeWindow", handler: baseJsHandler)
  56. // 表单的图片控件
  57. addScriptMessageHandler(key: "uploadImage2FileStorage", handler: baseJsHandler)
  58. // 打印日志
  59. addScriptMessageHandler(key: "o2mLog", handler: baseJsHandler)
  60. //o2m.notification
  61. let o2Notification = O2JsApiNotification(viewController: self)
  62. addScriptMessageHandler(key: "o2mNotification", handler: o2Notification)
  63. //o2m.util
  64. let o2Util = O2JsApiUtil(viewController: self)
  65. addScriptMessageHandler(key: "o2mUtil", handler: o2Util)
  66. // o2m.biz
  67. let biz = O2JsApiBizUtil(viewController: self)
  68. addScriptMessageHandler(key: "o2mBiz", handler: biz)
  69. setupWebView()
  70. }
  71. public func setupWebView() {
  72. let userContentController = WKUserContentController()
  73. //cookie脚本
  74. if let cookies = HTTPCookieStorage.shared.cookies {
  75. let script = getJSCookiesString(cookies: cookies)
  76. let cookieScript = WKUserScript(source: script, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: false)
  77. userContentController.addUserScript(cookieScript)
  78. }
  79. // console.log 打印到ios log debug用
  80. let consoleLog = "console.log = (function(oriLogFunc){return function(str){window.webkit.messageHandlers.o2mLog.postMessage(str);oriLogFunc.call(console,str);} })(console.log);"
  81. let logScript = WKUserScript(source: consoleLog, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: false)
  82. userContentController.addUserScript(logScript)
  83. let webViewConfig = WKWebViewConfiguration()
  84. webViewConfig.userContentController = userContentController
  85. //加入js-app message handler
  86. for item in o2WKScriptHandlers {
  87. userContentController.add(self, name: item.key)
  88. }
  89. self.webView = WKWebView(frame: self.view.frame, configuration: webViewConfig)
  90. /// 设置 userAgent
  91. self.webView.evaluateJavaScript("navigator.userAgent") { (result, err) in
  92. if let ua = result as? String {
  93. self.webView.customUserAgent = "\(ua) o2oa"
  94. }
  95. }
  96. }
  97. ///Generates script to create given cookies
  98. public func getJSCookiesString(cookies: [HTTPCookie]) -> String {
  99. var result = ""
  100. let dateFormatter = DateFormatter()
  101. dateFormatter.timeZone = NSTimeZone(abbreviation: "UTC") as TimeZone?
  102. dateFormatter.dateFormat = "EEE, d MMM yyyy HH:mm:ss zzz"
  103. for cookie in cookies {
  104. result += "document.cookie='\(cookie.name)=\(cookie.value); domain=\(cookie.domain); path=\(cookie.path); "
  105. if let date = cookie.expiresDate {
  106. result += "expires=\(dateFormatter.string(from: date)); "
  107. }
  108. if (cookie.isSecure) {
  109. result += "secure; "
  110. }
  111. result += "'; "
  112. }
  113. return result
  114. }
  115. // MARK: - 文件预览
  116. //预览文件
  117. private lazy var previewVC: CloudFilePreviewController = {
  118. return CloudFilePreviewController()
  119. }()
  120. // 文件预览
  121. func previewDoc(path: String) {
  122. let currentURL = NSURL(fileURLWithPath: path)
  123. if QLPreviewController.canPreview(currentURL) {
  124. self.previewVC.currentFileURLS.removeAll()
  125. self.previewVC.currentFileURLS.append(currentURL)
  126. self.previewVC.reloadData()
  127. self.pushVC(self.previewVC)
  128. } else {
  129. self.showError(title: "当前文件类型不支持预览!")
  130. }
  131. }
  132. // MARK: - 旋转屏幕
  133. // 此参数由外部传入,并且在要在构造控制器时传入
  134. fileprivate var _isLandscape = false
  135. override var _prefersStatusBarHidden_: Bool? {
  136. return false
  137. }
  138. override var _supportedInterfaceOrientations_: UIInterfaceOrientationMask? {
  139. return _isLandscape ? .landscapeRight: .portrait
  140. }
  141. override var _preferredInterfaceOrientationForPresentation_: UIInterfaceOrientation? {
  142. return _isLandscape ? .landscapeRight: .portrait
  143. }
  144. override var isForbidInteractivePopGesture: Bool {
  145. return _isLandscape
  146. }
  147. // MARK: - 控制旋转
  148. fileprivate func updateOrientationIfNeeded(_ force: Bool = false) {
  149. if _isLandscape {
  150. toLandscapeOrientation(force)
  151. } else {
  152. toPortraitOrientation(force)
  153. }
  154. }
  155. fileprivate func toLandscapeOrientation(_ force: Bool = false) {
  156. guard force || !_isLandscape else {
  157. return
  158. }
  159. UIRotateUtils.shared.rotateToLandscape()
  160. }
  161. fileprivate func toPortraitOrientation(_ force: Bool = false) {
  162. guard force || _isLandscape else {
  163. return
  164. }
  165. UIRotateUtils.shared.rotateToPortrait()
  166. }
  167. // 点击 “旋转” 按钮
  168. @objc func onChangeOrientationBtnTapped(_ any: Any?) {
  169. DDLogDebug("旋转屏幕 \(_isLandscape)")
  170. // 核心控制
  171. _isLandscape = !_isLandscape
  172. if _isLandscape {
  173. toLandscapeOrientation(true)
  174. } else {
  175. toPortraitOrientation(true)
  176. }
  177. }
  178. }
  179. extension BaseWebViewUIViewController: WKScriptMessageHandler {
  180. public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
  181. let name = message.name
  182. if let handler = o2WKScriptHandlers[name] {
  183. handler.userController(userContentController, didReceive: message)
  184. }else {
  185. let err = "没有找到对应的key,key:\(name)"
  186. self.showError(title: err)
  187. }
  188. }
  189. }
  190. extension BaseWebViewUIViewController: BMKLocationManagerDelegate, BMKGeoCodeSearchDelegate {
  191. public func startLocation() {
  192. //开始定位
  193. locService = BMKLocationManager()
  194. if locService == nil {
  195. locService?.desiredAccuracy = kCLLocationAccuracyBest
  196. //设置返回位置的坐标系类型
  197. locService?.coordinateType = .BMK09LL
  198. //设置距离过滤参数
  199. locService?.distanceFilter = kCLDistanceFilterNone;
  200. //设置预期精度参数
  201. locService?.desiredAccuracy = kCLLocationAccuracyBest;
  202. //设置应用位置类型
  203. locService?.activityType = .automotiveNavigation
  204. //设置是否自动停止位置更新
  205. locService?.pausesLocationUpdatesAutomatically = false
  206. //定位返回geo地址信息
  207. locService?.locatingWithReGeocode = true
  208. //后台定位
  209. locService?.allowsBackgroundLocationUpdates = true
  210. }
  211. if searchAddress == nil {
  212. searchAddress = BMKGeoCodeSearch()
  213. }
  214. searchAddress?.delegate = self
  215. locService?.delegate = self
  216. locService?.startUpdatingLocation()
  217. }
  218. public func stopLocation() {
  219. locService?.stopUpdatingLocation()
  220. locService?.delegate = nil
  221. searchAddress?.delegate = nil
  222. }
  223. public func bmkLocationManager(_ manager: BMKLocationManager, didUpdate location: BMKLocation?, orError error: Error?) {
  224. if let loc = location?.location {
  225. DDLogDebug("当前位置,\(loc.coordinate.latitude),\(loc.coordinate.longitude)")
  226. //根据经纬度搜索到地址
  227. let re = BMKReverseGeoCodeSearchOption()
  228. re.location = CLLocationCoordinate2D(latitude: loc.coordinate.latitude, longitude: loc.coordinate.longitude)
  229. let _ = searchAddress?.reverseGeoCode(re)
  230. } else {
  231. DDLogError("没有获取到定位信息!!!!!")
  232. }
  233. }
  234. public func bmkLocationManager(_ manager: BMKLocationManager, didFailWithError error: Error?) {
  235. DDLogError("定位错误:\(String(describing: error?.localizedDescription))")
  236. }
  237. public func onGetReverseGeoCodeResult(_ searcher: BMKGeoCodeSearch?, result: BMKReverseGeoCodeSearchResult?, errorCode error: BMKSearchErrorCode) {
  238. //发送定位的实时位置及名称信息
  239. if let location = result?.location {
  240. var r = O2DeviceLocationResult()
  241. r.latitude = location.latitude
  242. r.longitude = location.longitude
  243. r.address = result?.address ?? "没有获取到地址!"
  244. locationCallBack(r.toJSONString())
  245. }else {
  246. var r = O2DeviceLocationResult()
  247. r.address = "没有获取到地址!"
  248. locationCallBack(r.toJSONString())
  249. DDLogError("搜索地址失败, \(error)")
  250. }
  251. //结束定位
  252. self.stopLocation()
  253. }
  254. public func onGetGeoCodeResult(_ searcher: BMKGeoCodeSearch!, result: BMKGeoCodeSearchResult!, errorCode error: BMKSearchErrorCode) {
  255. if Int(error.rawValue) == 0 {
  256. DDLogDebug("result \(String(describing: result))")
  257. } else {
  258. DDLogDebug("result error errorCode = \(Int(error.rawValue))")
  259. }
  260. }
  261. }