MainController.swift 72 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720
  1. //
  2. // MainController.swift
  3. //
  4. // Created by 方楚豪 on 2022/05/13.
  5. //
  6. import UIKit
  7. import WebKit
  8. import Foundation
  9. import Toast_Swift
  10. import ImSDK_Plus
  11. import QuickLook
  12. import MMKV
  13. import SwiftEntryKit
  14. import NotificationBannerSwift
  15. import Alamofire
  16. import swiftScan
  17. import SwiftGifOrigin
  18. import AdSupport
  19. import CoreLocation
  20. import Photos
  21. import TUICore
  22. import AVFoundation
  23. import YJNetManager
  24. import YJTaskMark
  25. import LGAlertHUD
  26. import YJExtensions
  27. // IMID
  28. #if DEBUG
  29. let IMID: Int32 = 33365
  30. #else
  31. let IMID: Int32 = 33364
  32. #endif
  33. // WkWebView加载地址 http://m.lancooedu.com/#/login http://isca.lancooedu.com/airobot/AndroidWeb/index.html
  34. #if DEBUG
  35. let mainUrl:String = "http://m.lancooedu.com/#/login"
  36. #else
  37. let mainUrl:String = "http://m.lancooedu.com"
  38. #endif
  39. class MainController: UIViewController,WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler,UINavigationControllerDelegate {
  40. var webView: WKWebView!
  41. var payView: WKWebView!
  42. var mmkv:MMKV = MMKV.default()!
  43. var payScheme:String = ""
  44. let filePath:String = NSHomeDirectory () + "/Documents/"
  45. var testBtn: UIButton!
  46. var stopTestBtn: UIButton!
  47. static var preViewFilePath:String = ""
  48. // 在线消息推送队列 实现堆叠的通知
  49. let bannerQueueToDisplaySeveralBanners = NotificationBannerQueue(maxBannersOnScreenSimultaneously: 3)
  50. let appId = "1598062593" // appId,为了跳转到App Store下载
  51. let imageView = UIImageView()
  52. //定位管理器
  53. let locationManager:CLLocationManager = CLLocationManager()
  54. private lazy var session:URLSession = {
  55. //只执行一次
  56. let config = URLSessionConfiguration.default
  57. // 设置超时时常 单位是s
  58. config.timeoutIntervalForRequest = 100
  59. let currentSession = URLSession(configuration: config, delegate: self,delegateQueue: nil)
  60. return currentSession
  61. }()
  62. var taskId:Int = 0
  63. var fileName:String = ""
  64. var uploadFileUrl:String = ""
  65. var uploadFileTaskId:Int = 0
  66. var uploadParam:UploadParam = UploadParam.init()
  67. var scanCodeTaskId:Int = 0
  68. var getLocationTaskId:Int = 0
  69. let loading = UIActivityIndicatorView()
  70. override func viewDidLayoutSubviews() {
  71. super.viewDidLayoutSubviews()
  72. view.bringSubviewToFront(loading)
  73. }
  74. var callingVC = UIViewController()
  75. var updateMessage:String = "" // 获取到的更新App的信息
  76. var trackViewUrlString:String = "" // 一个地址,提示用户更新的时候需要的
  77. // 加载的动态图
  78. var gifView = WKWebView()
  79. var soundId: SystemSoundID?
  80. override func loadView() {
  81. let configuration=WKWebViewConfiguration()
  82. // 为WKWebViewController设置偏好设置
  83. let preference = WKWebpagePreferences()
  84. // 允许native与js交互
  85. preference.allowsContentJavaScript = true
  86. configuration.defaultWebpagePreferences = preference
  87. let userContentController = WKUserContentController.init()
  88. userContentController.add(self, name: "IosStorage")
  89. userContentController.add(self, name: "IosDevices")
  90. userContentController.add(self, name: "IosNet")
  91. configuration.userContentController = userContentController
  92. configuration.allowsInlineMediaPlayback = true;
  93. webView = WKWebView(frame: .zero,configuration: configuration)
  94. webView.uiDelegate = self
  95. webView.navigationDelegate = self
  96. webView.allowsBackForwardNavigationGestures = true
  97. webView.scrollView.contentInsetAdjustmentBehavior = UIScrollView.ContentInsetAdjustmentBehavior.never
  98. view = webView
  99. // testAction()
  100. if(mmkv.contains(key: "userInfo")) {
  101. self.rtcLogin()
  102. }
  103. }
  104. func testAction() {
  105. testBtn = UIButton.init(frame: CGRect(x: 100, y: 200, width: 100, height: 50))
  106. testBtn.setTitle("测试识别", for: .normal)
  107. testBtn.setTitleColor(UIColor.red, for: .normal)
  108. testBtn.addTarget(self, action: #selector(startSpeechMark), for: .touchUpInside)
  109. view.addSubview(testBtn)
  110. stopTestBtn = UIButton.init(frame: CGRect(x: 100, y: 260, width: 100, height: 50))
  111. stopTestBtn.setTitle("停止测试", for: .normal)
  112. stopTestBtn.setTitleColor(UIColor.red, for: .normal)
  113. stopTestBtn.addTarget(self, action: #selector(stopSpeechMark), for: .touchUpInside)
  114. view.addSubview(stopTestBtn)
  115. }
  116. @objc func refuslt(){
  117. }
  118. override func viewWillAppear(_ animated: Bool) {
  119. self.navigationController?.navigationBar.isHidden = true
  120. }
  121. override func viewDidLoad() {
  122. super.viewDidLoad()
  123. let myURL = URL(string: mainUrl)!
  124. // if (mmkv.contains(key: "homeUrl")) {
  125. // myURL = URL(string: mmkv.string(forKey: "homeUrl")!)!
  126. // }
  127. let myRequest = URLRequest(url: myURL)
  128. self.webView.load(myRequest)
  129. self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true
  130. if(mmkv.contains(key: "userInfo")) {
  131. self.rtcAuthLogin()
  132. }
  133. // 未读通知设置为0
  134. AppDelegate.unreadNumber = 0
  135. UIApplication.shared.applicationIconBadgeNumber = 0
  136. //设置状态监听
  137. NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
  138. NotificationCenter.default.addObserver(self, selector: #selector(appDidEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
  139. if (AppDelegate.PUSH_URL != nil) {
  140. let myURL = URL(string: AppDelegate.PUSH_URL!)!
  141. let myRequest = URLRequest(url: myURL)
  142. webView.load(myRequest)
  143. AppDelegate.PUSH_URL = nil
  144. }
  145. if mmkv.contains(key: "__APP_ONLY_LOG_SUCCESS_KEY__") {
  146. // 登录了
  147. // 判断有没有url,没有url,不做任何处理,有url,加载url
  148. if mmkv.contains(key: "scheme_to_url") {
  149. let url = mmkv.string(forKey: "scheme_to_url")!
  150. let myURL = URL(string: url)!
  151. let myRequest = URLRequest(url: myURL)
  152. webView.load(myRequest)
  153. mmkv.removeValue(forKey: "scheme_to_url")
  154. }else {
  155. }
  156. }else {
  157. // 未登录
  158. }
  159. // 检查版本更新
  160. AppCheckVersion.checkVersion(appId, nil)
  161. }
  162. // 即将进入前台通知
  163. @objc func appWillEnterForeground(){
  164. // 检查版本更新
  165. AppCheckVersion.checkVersion(appId, nil)
  166. AppDelegate.unreadNumber = 0
  167. if mmkv.contains(key: "__APP_ONLY_LOG_SUCCESS_KEY__") {
  168. // 登录了
  169. // 判断有没有url,没有url,不做任何处理,有url,加载url
  170. if mmkv.contains(key: "scheme_to_url") {
  171. let url = mmkv.string(forKey: "scheme_to_url")!
  172. let myURL = URL(string: url)!
  173. let myRequest = URLRequest(url: myURL)
  174. webView.load(myRequest)
  175. mmkv.removeValue(forKey: "scheme_to_url")
  176. }else {
  177. // if(mmkv.contains(key: "homeUrl")) {
  178. // let homeUrl:String = mmkv.string(forKey: "homeUrl")!
  179. // print("homeUrl:\(homeUrl)")
  180. // if !homeUrl.isEmpty {
  181. // let myURL = URL(string: homeUrl)!
  182. // let myRequest = URLRequest(url: myURL)
  183. // webView.load(myRequest)
  184. // }
  185. // }else {
  186. // self.view.makeToast("无法跳转到主页")
  187. // }
  188. }
  189. }else {
  190. // 未登录
  191. }
  192. print("周期 ---将进入前台通知")
  193. }
  194. //应用程序确实进入了后台
  195. @objc func appDidEnterBackground(){
  196. print("周期 ---应用程序确实进入了后台")
  197. }
  198. //语音识别授权
  199. func authSpeechMark(userID:String){
  200. YJNetManager.default().userID = userID
  201. if (!YJSpeechManager.default().isInitEngine()){
  202. YJSpeechManager.default().initEngine()
  203. YJSpeechManager.default().updateWarrntIdAuth()
  204. }
  205. }
  206. //开启语音识别
  207. @objc func startSpeechMark() {
  208. YJSpeechManager.default().startEngine(atRefText: nil, markType: .chineseASR, symbol: true)
  209. YJSpeechManager.default().speechEngineResult { resultModel in
  210. if (resultModel!.isError){
  211. LGAlertHUD.shareInstance().showError(withStatus: resultModel?.errorMsg)
  212. }else {
  213. let answer:String = resultModel?.recognition.yj_deleteWhitespaceCharacter() ?? ""
  214. if (answer.count > 0){
  215. print("识别内容:\(answer)")
  216. self.webView.evaluateJavaScript("onAndroidRecognitionResult('\(answer)')") { obj, error in
  217. print("识别上传错误:",error ?? "无错")
  218. }
  219. }else{
  220. LGAlertHUD.shareInstance().showInfo(withStatus: "语音输入为空")
  221. }
  222. }
  223. }
  224. }
  225. //停止语音识别
  226. @objc func stopSpeechMark() {
  227. YJSpeechManager.default().stopEngine(withTip: NSString.yj_Char1())
  228. }
  229. // RTC login
  230. func rtcLogin() {
  231. let userInfo = self.mmkv.string(forKey: "userInfo", defaultValue: "")!
  232. if userInfo.count > 0 {
  233. // userInfo不为空,转化为字典,取出SchoolID和UserID,拼接出实时音的登录用户名
  234. let userInfoDict = userInfo.toDictionary()
  235. let schoolId = userInfoDict["SchoolID"]!
  236. let userId = userInfoDict["UserID"]!
  237. let userName = userInfoDict["UserName"] as! String
  238. let avatar = userInfoDict["PhotoPath"] as! String
  239. let userInfo:[String:String] = ["userId":"\(schoolId)_\(userId)","userName":userName,"avatar": avatar]
  240. ProfileManager.shared.login(phone: dicValueString(userInfo)!, code: "") { [weak self] in
  241. guard let `self` = self else { return }
  242. self.loading.stopAnimating()
  243. self.loginIM { [weak self] (success) in
  244. guard let `self` = self else { return }
  245. if success {
  246. if ProfileManager.shared.curUserModel?.name.count == 0 {
  247. ProfileManager.shared.synchronizUserInfo()
  248. ProfileManager.shared.setNickName(name: "\(userName)") { [weak self] in
  249. guard self != nil else { return }
  250. let confg:V2TIMAPNSConfig = V2TIMAPNSConfig.init()
  251. // 推送证书 ID,上传推送证书(p.12)到 IM 控制台后生成
  252. confg.businessID = IMID
  253. // 苹果后台请求的 deviceToken
  254. confg.token = AppDelegate.deviceToken;
  255. print("deviceToken:\(AppDelegate.deviceToken)")
  256. V2TIMManager.sharedInstance()?.setAPNS(confg, succ: {
  257. print("-----> 设置 APNS 成功")
  258. }, fail: { (code,msg) in
  259. print("-----> 设置 APNS 失败")
  260. })
  261. } failed: { (err) in
  262. self.loading.stopAnimating()
  263. //self.view.makeToast(err)
  264. DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
  265. self.navigationController?.popViewController(animated: true)
  266. }
  267. }
  268. } else {
  269. //self.view.makeToast(LoginLocalize(key:"V2.Live.LinkMicNew.loginsuccess"))
  270. }
  271. }
  272. }
  273. }
  274. }
  275. }
  276. // RTC authLogin
  277. func rtcAuthLogin() {
  278. let userInfo = mmkv.string(forKey: "userInfo",defaultValue: "")!
  279. if userInfo.count > 0{
  280. // userInfo不为空,转化为字典,取出SchoolID和UserID,拼接出实时音的登录用户名
  281. let userInfoDict = userInfo.toDictionary()
  282. let userName = userInfoDict["UserName"] as! String
  283. let userId = userInfoDict["UserID"]!
  284. authSpeechMark(userID: userId as! String)
  285. if ProfileManager.shared.autoLogin(success: {
  286. self.loginIM { [weak self] (success) in
  287. guard let `self` = self else { return }
  288. self.loading.stopAnimating()
  289. if success {
  290. if ProfileManager.shared.curUserModel?.name.count == 0 {
  291. ProfileManager.shared.synchronizUserInfo()
  292. // name: "S-11261527_jz_S03004"
  293. ProfileManager.shared.setNickName(name: "\(userName)") { [weak self] in
  294. print(self as Any)
  295. } failed: { (err) in
  296. self.loading.stopAnimating()
  297. //self.view.makeToast(err)
  298. DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
  299. self.navigationController?.popViewController(animated: true)
  300. }
  301. }
  302. } else {
  303. //self.view.makeToast(LoginLocalize(key:"V2.Live.LinkMicNew.loginsuccess"))
  304. }
  305. let confg:V2TIMAPNSConfig = V2TIMAPNSConfig.init()
  306. // 推送证书 ID,上传推送证书(p.12)到 IM 控制台后生成
  307. confg.businessID = IMID;
  308. // 苹果后台请求的 deviceToken
  309. confg.token = AppDelegate.deviceToken;
  310. print("deviceToken:\(AppDelegate.deviceToken)")
  311. V2TIMManager.sharedInstance()?.setAPNS(confg, succ: {
  312. print("-----> 设置 APNS 成功")
  313. }, fail: { (code,msg) in
  314. print("-----> 设置 APNS 失败")
  315. })
  316. }
  317. }
  318. }, failed: { [weak self] (err) in
  319. guard let self = self else {return}
  320. self.loading.stopAnimating()
  321. //self.view.makeToast(err)
  322. }) {
  323. }
  324. }
  325. }
  326. func loginIM(complete: @escaping (_ success: Bool)->Void) {
  327. guard let userID = ProfileManager.shared.curUserID() else { return }
  328. let userSig = ProfileManager.shared.curUserSig()
  329. V2TIMManager.sharedInstance()
  330. if V2TIMManager.sharedInstance()?.getLoginUser() != userID {
  331. ProfileManager.shared.IMLogin(userSig: userSig) {
  332. debugPrint("IM login success.")
  333. complete(true)
  334. } failed: { [weak self] (error) in
  335. guard self != nil else { return }
  336. //self.view.makeToast(LoginLocalize(key: "App.PortalViewController.loginimfailed"))
  337. complete(false)
  338. }
  339. }
  340. }
  341. var payPreUrl:String = "" // 跳转支付前,记录一下,跳转回APP时,需要加载的页面地址
  342. var preUrl:String = "" // 记录每次跳转页面的时候,前一个页面的地址
  343. // 支付跳转
  344. func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
  345. // 拦截请求头,支付跳转回APP,需要修改请求的referer地址
  346. let headers:[String:String] = navigationAction.request.allHTTPHeaderFields!
  347. let keys = headers.keys
  348. let b = keys.contains("Referer")
  349. if b {
  350. let referer = headers["Referer"]!
  351. // https://pay.lancooedu.com/mobilePay/pay.html
  352. print("【Referer】:\(referer)")
  353. if self.payScheme != "" && referer.contains("https://\(self.payScheme)") {
  354. var newRequest = navigationAction.request.urlRequest
  355. newRequest!.setValue("main.pay.lancooedu.com://", forHTTPHeaderField: "Referer")
  356. webView.load(newRequest!)
  357. decisionHandler(WKNavigationActionPolicy.cancel)
  358. return
  359. }
  360. }
  361. var reqUrl = navigationAction.request.url!.absoluteString
  362. print("reqUrl:\(reqUrl)")
  363. if reqUrl.hasPrefix("lancoopay://") {
  364. payPreUrl = preUrl
  365. // 跳转到微信 或 支付宝
  366. let lancoopay: String = "https"
  367. let range: Range = reqUrl.range(of: lancoopay)!
  368. let indexOfUrl = reqUrl.distance(from:reqUrl.startIndex, to:range.lowerBound)
  369. var navUrl = String(reqUrl.suffix(reqUrl.count-indexOfUrl))
  370. navUrl.insert(":", at: navUrl.firstIndex(of: "/")!)
  371. if let url = URL(string: navUrl) {
  372. if let hostName = url.host {
  373. // 设置跳转回App的scheme
  374. self.payScheme = hostName
  375. }
  376. }
  377. let configuration = WKWebViewConfiguration()
  378. let preference = WKWebpagePreferences()
  379. configuration.defaultWebpagePreferences = preference
  380. preference.allowsContentJavaScript = true
  381. let userContentController = WKUserContentController.init()
  382. userContentController.add(self, name: "IosStorage")
  383. userContentController.add(self, name: "IosDevices")
  384. userContentController.add(self, name: "IosNet")
  385. configuration.userContentController = userContentController
  386. payView = WKWebView(frame: .zero,configuration: configuration)
  387. payView.uiDelegate = self
  388. payView.navigationDelegate = self
  389. payView.allowsBackForwardNavigationGestures = true
  390. payView.scrollView.contentInsetAdjustmentBehavior = UIScrollView.ContentInsetAdjustmentBehavior.never
  391. let myURL = URL(string: navUrl)!
  392. let myRequest = URLRequest(url: myURL)
  393. payView.load(myRequest)
  394. webView.addSubview(payView)
  395. decisionHandler(.cancel)
  396. return
  397. }
  398. // 跳转到微信支付
  399. else if reqUrl.hasPrefix("weixin://") {
  400. mmkv.removeValues(forKeys: ["__pay__url","__pay__type","__pay__form"])
  401. // 跳转微信App
  402. if let toUrl = URL(string: reqUrl) {
  403. if #available(iOS 10, *) {
  404. UIApplication.shared.open(toUrl, options: [:], completionHandler: {(success) in
  405. if (!success) {
  406. let content = "当前手机暂未下载微信,是否前往 AppStore 下载"
  407. let appStoreURL = "https://itunes.apple.com/app/id414478124"
  408. UIAlertController.alertPayTip(content,appStoreURL)
  409. }
  410. })
  411. } else {
  412. let bSucc = UIApplication.shared.openURL(toUrl)
  413. if !bSucc {
  414. let content = "当前手机暂未下载微信,是否前往 AppStore 下载"
  415. let appStoreURL = "https://itunes.apple.com/app/id414478124"
  416. UIAlertController.alertPayTip(content,appStoreURL)
  417. }
  418. }
  419. }
  420. webView.willRemoveSubview(payView)
  421. decisionHandler(WKNavigationActionPolicy.cancel)
  422. return
  423. }
  424. // 跳转到支付宝支付
  425. else if reqUrl.hasPrefix("alipays://") || reqUrl.hasPrefix("alipay://") {
  426. mmkv.removeValues(forKeys: ["__pay__url","__pay__type","__pay__form"])
  427. reqUrl = reqUrl.replacingOccurrences(of: "alipays", with: "main.pay.lancooedu.com")
  428. // 跳转支付宝App
  429. if let toUrl = URL(string: reqUrl) {
  430. if #available(iOS 10, *) {
  431. UIApplication.shared.open(toUrl, options: [:], completionHandler: {(success) in
  432. if (!success) {
  433. let content = "当前手机暂未下载支付宝,是否前往 AppStore 下载"
  434. let appStoreURL = "https://itunes.apple.com/cn/app/zhi-fu-bao-qian-bao-yu-e-bao/id333206289?mt=8"
  435. UIAlertController.alertPayTip(content,appStoreURL)
  436. }
  437. })
  438. } else {
  439. let bSucc = UIApplication.shared.openURL(toUrl)
  440. if !bSucc {
  441. let content = "当前手机暂未下载支付宝,是否前往 AppStore 下载"
  442. let appStoreURL = "https://itunes.apple.com/cn/app/zhi-fu-bao-qian-bao-yu-e-bao/id333206289?mt=8"
  443. UIAlertController.alertPayTip(content,appStoreURL)
  444. }
  445. }
  446. }
  447. webView.willRemoveSubview(payView)
  448. decisionHandler(WKNavigationActionPolicy.cancel)
  449. return
  450. }
  451. else if reqUrl.contains("lancooIosAppId") {
  452. let getIdString = "lancooIosAppId";
  453. let location:Int = reqUrl.positionOf(sub: getIdString)
  454. let jumpAppId = reqUrl.substring(from: location+getIdString.count+1)
  455. print("AppId:\(jumpAppId)")
  456. // 跳转第三方应用:lancoodemo://
  457. if let toUrl = URL(string: reqUrl) {
  458. if #available(iOS 10, *) {
  459. UIApplication.shared.open(toUrl, options: [:], completionHandler: {(success) in
  460. if (!success) {
  461. let content = "当前手机暂未下载该应用,是否前往 AppStore 下载"
  462. let appStoreURL = "https://itunes.apple.com/app/id\(jumpAppId)"
  463. UIAlertController.alertPayTip(content,appStoreURL)
  464. }
  465. })
  466. } else {
  467. let bSucc = UIApplication.shared.openURL(toUrl)
  468. if !bSucc {
  469. let content = "当前手机暂未下载该应用,是否前往 AppStore 下载"
  470. let appStoreURL = "https://itunes.apple.com/app/id\(jumpAppId)"
  471. UIAlertController.alertPayTip(content,appStoreURL)
  472. }
  473. }
  474. }
  475. }
  476. preUrl = reqUrl
  477. decisionHandler(WKNavigationActionPolicy.allow)
  478. }
  479. let keyWindow = UIApplication.shared.connectedScenes
  480. .map({ $0 as? UIWindowScene })
  481. .compactMap({ $0 })
  482. .first?.windows.first
  483. func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
  484. print("跳转页面中。。。")
  485. LoadingView.width = self.webView.bounds.width
  486. LoadingView.height = self.webView.bounds.height
  487. LoadingView.show()
  488. AppDelegate.initalTime = Int64(Date().timeIntervalSince1970)
  489. }
  490. // flag: true被t下线,false主动退出
  491. func logout(_ flag:Bool) {
  492. let cachePath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first
  493. let fileArr = FileManager.default.subpaths(atPath: cachePath!)
  494. for file in fileArr! {
  495. let path = (cachePath! as NSString).appending("/\(file)")
  496. if FileManager.default.fileExists(atPath: path) {
  497. do {
  498. try FileManager.default.removeItem(atPath: path)
  499. } catch {}
  500. }
  501. }
  502. let dataStore = WKWebsiteDataStore.default()
  503. dataStore.fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), completionHandler: { (records) in
  504. for record in records{
  505. WKWebsiteDataStore.default().removeData(ofTypes: record.dataTypes, for: [record], completionHandler: {
  506. print("清除成功\(record)")
  507. })
  508. }
  509. })
  510. if (mmkv.contains(key: "userInfo") && mmkv.contains(key: "homeUrl") && mmkv.contains(key: "token")
  511. && mmkv.contains(key: "account")) {
  512. mmkv.removeValue(forKey: "userInfo")
  513. mmkv.removeValue(forKey: "token")
  514. mmkv.removeValue(forKey: "account")
  515. mmkv.removeValue(forKey: "homeUrl")
  516. mmkv.removeValue(forKey: "__APP_ONLY_LOG_SUCCESS_KEY__")
  517. let myURL = URL(string: mainUrl)!
  518. let myRequest = URLRequest(url: myURL)
  519. webView.load(myRequest)
  520. webView.backForwardList.perform(Selector(("_removeAllItems")))
  521. }
  522. }
  523. func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
  524. let name = message.name
  525. print("name:\(name)")
  526. if name == "IosDevices" {
  527. print("messageBody:\(message.body)")
  528. let body:[String:Optional] = message.body as! [String : Optional<Any>]
  529. let method:String = body["method"] as! String
  530. if method == "back" {
  531. print("back")
  532. if(webView.canGoBack) {
  533. webView.goBack()
  534. }else {
  535. self.navigationController?.popViewController(animated: true)
  536. }
  537. }
  538. else if method == "goHome" {
  539. if(mmkv.contains(key: "homeUrl")) {
  540. let homeUrl:String = mmkv.string(forKey: "homeUrl")!
  541. print("homeUrl:\(homeUrl)")
  542. if !homeUrl.isEmpty {
  543. let myURL = URL(string: homeUrl)!
  544. let myRequest = URLRequest(url: myURL)
  545. webView.load(myRequest)
  546. webView.backForwardList.perform(Selector(("_removeAllItems")))
  547. }
  548. }else {
  549. self.view.makeToast("无法跳转到主页")
  550. }
  551. }
  552. else if method == "logout" {
  553. // 删除智慧校园登录信息
  554. self.logout(false)
  555. }else if method == "openFileReader" {
  556. let path = body["path"] as! String
  557. MainController.preViewFilePath = path
  558. print("预览文件路径:\(MainController.preViewFilePath)")
  559. let manager = FileManager.default
  560. var isDirectory = ObjCBool(false)
  561. let isExist:Bool = manager.fileExists(atPath: MainController.preViewFilePath,isDirectory:&isDirectory)
  562. if isExist {
  563. // 方法1:
  564. //navigationController?.pushViewController(PreViewFileVc(), animated: true)
  565. //方法2:
  566. let preViewController = QLPreviewController.init()
  567. preViewController.delegate = self
  568. preViewController.dataSource = self
  569. self.present(preViewController, animated: true) {
  570. print("打开文件")
  571. }
  572. // 方法3:
  573. // let filePath: String = MainController.preViewFilePath
  574. //
  575. // let indexOfFileName = filePath.positionOf(sub: "/", backwards: true)
  576. // let fileName = filePath.suffix(filePath.count-1-indexOfFileName)
  577. //
  578. // let documents:String = NSHomeDirectory() + "/Documents/" + fileName;
  579. // print("documents:\(documents)")
  580. // let documentController = UIDocumentInteractionController.init(url: URL.init(fileURLWithPath: documents))
  581. // documentController.delegate = self
  582. // documentController.presentPreview(animated: true)
  583. // 最终方法:采用wkwebview
  584. // let myURL = URL(string: MainController.preViewFilePathUrl)!
  585. // let myRequest = URLRequest(url: myURL)
  586. // webView.load(myRequest)
  587. }else {
  588. self.view.makeToast("文件已损坏,请退出重新登录下载")
  589. }
  590. //navigationController?.pushViewController(PreViewFileVc(), animated: true)
  591. } else if method == "clearCache" {
  592. // 暂时不清除缓存
  593. } else if method == "gotoUpdate" {
  594. // 手动更新
  595. let hasNewVersion = MMKV.default()!.bool(forKey: ConstantVC.HAS_NEW_VERSION)
  596. if hasNewVersion {
  597. UIApplication.shared.open(URL.init(string: "https://itunes.apple.com/app/id\(appId)")!, options: [:], completionHandler: nil)
  598. }else {
  599. self.view.makeToast("当前已经是最新版本")
  600. }
  601. } else if method == "scanCode" {
  602. self.scanCodeTaskId = body["taskId"] as! Int
  603. codeScan()
  604. } else if method == "getLocation" {
  605. self.getLocationTaskId = body["taskId"] as! Int
  606. getLocation()
  607. }
  608. }else if name == "IosStorage" {
  609. let sentData = message.body as! Dictionary<String,Optional<Any>>
  610. let method = sentData["method"] as! String
  611. if method == "set" {
  612. let key = sentData["key"] as! String
  613. if (sentData["value"] != nil) {
  614. let value = try? (sentData["value"] as! String)
  615. if (value != nil) {
  616. mmkv.set(value!, forKey: key)
  617. print("存储用户存储缓存:\(key)--\(value)--\(Date())")
  618. }
  619. }
  620. }
  621. self.rtcLogin()
  622. self.rtcAuthLogin()
  623. }else if name == "IosNet" {
  624. let body:[String:Optional] = message.body as! [String : Optional<Any>]
  625. let method:String = body["method"] as! String
  626. if method == "downloadFile" {
  627. self.taskId = body["taskId"] as! Int
  628. let url:String = body["url"] as! String
  629. self.fileName = body["fileName"] as! String
  630. print("\(taskId)--\(url)--\(fileName)")
  631. sessionSeniorDownload(downLoadUrl: url)
  632. }else if method == "uploadFile" {
  633. self.uploadParam.taskId = body["taskId"] as! Int
  634. self.uploadParam.url = body["url"] as! String
  635. self.uploadParam.fileType = body["fileType"] as! [String]
  636. self.uploadParam.limit = body["limit"] as! Int
  637. self.uploadParam.header = stringValueDic(body["header"] as! String)
  638. self.uploadParam.count = body["count"] as! Int
  639. let fileType = self.uploadParam.fileType
  640. let imageType = ["png","jpge","jpg"]
  641. var flag = true
  642. for ft in fileType {
  643. if !imageType.contains(ft) {
  644. flag = false
  645. }
  646. }
  647. if flag {
  648. let picker = UIImagePickerController()
  649. picker.delegate = self
  650. present(picker, animated: true, completion: nil)
  651. }else {
  652. var documentTypes:[UTType] = []
  653. for type in fileType {
  654. let type:UTType = UTType.init(filenameExtension: type)!
  655. documentTypes.append(type)
  656. }
  657. let document = UIDocumentPickerViewController.init(forOpeningContentTypes: documentTypes)
  658. if self.uploadParam.count == 1 {
  659. document.allowsMultipleSelection = false
  660. }else {
  661. document.allowsMultipleSelection = true
  662. }
  663. document.delegate = self //UIDocumentPickerDelegate
  664. print("开始选择文件")
  665. self.present(document, animated:true, completion:nil)
  666. }
  667. }else if method == "startSpeechRecognition" {
  668. startSpeechMark()
  669. }else if method == "stopSpeechRecognition" {
  670. stopSpeechMark()
  671. }
  672. }
  673. }
  674. func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]){
  675. //获取选择的原图
  676. let pickedImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
  677. //将选择的图片保存到Document目录下
  678. let fileManager = FileManager.default
  679. let rootPath = NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask, true)[0] as String
  680. let filePath = "\(rootPath)/pickedimage.jpg"
  681. let imageData = pickedImage.jpegData(compressionQuality: 1.0)
  682. fileManager.createFile(atPath: filePath, contents: imageData, attributes: nil)
  683. //上传图片
  684. if (fileManager.fileExists(atPath: filePath)){
  685. //取得NSURL
  686. sessionUpload(filePath)
  687. }
  688. picker.dismiss(animated: true, completion: nil)
  689. }
  690. func sessionUpload(_ document:String){
  691. print("document:\(document)")
  692. //上传地址
  693. let url = URL(string: self.uploadParam.url)
  694. //请求
  695. let request = NSMutableURLRequest(url: url!)
  696. for e in self.uploadParam.header {
  697. request.addValue(e.value, forHTTPHeaderField: e.key)
  698. }
  699. let boundary = "Boundary-\(UUID().uuidString)"
  700. let body = NSMutableArray()
  701. var fileTmpStr = ""
  702. //设置为POST请求
  703. request.httpMethod = "POST"
  704. request.setValue("multipart/form-data; boundary=----\(boundary)", forHTTPHeaderField: "Content-Type")
  705. // 上传文件的文件名,按照需求起名字就好
  706. let imgPath:String = document.removingPercentEncoding!
  707. let indexOfPoint = imgPath.positionOf(sub: ".", backwards: true)
  708. let suffix = imgPath.suffix(imgPath.count-1-indexOfPoint)
  709. print(suffix)
  710. let indexOfFileName = imgPath.positionOf(sub: "/", backwards: true)
  711. let fileName = imgPath.suffix(imgPath.count-1-indexOfFileName)
  712. print(fileName)
  713. // 将文件名和boundary组装在一起
  714. fileTmpStr = "------\(boundary)\r\nContent-Disposition: form-data; name=\"file\"; filename=\"\(fileName)\"\r\n"
  715. body.add(fileTmpStr)
  716. // 文件类型是图片,png、jpeg随意
  717. fileTmpStr = "Content-Type: image/\(suffix)\r\n\r\n"
  718. body.add(fileTmpStr)
  719. // 将body里的内容转成字符串
  720. let parameterStr = body.componentsJoined(by: "")
  721. // UTF8转码,防止汉字符号引起的非法网址
  722. var parameterData = parameterStr.data(using: String.Encoding.utf8)!
  723. // 将图片追加进parameterData
  724. let imageData = try! Data(contentsOf: URL(fileURLWithPath: imgPath))
  725. parameterData.append(imageData)
  726. // 将boundary结束部分追加进parameterData
  727. parameterData.append("\r\n------\(boundary)--".data(using: String.Encoding.utf8)!)
  728. // 设置请求体
  729. request.httpBody = parameterData
  730. //发起请求
  731. let dataTask = session.dataTask(with: request as URLRequest) { (data, response, error) in
  732. //上传完毕后
  733. if error != nil{
  734. DispatchQueue.main.async {
  735. self.webView.evaluateJavaScript("onIosUploadError(\(self.uploadParam.taskId),'network')") { (data, err) in
  736. print("onIosUploadError|network")
  737. }
  738. }
  739. }else{
  740. let str = String(data: data!, encoding: String.Encoding.utf8)!
  741. print("上传完毕:\(str)")
  742. DispatchQueue.main.async {
  743. self.webView.evaluateJavaScript("onIosUploadSuccess(\(self.uploadParam.taskId),'\(str)')") { (data, err) in
  744. }
  745. }
  746. }
  747. }
  748. //请求开始
  749. dataTask.resume()
  750. }
  751. func sessionFileUpload(_ urlsAndData:[String:Data]){
  752. print("urlsAndData:\(urlsAndData)")
  753. //上传地址
  754. let url = URL(string: self.uploadParam.url)
  755. //请求
  756. let request = NSMutableURLRequest(url: url!)
  757. for e in self.uploadParam.header {
  758. print("header:\(e)")
  759. request.addValue(e.value, forHTTPHeaderField: e.key)
  760. }
  761. let boundary = "Boundary-\(UUID().uuidString)"
  762. let body = NSMutableArray()
  763. var fileTmpStr = ""
  764. //设置为POST请求
  765. request.httpMethod = "POST"
  766. request.setValue("multipart/form-data; boundary=----\(boundary)", forHTTPHeaderField: "Content-Type")
  767. var parameterData:Data = Data()
  768. for e in urlsAndData {
  769. if e.value.count == 0 {
  770. DispatchQueue.main.async {
  771. self.webView.evaluateJavaScript("onIosUploadError(\(self.uploadParam.taskId),'noSelect')") { (data, err) in
  772. print("onIosUploadError|noSelect")
  773. }
  774. }
  775. return
  776. }
  777. let filePath = e.key
  778. let indexOfFileName = filePath.positionOf(sub: "/", backwards: true)
  779. let fileName = filePath.suffix(filePath.count-1-indexOfFileName)
  780. print(fileName)
  781. // 将文件名和boundary组装在一起
  782. fileTmpStr = "\r\n------\(boundary)\r\nContent-Disposition: form-data; name=\"file\"; filename=\"\(fileName)\"\r\n"
  783. body.add(fileTmpStr)
  784. // 文件类型
  785. fileTmpStr = "Content-type:application/octet-stream\r\n\r\n"
  786. body.add(fileTmpStr)
  787. // 将body里的内容转成字符串
  788. let parameterStr = body.componentsJoined(by: "")
  789. // UTF8转码,防止汉字符号引起的非法网址
  790. parameterData = parameterStr.data(using: String.Encoding.utf8)!
  791. // 将文件追加进parameterData
  792. let data = e.value
  793. parameterData.append(data)
  794. parameterData.append("\r\n".data(using: String.Encoding.utf8)!)
  795. }
  796. // 将boundary结束部分追加进parameterData
  797. parameterData.append("\r\n------\(boundary)--".data(using: String.Encoding.utf8)!)
  798. // 设置请求体
  799. request.httpBody = parameterData
  800. //发起请求
  801. let dataTask = session.dataTask(with: request as URLRequest) { (data, response, error) in
  802. //上传完毕后
  803. if error != nil{
  804. DispatchQueue.main.async {
  805. self.webView.evaluateJavaScript("onIosUploadError(\(self.uploadParam.taskId),'network')") { (data, err) in
  806. print("onIosUploadError|network")
  807. }
  808. }
  809. }else{
  810. let str = String(data: data!, encoding: String.Encoding.utf8)!
  811. print("上传完毕:\(str)")
  812. DispatchQueue.main.async {
  813. self.webView.evaluateJavaScript("onIosUploadSuccess(\(self.uploadParam.taskId),'\(str)')") { (data, err) in
  814. }
  815. }
  816. }
  817. }
  818. print("dataTask:\(dataTask)")
  819. //请求开始
  820. dataTask.resume()
  821. }
  822. // 监听上传文件进度
  823. func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
  824. let written:CGFloat = (CGFloat)(totalBytesSent)
  825. let total:CGFloat = (CGFloat)(totalBytesExpectedToSend)
  826. let pro:CGFloat = written/total
  827. let process:Int = Int(pro * 100)
  828. print("上传进度:\(pro)")
  829. DispatchQueue.main.async {
  830. self.webView.evaluateJavaScript("onIosUploadProgress(\(self.uploadParam.taskId),\(process))") { (data, err) in
  831. print("onIosUploadProgress:\(self.uploadParam.taskId)--\(process)")
  832. }
  833. }
  834. }
  835. func buildFileData(_ url:String) -> Data {
  836. // 上传文件的文件名,按照需求起名字就好
  837. //let  strToUtf8 = url.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) ?? ""
  838. let filePath:String = url.removingPercentEncoding!
  839. let indexOfPoint = filePath.positionOf(sub: ".", backwards: true)
  840. let suffix = filePath.suffix(filePath.count-1-indexOfPoint)
  841. print(suffix)
  842. // 校验文件类型
  843. print(self.uploadParam.fileType)
  844. print(self.uploadParam.fileType.contains(String(suffix).lowercased()))
  845. if !self.uploadParam.fileType.contains(String(suffix).lowercased()) {
  846. DispatchQueue.main.async {
  847. self.webView.evaluateJavaScript("onIosUploadError(\(self.uploadParam.taskId),'extendNameError')") { (data, err) in
  848. print("onIosUploadError|extendNameError")
  849. }
  850. }
  851. return Data.init()
  852. }
  853. let data = try! Data(contentsOf: URL(fileURLWithPath: filePath))
  854. if data.count > self.uploadParam.limit*1024*1024 {
  855. DispatchQueue.main.async {
  856. self.webView.evaluateJavaScript("onIosUploadError(\(self.uploadParam.taskId),'exceedLimit')") { (data, err) in
  857. print("onIosUploadError|exceedLimit")
  858. }
  859. }
  860. return Data.init()
  861. }
  862. return data
  863. }
  864. func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
  865. // 未选择
  866. if urls.count == 0 {
  867. DispatchQueue.main.async {
  868. self.webView.evaluateJavaScript("onIosUploadError(\(self.uploadParam.taskId),'noSelect')") { (data, err) in
  869. }
  870. }
  871. return
  872. }
  873. // 超过所需选择数量
  874. if urls.count > self.uploadParam.count {
  875. DispatchQueue.main.async {
  876. self.webView.evaluateJavaScript("onIosUploadError(\(self.uploadParam.taskId),'exceedCount')") { (data, err) in
  877. }
  878. }
  879. return
  880. }
  881. let fileUrlAuthorized:Bool = (urls.first?.startAccessingSecurityScopedResource())! as Bool
  882. if fileUrlAuthorized {
  883. let fileCoordinator = NSFileCoordinator.init()
  884. var error:NSError?
  885. // 需要上传的文件路径
  886. var newUrlsData:[String:Data] = [:]
  887. for url in urls {
  888. fileCoordinator.coordinate(readingItemAt: url, options: NSFileCoordinator.ReadingOptions.forUploading, error: &error) { (newURL:URL) in
  889. let tempUrl = String(newURL.absoluteString.suffix(newURL.absoluteString.count - 7))
  890. let data = buildFileData(tempUrl)
  891. newUrlsData[tempUrl] = data
  892. }
  893. }
  894. sessionFileUpload(newUrlsData)
  895. urls.first?.stopAccessingSecurityScopedResource()
  896. }
  897. }
  898. func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
  899. print("documentPickerWasCancelled")
  900. }
  901. func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
  902. }
  903. func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
  904. LoadingView.complete()
  905. YJSpeechManager.default().setMicrophoneAuthorization()
  906. }
  907. func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
  908. LoadingView.complete()
  909. }
  910. func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
  911. LoadingView.complete()
  912. }
  913. let refreshLabel = UILabel()
  914. func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
  915. // let response:HTTPURLResponse = navigationResponse.response as! HTTPURLResponse
  916. // print("跳转地址:\(response.url?.absoluteString)!")
  917. decisionHandler(.allow)
  918. }
  919. //MARK:WKUIDelegate
  920. //此方法作为js的alert方法接口的实现,默认弹出窗口应该只有提示消息,及一个确认按钮,当然可以添加更多按钮以及其他内容,但是并不会起到什么作用
  921. //点击确认按钮的相应事件,需要执行completionHandler,这样js才能继续执行
  922. //参数 message为 js 方法 alert(<message>) 中的<message>
  923. func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
  924. let alertViewController = UIAlertController(title: nil, message:message, preferredStyle: UIAlertController.Style.alert)
  925. alertViewController.addAction(UIAlertAction(title: "确认", style: UIAlertAction.Style.default, handler: { (action) in
  926. completionHandler()
  927. }))
  928. self.present(alertViewController, animated: true, completion: nil)
  929. }
  930. // confirm
  931. //作为js中confirm接口的实现,需要有提示信息以及两个相应事件, 确认及取消,并且在completionHandler中回传相应结果,确认返回YES, 取消返回NO
  932. //参数 message为 js 方法 confirm(<message>) 中的<message>
  933. func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
  934. let alertVicwController = UIAlertController(title: "提示", message: message, preferredStyle: UIAlertController.Style.alert)
  935. alertVicwController.addAction(UIAlertAction(title: "取消", style: UIAlertAction.Style.cancel, handler: { (alertAction) in
  936. completionHandler(false)
  937. }))
  938. alertVicwController.addAction(UIAlertAction(title: "确定", style: UIAlertAction.Style.default, handler: { (alertAction) in
  939. 3
  940. }))
  941. self.present(alertVicwController, animated: true, completion: nil)
  942. }
  943. // prompt
  944. //作为js中prompt接口的实现,默认需要有一个输入框一个按钮,点击确认按钮回传输入值
  945. //当然可以添加多个按钮以及多个输入框,不过completionHandler只有一个参数,如果有多个输入框,需要将多个输入框中的值通过某种方式拼接成一个字符串回传,js接收到之后再做处理
  946. //参数 prompt 为 prompt(<message>, <defaultValue>);中的<message>
  947. //参数defaultText 为 prompt(<message>, <defaultValue>);中的 <defaultValue>
  948. func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
  949. let body:String = prompt.description
  950. if(body.hasPrefix("IosStorageGet")) {
  951. let keys = body.components(separatedBy: "|")
  952. if keys.count >= 2 {
  953. let key = keys[1]
  954. if (mmkv.contains(key:key)) {
  955. let value = mmkv.string(forKey: key)
  956. print("获取用户存储缓存:\(key)--\(value!)")
  957. completionHandler(value)
  958. return
  959. }
  960. }
  961. completionHandler("")
  962. return
  963. }
  964. if(body.hasPrefix("EnvironmentVariable")) {
  965. let keys = body.components(separatedBy: "|")
  966. if keys.count >= 2 {
  967. let key = keys[1]
  968. switch key {
  969. case "iosEnv":
  970. completionHandler("iOS")
  971. return
  972. case "CameraPermission":
  973. let isOpenCamera = IsOpenCamera()
  974. let result = "\(isOpenCamera)"
  975. print("isOpenCamera:\(result)")
  976. completionHandler(result)
  977. return;
  978. default:
  979. completionHandler("")
  980. break;
  981. }
  982. }
  983. completionHandler("")
  984. return
  985. }
  986. switch body {
  987. case "getId":
  988. // 获取设备唯一标识
  989. print("getId...")
  990. // let deviceId = ASIdentifierManager.shared().advertisingIdentifier.uuidString
  991. let deviceId = UIDevice.current.identifierForVendor?.uuidString
  992. print("deviceId:\(deviceId!)")
  993. completionHandler("\(deviceId!)")
  994. break
  995. case "getIp":
  996. // 获取ip地址
  997. print("getIp...")
  998. completionHandler("192.168.2.90")
  999. break
  1000. case "getStatusBarHeight":
  1001. print("getStatusBarHeight...")
  1002. // 状态栏高度
  1003. let statusHeight = isIphoneX() ? "24" : "0";
  1004. print("statusHeight:\(statusHeight)")
  1005. completionHandler(statusHeight)
  1006. break
  1007. case "getFooterHeight":
  1008. print("getFooterHeight...")
  1009. // 底部横线高度
  1010. let footerHeight = isIphoneX() ? "10" : "0";
  1011. completionHandler(footerHeight)
  1012. break
  1013. case "cacheSize":
  1014. completionHandler("1")
  1015. break;
  1016. case "getAppVersion":
  1017. var appVersion = "5.0.0"
  1018. if MMKV.default()!.contains(key: ConstantVC.APP_VERSION) {
  1019. appVersion = MMKV.default()!.string(forKey: ConstantVC.APP_VERSION)!
  1020. }
  1021. completionHandler("\(appVersion)")
  1022. break;
  1023. case "hasNewVersion":
  1024. completionHandler("\(MMKV.default()!.bool(forKey: ConstantVC.HAS_NEW_VERSION))")
  1025. break
  1026. case "hasScanCode":
  1027. completionHandler("true")
  1028. break
  1029. default:
  1030. completionHandler("")
  1031. break
  1032. }
  1033. // let alertViewController = UIAlertController(title: prompt.description, message: "撒打算", preferredStyle: UIAlertController.Style.alert)
  1034. // alertViewController.addTextField { (textField) in
  1035. // textField.text = defaultText
  1036. // }
  1037. //
  1038. // alertViewController.addAction(UIAlertAction(title: "完成", style: UIAlertAction.Style.default, handler: { (alertAction) in
  1039. // completionHandler("当前设备ID")
  1040. // }))
  1041. // self.present(alertViewController, animated: true, completion: nil)
  1042. }
  1043. // 判断是否设备是iphonex系列
  1044. func isIphoneX() -> (Bool) {
  1045. // ========第一种判断方法=========
  1046. // // iPhoneX,XS
  1047. // if (UIScreen.main.bounds.size.width == 375 && UIScreen.main.bounds.size.height == 812) {
  1048. // return true;
  1049. // }
  1050. //// // iPhoneXS Max,XR
  1051. // if (UIScreen.main.bounds.size.width == 414 && UIScreen.main.bounds.size.height == 896) {
  1052. // return true;
  1053. // }
  1054. // return false;
  1055. // ========第二种判断方法=========
  1056. if UIDevice.current.userInterfaceIdiom == .pad {
  1057. return false
  1058. }
  1059. let size = UIScreen.main.bounds.size
  1060. let notchValue = Int(size.width/size.height*100)
  1061. if notchValue == 216 || notchValue == 46 {
  1062. return true
  1063. }
  1064. return false
  1065. // ========第三种判断方法=========
  1066. // let screenHeight = UIScreen.main.nativeBounds.size.height
  1067. // if screenHeight == 2436 || screenHeight == 1792 || screenHeight == 2688 || screenHeight == 1624 {
  1068. // return true
  1069. // }
  1070. // return false
  1071. }
  1072. //下载文件
  1073. func sessionSeniorDownload(downLoadUrl:String){
  1074. var filePath:String = downLoadUrl.removingPercentEncoding!
  1075. filePath = filePath.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
  1076. //下载地址
  1077. let url = URL(string: filePath)
  1078. //请求
  1079. let request = URLRequest(url: url!)
  1080. //下载任务
  1081. let downloadTask = session.downloadTask(with: request)
  1082. //使用resume方法启动任务
  1083. downloadTask.resume()
  1084. let task = session.dataTask(with: request) { (data, response, error) in
  1085. if error != nil {
  1086. DispatchQueue.main.async {
  1087. self.webView.evaluateJavaScript("onIosDownError(\(self.taskId),'network')") { (data, err) in
  1088. print("onIosDownError")
  1089. }
  1090. }
  1091. } else {
  1092. print("NO ERROR")
  1093. }
  1094. }
  1095. task.resume()
  1096. }
  1097. //下载代理方法,下载结束
  1098. func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask,
  1099. didFinishDownloadingTo location: URL) {
  1100. //下载结束
  1101. print("下载结束")
  1102. //输出下载文件原来的存放目录
  1103. print("location:\(location)")
  1104. //location位置转换
  1105. let locationPath = location.path
  1106. //拷贝到用户目录
  1107. let fileManager = FileManager.default
  1108. //================获取文件下载地址
  1109. // let homeDirectory = NSHomeDirectory()
  1110. // print("\(homeDirectory)")
  1111. // let indexOfVirgule = homeDirectory.lastIndex(of: "/") ?? homeDirectory.endIndex
  1112. // let directory = homeDirectory[..<indexOfVirgule]
  1113. // let documents:String = "\(directory)/\(self.fileName)"
  1114. let documents:String = NSHomeDirectory() + "/Documents/" + self.fileName;
  1115. // let documents:String = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)[0] + "/" + self.fileName
  1116. // let documents:String = NSHomeDirectory() + "/Documents/" + self.fileName;
  1117. //创建文件管理器
  1118. if fileManager.fileExists(atPath: documents) {
  1119. do {
  1120. try FileManager.init().removeItem(atPath: documents)
  1121. debugPrint("已删除" + documents)
  1122. } catch {
  1123. DispatchQueue.main.async {
  1124. self.webView.evaluateJavaScript("onIosDownError(\(self.taskId),'network')") { (data, err) in
  1125. print("onIosDownError")
  1126. }
  1127. }
  1128. print(error)
  1129. }
  1130. }
  1131. try! fileManager.moveItem(atPath: locationPath, toPath: documents)
  1132. print("new location:\(documents)")
  1133. DispatchQueue.main.async {
  1134. self.webView.evaluateJavaScript("onIosDownSuccess(\(self.taskId),'\(documents)')") { (data, err) in
  1135. print("onIosDownSuccess")
  1136. }
  1137. }
  1138. }
  1139. //下载代理方法,监听下载进度
  1140. func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask,
  1141. didWriteData bytesWritten: Int64, totalBytesWritten: Int64,
  1142. totalBytesExpectedToWrite: Int64) {
  1143. //获取进度
  1144. let written:CGFloat = (CGFloat)(totalBytesWritten)
  1145. let total:CGFloat = (CGFloat)(totalBytesExpectedToWrite)
  1146. let pro:CGFloat = written/total
  1147. let process:Int = Int(pro * 100)
  1148. print("下载进度:\(pro)")
  1149. DispatchQueue.main.async {
  1150. self.webView.evaluateJavaScript("onIosDownProgress(\(self.taskId),\(process))") { (data, err) in
  1151. print("onIosDownProgress:\(self.taskId)--\(process)")
  1152. }
  1153. }
  1154. }
  1155. //下载代理方法,下载偏移
  1156. func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask,
  1157. didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {
  1158. //下载偏移,主要用于暂停续传
  1159. DispatchQueue.main.async {
  1160. self.webView.evaluateJavaScript("onIosDownError(\(self.taskId),'network')") { (data, err) in
  1161. print("onIosDownError")
  1162. }
  1163. }
  1164. }
  1165. override func didReceiveMemoryWarning() {
  1166. super.didReceiveMemoryWarning()
  1167. print("didReceiveMemoryWarning")
  1168. }
  1169. // MARK: 字符串转字典
  1170. func stringValueDic(_ str: String) -> [String : String]{
  1171. print("stringValueDic:\(str)")
  1172. let data = str.data(using: String.Encoding.utf8)
  1173. if let dict = try? JSONSerialization.jsonObject(with: data!,
  1174. options: .mutableContainers) as? [String : String] {
  1175. print("stringValueDic:dict:\(dict)")
  1176. return dict
  1177. }
  1178. return [:]
  1179. }
  1180. }
  1181. extension MainController: URLSessionDownloadDelegate,UIDocumentPickerDelegate,UIImagePickerControllerDelegate,V2TIMSignalingListener{
  1182. func onReceiveNewInvitation(_ inviteID: String!, inviter: String!, groupID: String!, inviteeList: [String]!, data: String?) {
  1183. print("inviteID:\(String(describing: inviteID))")
  1184. }
  1185. // 打开相机权限
  1186. func openCamera() {
  1187. let authStatus = AVCaptureDevice.authorizationStatus(for: .video)
  1188. if authStatus == .notDetermined {
  1189. AVCaptureDevice.requestAccess(for: .video) { (res) in
  1190. //此处可以判断权限状态来做出相应的操作,如改变按钮状态
  1191. if res{
  1192. }else{
  1193. }
  1194. }
  1195. }
  1196. }
  1197. //开启相册权限
  1198. func openAlbum() {
  1199. let authStatus = PHPhotoLibrary.authorizationStatus()
  1200. if authStatus == .notDetermined {
  1201. PHPhotoLibrary.requestAuthorization({ (status) in
  1202. //此处可以判断权限状态来做出相应的操作,如改变按钮状态
  1203. if status == .authorized {
  1204. } else if status == .denied || status == .restricted{
  1205. }
  1206. })
  1207. }
  1208. }
  1209. //是否开启相机权限
  1210. func IsOpenCamera() -> Bool{
  1211. let authStatus = AVCaptureDevice.authorizationStatus(for: .video)
  1212. return authStatus != .restricted && authStatus != .denied
  1213. }
  1214. //是否开启相册权限
  1215. func IsOpenAlbum() -> Bool{
  1216. let authStatus = PHPhotoLibrary.authorizationStatus(for: .readWrite)
  1217. return authStatus != .restricted && authStatus != .denied
  1218. }
  1219. }
  1220. extension MainController:V2TIMSDKListener {
  1221. func onKickedOffline() {
  1222. print("被t下线了")
  1223. if (mmkv.contains(key: "userInfo") && mmkv.contains(key: "homeUrl") && mmkv.contains(key: "token")
  1224. && mmkv.contains(key: "account")) {
  1225. mmkv.removeValue(forKey: "userInfo")
  1226. mmkv.removeValue(forKey: "token")
  1227. mmkv.removeValue(forKey: "account")
  1228. mmkv.removeValue(forKey: "homeUrl")
  1229. let myURL = URL(string: mainUrl)!
  1230. let myRequest = URLRequest(url: myURL)
  1231. webView.load(myRequest)
  1232. webView.backForwardList.perform(Selector(("_removeAllItems")))
  1233. }
  1234. }
  1235. func IMLogout() {
  1236. ProfileManager.shared.removeLoginCache()
  1237. V2TIMManager.sharedInstance()?.logout({
  1238. }, fail: { (errCode, errMsg) in
  1239. })
  1240. self.view.makeToast("已退出")
  1241. }
  1242. func IMKickOff() {
  1243. ProfileManager.shared.removeLoginCache()
  1244. V2TIMManager.sharedInstance()?.logout({
  1245. }, fail: { (errCode, errMsg) in
  1246. })
  1247. }
  1248. // MARK: 字典转字符串
  1249. func dicValueString(_ dic:[String : Any]) -> String?{
  1250. let data = try? JSONSerialization.data(withJSONObject: dic, options: [])
  1251. let str = String(data: data!, encoding: String.Encoding.utf8)
  1252. return str
  1253. }
  1254. }
  1255. // 在线推送
  1256. extension MainController: V2TIMAdvancedMsgListener {
  1257. //注册音频文件,获取SystemSoundID
  1258. func getSoundId() -> SystemSoundID {
  1259. var soundId: SystemSoundID = SystemSoundID()
  1260. let path = Bundle.main.path(forResource: "phone_ringing", ofType: "caf")
  1261. let url = URL.init(fileURLWithPath: path!)
  1262. AudioServicesCreateSystemSoundID(url as CFURL, &soundId)
  1263. return soundId
  1264. }
  1265. //播放自定义铃声和震动
  1266. func playAlertSound() {
  1267. if soundId == nil {
  1268. soundId = self.getSoundId()
  1269. }
  1270. AudioServicesAddSystemSoundCompletion(soundId!, nil, nil, { (SystemSoundID, pointer: UnsafeMutableRawPointer?) in
  1271. AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
  1272. AudioServicesPlaySystemSound(SystemSoundID)
  1273. }, nil)
  1274. //kSystemSoundID_Vibrate是震动的id
  1275. AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
  1276. AudioServicesPlaySystemSound(soundId!)
  1277. }
  1278. //停止播放
  1279. func stopAlertSoundWithSoundID() {
  1280. if soundId != nil {
  1281. AudioServicesDisposeSystemSoundID(soundId!)
  1282. AudioServicesRemoveSystemSoundCompletion(soundId!)
  1283. soundId = nil
  1284. }
  1285. AudioServicesDisposeSystemSoundID(kSystemSoundID_Vibrate)
  1286. }
  1287. func onRecvNewMessage(_ msg: V2TIMMessage!) {
  1288. let curTimeStamp = Int64(Date().timeIntervalSince1970)
  1289. if msg.customElem.desc != nil && msg.customElem.data != nil {
  1290. if curTimeStamp - AppDelegate.initalTime >= 3 && !String(msg.customElem.description).isEmpty {
  1291. if UIApplication.shared.applicationState == .active {
  1292. let content = UNMutableNotificationContent()
  1293. content.title = msg.customElem.desc!
  1294. content.userInfo["ext"] = msg.customElem.extension
  1295. content.body = String.init(data: msg.customElem.data, encoding: .utf8)!
  1296. //content.userInfo = ["icon":"1","mutable-content":1]
  1297. content.categoryIdentifier = "categoryIdentifier"
  1298. let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
  1299. let requestIdentifier = "imageLocal"
  1300. let request = UNNotificationRequest(identifier: requestIdentifier, content: content, trigger: trigger)
  1301. UNUserNotificationCenter.current().add(request, withCompletionHandler: { (error) in
  1302. if (error != nil) {
  1303. print("error: \(error.debugDescription)")
  1304. }
  1305. })
  1306. }
  1307. }
  1308. }
  1309. }
  1310. }
  1311. extension MainController: QLPreviewControllerDataSource,QLPreviewControllerDelegate {
  1312. func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
  1313. return 1
  1314. }
  1315. func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
  1316. let filePath: String = MainController.preViewFilePath
  1317. let indexOfFileName = filePath.positionOf(sub: "/", backwards: true)
  1318. let fileName = filePath.suffix(filePath.count-1-indexOfFileName)
  1319. let documents:String = NSHomeDirectory() + "/Documents/" + fileName;
  1320. print("documents:\(documents)")
  1321. return URL.init(fileURLWithPath: filePath) as QLPreviewItem
  1322. }
  1323. func previewControllerDidDismiss(_ controller: QLPreviewController) {
  1324. print("用户界面已消失")
  1325. }
  1326. func previewController(_ controller: QLPreviewController, shouldOpen url: URL, for item: QLPreviewItem) -> Bool {
  1327. return false
  1328. }
  1329. }
  1330. //extension MainController:UIDocumentInteractionControllerDelegate {
  1331. // func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
  1332. // return self
  1333. // }
  1334. // func documentInteractionControllerViewForPreview(_ controller: UIDocumentInteractionController) -> UIView? {
  1335. // return self.view
  1336. // }
  1337. // func documentInteractionControllerRectForPreview(_ controller: UIDocumentInteractionController) -> CGRect {
  1338. // return self.view.frame
  1339. // }
  1340. //}
  1341. extension MainController: NotificationBannerDelegate {
  1342. func notificationBannerWillAppear(_ banner: BaseNotificationBanner) {
  1343. }
  1344. func notificationBannerDidAppear(_ banner: BaseNotificationBanner) {
  1345. }
  1346. func notificationBannerWillDisappear(_ banner: BaseNotificationBanner) {
  1347. }
  1348. func notificationBannerDidDisappear(_ banner: BaseNotificationBanner) {
  1349. }
  1350. internal func showAlert(title: String, message: String) {
  1351. let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
  1352. let action = UIAlertAction(title: "OK", style: .default, handler: nil)
  1353. alertController.addAction(action)
  1354. present(alertController, animated: true, completion: nil)
  1355. }
  1356. /**
  1357. Convenience function to display banner with non .zero default edge insets
  1358. */
  1359. public func show(
  1360. queuePosition: QueuePosition = .back,
  1361. bannerPosition: BannerPosition = .top,
  1362. queue: NotificationBannerQueue = NotificationBannerQueue.default,
  1363. on viewController: UIViewController? = nil,
  1364. edgeInsets: UIEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8),
  1365. cornerRadius: CGFloat? = nil,
  1366. shadowColor: UIColor = .black,
  1367. shadowOpacity: CGFloat = 1,
  1368. shadowBlurRadius: CGFloat = 0,
  1369. shadowCornerRadius: CGFloat = 0,
  1370. shadowOffset: UIOffset = .zero,
  1371. shadowEdgeInsets: UIEdgeInsets? = nil
  1372. ) {
  1373. show(
  1374. queuePosition: queuePosition,
  1375. bannerPosition: bannerPosition,
  1376. queue: queue,
  1377. on: viewController
  1378. )
  1379. }
  1380. }
  1381. extension MainController: CLLocationManagerDelegate {
  1382. func getLocation() {
  1383. //设置定位服务管理器代理
  1384. locationManager.delegate = self
  1385. //设置定位进度
  1386. locationManager.desiredAccuracy = kCLLocationAccuracyBest
  1387. //更新距离
  1388. locationManager.distanceFilter = 0.1
  1389. ////发送授权申请
  1390. locationManager.requestAlwaysAuthorization()
  1391. if CLLocationManager.locationServicesEnabled()
  1392. {
  1393. //允许使用定位服务的话,开启定位服务更新
  1394. locationManager.startUpdatingLocation()
  1395. print("定位开始")
  1396. }
  1397. }
  1398. func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
  1399. print("定位失败")
  1400. DispatchQueue.main.async {
  1401. self.webView.evaluateJavaScript("onIosLocationError(\(self.getLocationTaskId),\"\(error.localizedDescription)\")") { (data, err) in
  1402. }
  1403. }
  1404. }
  1405. func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
  1406. //获取最新的坐标
  1407. let currLocation:CLLocation = locations.last!
  1408. var province:String = String.init()
  1409. var city:String = String.init()
  1410. let geocoder:CLGeocoder = CLGeocoder()
  1411. geocoder.reverseGeocodeLocation(currLocation) { placemarksArray, error in
  1412. if (error) == nil {
  1413. if placemarksArray!.count > 0 {
  1414. let placemark = placemarksArray?[0]
  1415. province = placemark?.administrativeArea ?? ""
  1416. city = placemark?.locality ?? ""
  1417. let locationDic:Dictionary<String, String> = [
  1418. "longitude":"\(currLocation.coordinate.longitude)",
  1419. "latitude":"\(currLocation.coordinate.latitude)",
  1420. "province":"\(province)",
  1421. "city":"\(city)"
  1422. ]
  1423. let data = try? JSONSerialization.data(withJSONObject: locationDic, options: JSONSerialization.WritingOptions.init(rawValue:0))
  1424. var result = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)! as String
  1425. result = result.replacingOccurrences(of: "\"", with: "\\\"")
  1426. print("定位成功:\(result)")
  1427. DispatchQueue.main.async {
  1428. self.webView.evaluateJavaScript("onIosLocationSuccess(\(self.getLocationTaskId),\"\(result)\")") { (data, err) in
  1429. }
  1430. }
  1431. }
  1432. }
  1433. }
  1434. locationManager.stopUpdatingLocation()
  1435. }
  1436. }
  1437. extension MainController: LBXScanViewControllerDelegate {
  1438. func scanFinished(scanResult: LBXScanResult, error: String?) {
  1439. let scanInfo:String? = scanResult.strScanned
  1440. if scanResult.strScanned != nil {
  1441. DispatchQueue.main.async {
  1442. do{
  1443. let data = try? JSONEncoder().encode(scanInfo)
  1444. let jsonArr = String(data: data!, encoding:String.Encoding.utf8)!
  1445. self.webView.evaluateJavaScript("onIosScanCodeSuccess(\(self.scanCodeTaskId),\(jsonArr))") { (data, err) in
  1446. print("将\(String(describing: scanInfo!))传回H5页面")
  1447. }
  1448. }
  1449. }
  1450. }else {
  1451. DispatchQueue.main.async {
  1452. self.webView.evaluateJavaScript("onIosScanCodeError(\(self.scanCodeTaskId))") { (data, err) in
  1453. print("扫码错误")
  1454. }
  1455. }
  1456. }
  1457. }
  1458. @objc func codeScan() {
  1459. //设置扫码区域参数
  1460. var style = LBXScanViewStyle()
  1461. style.centerUpOffset = 44
  1462. style.photoframeAngleStyle = LBXScanViewPhotoframeAngleStyle.On
  1463. style.photoframeLineW = 6
  1464. style.photoframeAngleW = 24
  1465. style.photoframeAngleH = 24
  1466. style.isNeedShowRetangle = true
  1467. style.anmiationStyle = LBXScanViewAnimationStyle.NetGrid
  1468. //使用的支付宝里面网格图片
  1469. style.animationImage = UIImage(named: "CodeScan.bundle/qrcode_scan_part_net")
  1470. let vc = LBXScanViewController()
  1471. vc.scanStyle = style
  1472. vc.scanResultDelegate = self
  1473. DispatchQueue.main.async {
  1474. self.navigationController?.navigationBar.isHidden = false
  1475. self.navigationController?.pushViewController(vc, animated: true)
  1476. }
  1477. }
  1478. }
  1479. extension String {
  1480. //返回第一次出现的指定子字符串在此字符串中的索引
  1481. //(如果backwards参数设置为true,则返回最后出现的位置)
  1482. func positionOf(sub:String, backwards:Bool = false)->Int {
  1483. var pos = -1
  1484. if let range = range(of:sub, options: backwards ? .backwards : .literal ) {
  1485. if !range.isEmpty {
  1486. pos = self.distance(from:startIndex, to:range.lowerBound)
  1487. }
  1488. }
  1489. return pos
  1490. }
  1491. func toDictionary() -> [String : Any] {
  1492. var result = [String : Any]()
  1493. guard !self.isEmpty else { return result }
  1494. guard let dataSelf = self.data(using: .utf8) else {
  1495. return result
  1496. }
  1497. if let dic = try? JSONSerialization.jsonObject(with: dataSelf,
  1498. options: .mutableContainers) as? [String : Any] {
  1499. result = dic
  1500. }
  1501. return result
  1502. }
  1503. //将原始的url编码为合法的url
  1504. func urlEncoded() -> String {
  1505. let encodeUrlString = self.addingPercentEncoding(withAllowedCharacters:
  1506. .urlQueryAllowed)
  1507. return encodeUrlString ?? ""
  1508. }
  1509. //将编码后的url转换回原始的url
  1510. func urlDecoded() -> String {
  1511. return self.removingPercentEncoding ?? ""
  1512. }
  1513. /// String使用下标截取字符串
  1514. /// string[index] 例如:"abcdefg"[3] // c
  1515. subscript (i:Int)->String{
  1516. let startIndex = self.index(self.startIndex, offsetBy: i)
  1517. let endIndex = self.index(startIndex, offsetBy: 1)
  1518. return String(self[startIndex..<endIndex])
  1519. }
  1520. /// String使用下标截取字符串
  1521. /// string[index..<index] 例如:"abcdefg"[3..<4] // d
  1522. subscript (r: Range<Int>) -> String {
  1523. get {
  1524. let startIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
  1525. let endIndex = self.index(self.startIndex, offsetBy: r.upperBound)
  1526. return String(self[startIndex..<endIndex])
  1527. }
  1528. }
  1529. /// String使用下标截取字符串
  1530. /// string[index,length] 例如:"abcdefg"[3,2] // de
  1531. subscript (index:Int , length:Int) -> String {
  1532. get {
  1533. let startIndex = self.index(self.startIndex, offsetBy: index)
  1534. let endIndex = self.index(startIndex, offsetBy: length)
  1535. return String(self[startIndex..<endIndex])
  1536. }
  1537. }
  1538. // 截取 从头到i位置
  1539. func substring(to:Int) -> String{
  1540. return self[0..<to]
  1541. }
  1542. // 截取 从i到尾部
  1543. func substring(from:Int) -> String{
  1544. return self[from..<self.count]
  1545. }
  1546. }