MainController.swift 73 KB

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