PQCommonMethodUtil.swift 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828
  1. //
  2. // PQCommonMethodUtil.swift
  3. // PQSpeed
  4. //
  5. // Created by lieyunye on 2020/5/29.
  6. // Copyright © 2020 BytesFlow. All rights reserved.
  7. //
  8. import AdSupport
  9. import Alamofire
  10. import Foundation
  11. import KeychainAccess
  12. import Kingfisher
  13. import KingfisherWebP
  14. import Photos
  15. import RealmSwift
  16. import Toast_Swift
  17. import NXFramework_Swift
  18. /// Home文件地址
  19. public let homeDirectory = NSHomeDirectory()
  20. /// docdocumens文件地址
  21. public let documensDirectory = homeDirectory + "/Documents"
  22. /// library文件地址
  23. public let libraryDirectory = homeDirectory + "/Library"
  24. /// 本地存储资源地址
  25. public let resourceDirectory = documensDirectory + "/Resource"
  26. /// 播放视频缓冲本地沙河目录
  27. public let videoCacheDirectory = resourceDirectory + "/VideoCache"
  28. /// 相册视频导出到本地沙河目录
  29. public let photoLibraryDirectory = resourceDirectory + "/PhotoLibrary/"
  30. /// 背景音乐导出到本地沙河目录
  31. public let bgMusicDirectory = resourceDirectory + "/BGMusic/"
  32. /// 网络视频素材下载到本地沙河目录
  33. public let downloadDirectory = resourceDirectory + "/Download/"
  34. /// 网络图片、GIF 素材下载到本地沙河目录
  35. public let downloadImagesDirectory = resourceDirectory + "/DownloadImages/"
  36. /// 临时缓存本地沙河目录地址
  37. public let tempDirectory = resourceDirectory + "/Temp/"
  38. /// 导出声音的本地沙盒目录v
  39. public let exportAudiosDirectory = resourceDirectory + "/ExportAudios/"
  40. /// 导出合成视频的本地沙盒目录
  41. public let exportVideosDirectory = resourceDirectory + "/ExportVideos/"
  42. // 版本构建号
  43. public let versionCode = "\(Bundle.main.infoDictionary?["CFBundleVersion"] ?? "1")"
  44. // 版本号
  45. public let versionName = "\(Bundle.main.infoDictionary?["CFBundleShortVersionString"] ?? "1.0.0")"
  46. /// 创建目录文件
  47. /// - Returns: <#description#>
  48. public func createDirectory(path: String) {
  49. let fileManager = FileManager.default
  50. if !fileManager.fileExists(atPath: path) {
  51. try? fileManager.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
  52. }
  53. }
  54. /// 判断文件夹是否存在
  55. /// - Parameter dicPath:文件夹 目录
  56. public func directoryIsExists(dicPath: String) -> Bool {
  57. BFLog(message: " dir path is: \(dicPath)")
  58. var directoryExists = ObjCBool(false)
  59. let fileExists = FileManager.default.fileExists(atPath: dicPath, isDirectory: &directoryExists)
  60. return fileExists && directoryExists.boolValue
  61. }
  62. /// 判断文件是否存在
  63. /// - Parameter filepath: 文件目录
  64. public func fileIsExists(filePath: String) -> Bool {
  65. BFLog(message: "file path is: \(filePath)")
  66. let fileExists = FileManager.default.fileExists(atPath: filePath)
  67. return fileExists
  68. }
  69. /// 创建沙河文件地址
  70. /// - Parameter url: 原地址
  71. /// - Returns: <#description#>
  72. public func createFilePath(url: String) -> Bool {
  73. let fileManager = FileManager.default
  74. if !fileManager.fileExists(atPath: url) {
  75. let isFinished = fileManager.createFile(atPath: url, contents: nil, attributes: nil)
  76. return isFinished
  77. }
  78. return true
  79. }
  80. public func cIPHONE_X() -> Bool {
  81. guard #available(iOS 11.0, *) else {
  82. return false
  83. }
  84. let isX = (UIApplication.shared.windows.first?.safeAreaInsets.bottom ?? 0) > 0
  85. return isX
  86. }
  87. /// 给按钮/imageView加载网络图片
  88. ///
  89. /// - Parameters:
  90. /// - url: 网络url
  91. /// - mainView: 需要加载的视图
  92. public func netImage(url: String, mainView: Any, placeholder: UIImage = UIImage.init().BF_Image(named: "placehold_image")) {
  93. if mainView is UIImageView {
  94. (mainView as! UIImageView).kf.setImage(with: URL(string: url), placeholder: placeholder, options: url.suffix(5) == ".webp" ? [.processor(WebPProcessor.default), .cacheSerializer(WebPSerializer.default)] : nil, progressBlock: { _, _ in
  95. }) { _, _, _, _ in
  96. }
  97. } else if mainView is UIButton {
  98. (mainView as! UIButton).kf.setImage(with: URL(string: url), for: .normal, placeholder: placeholder, options: url.suffix(5) == ".webp" ? [.processor(WebPProcessor.default), .cacheSerializer(WebPSerializer.default)] : nil, progressBlock: { _, _ in
  99. }) { _, _, _, _ in
  100. }
  101. }
  102. }
  103. /** 获取Kingfisher缓存的图片的data */
  104. public func kf_imageCacheData(originUrl: String) -> Data? {
  105. let diskCachePath = ImageCache.default.cachePath(forKey: originUrl)
  106. let data = try? Data(contentsOf: URL(fileURLWithPath: diskCachePath))
  107. return data
  108. }
  109. /** 获取Kingfisher缓存的图片 */
  110. public func kf_imageCacheImage(originUrl: String) -> UIImage? {
  111. return ImageCache.default.retrieveImageInDiskCache(forKey: originUrl, options: [.cacheOriginalImage])
  112. }
  113. /** 打印 */
  114. public func BFLog<T>(message: T) {
  115. // let logger = NXLogger.shared
  116. //
  117. // logger.level = .info
  118. // logger.ouput = .debuggerConsole
  119. //
  120. // logger.d(message as? String ?? "")
  121. }
  122. // MARK: 获取公共参数
  123. public func commonParams() -> [String: Any] {
  124. let model = UIDevice.current.model
  125. let systemName = UIDevice.current.systemName
  126. let systemVersion = UIDevice.current.systemVersion
  127. let localizedModel = UIDevice.current.localizedModel
  128. let machineInfo: [String: Any] = [
  129. "model": model, "system": systemName + " " + systemVersion, "brand": localizedModel, "platform": "iOS", "networkType": networkStatus(), "clientIp": ipAddress(),
  130. ]
  131. var commParams: [String: Any] = [
  132. "appVersionCode": versionCode,
  133. "versionCode": versionCode,
  134. "system": systemName + " " + systemVersion,
  135. "systemVersion": systemName + " " + systemVersion,
  136. "appType": "15",
  137. "appId": "1570572849",
  138. "machineCode": getMachineCode(),
  139. "networkType": networkStatus(),
  140. "ipAddress": ipAddress(),
  141. "clientTimestamp": Int64(Date().timeIntervalSince1970 * 1000),
  142. "platform": "iOS",
  143. "versionName": versionName,
  144. "sessionId": PQSingletoMemoryUtil.shared.sessionId,
  145. "subSessionId": PQSingletoMemoryUtil.shared.subSessionid ?? PQSingletoMemoryUtil.shared.sessionId,
  146. "mid": getMachineCode(),
  147. "machineInfo": dictionaryToJsonString(machineInfo) ?? "",
  148. "abInfoData": dictionaryToJsonString(PQSingletoMemoryUtil.shared.abInfoData) ?? "",
  149. "requestId": getUniqueId(desc: "requestId"),
  150. "idfa": ASIdentifierManager.shared().advertisingIdentifier.uuidString,
  151. "idfv": UIDevice.current.identifierForVendor?.uuidString ?? "",
  152. "deviceToken": PQSingletoMemoryUtil.shared.deviceToken,
  153. ]
  154. if BFLoginUserInfo.shared.accessToken.count > 0 {
  155. commParams["token"] = BFLoginUserInfo.shared.accessToken
  156. }
  157. if BFLoginUserInfo.shared.uid.count > 0 {
  158. commParams["loginUid"] = BFLoginUserInfo.shared.uid
  159. commParams["uid"] = BFLoginUserInfo.shared.uid
  160. }
  161. // showAlertVc(title: "公参", message: dictionaryToJsonString(commParams))
  162. return commParams
  163. }
  164. /// 获取网络状态
  165. /// - Returns: <#description#>
  166. public func networkStatus() -> String {
  167. let status = NetworkReachabilityManager(host: "www.baidu.com")?.networkReachabilityStatus
  168. var statusStr: String!
  169. switch status {
  170. case .unknown:
  171. statusStr = "NETWORK_UNKNOWN"
  172. case .notReachable:
  173. statusStr = "NETWORK_NO"
  174. case .reachable(.wwan):
  175. statusStr = "4G"
  176. case .reachable(.ethernetOrWiFi):
  177. statusStr = "Wi-Fi"
  178. default:
  179. statusStr = "NETWORK_UNKNOWN"
  180. }
  181. return statusStr
  182. }
  183. /// 判断是否有网
  184. /// - Returns: <#description#>
  185. public func isNetConnected() -> Bool {
  186. return NetworkReachabilityManager(host: "www.baidu.com")?.networkReachabilityStatus != .notReachable
  187. }
  188. /// 获取ip地址
  189. /// - Returns: <#description#>
  190. public func ipAddress() -> String {
  191. var addresses = [String]()
  192. var ifaddr: UnsafeMutablePointer<ifaddrs>?
  193. if getifaddrs(&ifaddr) == 0 {
  194. var ptr = ifaddr
  195. while ptr != nil {
  196. let flags = Int32(ptr!.pointee.ifa_flags)
  197. var addr = ptr!.pointee.ifa_addr.pointee
  198. if (flags & (IFF_UP | IFF_RUNNING | IFF_LOOPBACK)) == (IFF_UP | IFF_RUNNING) {
  199. if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
  200. var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
  201. if getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST) == 0 {
  202. if let address = String(validatingUTF8: hostname) {
  203. addresses.append(address)
  204. }
  205. }
  206. }
  207. }
  208. ptr = ptr!.pointee.ifa_next
  209. }
  210. freeifaddrs(ifaddr)
  211. }
  212. return addresses.first ?? "0.0.0.0"
  213. }
  214. /// 生成唯一ID / 分享跟冷启动
  215. /// - Parameter desc: <#desc description#>
  216. /// - Returns: <#description#>
  217. public func getUniqueId(desc: String) -> String {
  218. let timeStr: String = "\(Date().timeIntervalSince1970)"
  219. let uuid: String = getMachineCode()
  220. let code: String = "\(arc4random_uniform(1_000_000_000))"
  221. let uniqueId = (timeStr + desc + uuid + code).kf.md5.kf.md5
  222. BFLog(message: "生成唯一码:desc = \(desc),timeStr = \(timeStr),uuid = \(uuid),code = \(code),uniqueId = \(uniqueId)")
  223. return uniqueId
  224. }
  225. // MARK: 字典转字符串
  226. public func dictionaryToJsonString(_ dic: [String: Any]) -> String? {
  227. BFLog(message: "dictionaryToJsonString = \(dic)")
  228. if !JSONSerialization.isValidJSONObject(dic) {
  229. return ""
  230. }
  231. guard let data = try? JSONSerialization.data(withJSONObject: dic, options: []) else {
  232. return ""
  233. }
  234. BFLog(message: "dictionaryToJsonString - data = \(data)")
  235. let str = String(data: data, encoding: String.Encoding.utf8)
  236. BFLog(message: "dictionaryToJsonString - str = \(String(describing: str))")
  237. return str
  238. }
  239. // MARK: 字符串转字典
  240. public func jsonStringToDictionary(_ str: String) -> [String: Any]? {
  241. let data = str.data(using: String.Encoding.utf8)
  242. if data == nil {
  243. return [:]
  244. }
  245. if let dict = try? JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any] {
  246. return dict
  247. }
  248. return [:]
  249. }
  250. // MARK: 字符串转数组
  251. public func jsonStringToArray(_ str: String) -> [[String: String]]? {
  252. let data = str.data(using: String.Encoding.utf8)
  253. if let array = try? JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [[String: String]] {
  254. return array
  255. }
  256. return nil
  257. }
  258. /// 数组转为string
  259. /// - Parameter array: <#array description#>
  260. /// - Returns: <#description#>
  261. public func arrayToJsonString(_ array: [Any]) -> String {
  262. if !JSONSerialization.isValidJSONObject(array) {
  263. BFLog(message: "无法解析String")
  264. return ""
  265. }
  266. let data: NSData! = try? JSONSerialization.data(withJSONObject: array, options: []) as NSData?
  267. let JSONString = NSString(data: data as Data, encoding: String.Encoding.utf8.rawValue)
  268. return JSONString! as String
  269. }
  270. /// jsonString转为数组
  271. /// - Parameter jsonString: <#jsonString description#>
  272. /// - Returns: <#description#>
  273. public func jsonStringToArray(jsonString: String) -> [Any]? {
  274. let data = jsonString.data(using: String.Encoding.utf8)
  275. if data == nil {
  276. return nil
  277. }
  278. if let array = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [Any] {
  279. return array
  280. }
  281. return nil
  282. }
  283. /// 计算字符串大小
  284. /// - Parameters:
  285. /// - text: <#text description#>
  286. /// - font: <#font description#>
  287. /// - size: <#size description#>
  288. /// - Returns: <#description#>
  289. public func sizeWithText(text: String, font: UIFont, size: CGSize) -> CGSize {
  290. let attributes = [NSAttributedString.Key.font: font]
  291. let option = NSStringDrawingOptions.usesLineFragmentOrigin
  292. let rect: CGRect = text.boundingRect(with: size, options: option, attributes: attributes, context: nil)
  293. return rect.size
  294. }
  295. /// 根据行数计算字符串大小
  296. /// - Parameters:
  297. /// - text: <#text description#>
  298. /// - numberOfLines: <#numberOfLines description#>
  299. /// - font: <#font description#>
  300. /// - maxSize: <#maxSize description#>
  301. /// - Returns: <#description#>
  302. public func sizeTextFits(attributedText: NSMutableAttributedString?, text: String?, numberOfLines: Int, font: UIFont, maxSize: CGSize) -> CGSize {
  303. var newSize: CGSize = CGSize(width: 0, height: 0)
  304. let label = UILabel(frame: CGRect.zero)
  305. label.font = font
  306. label.numberOfLines = numberOfLines
  307. if attributedText != nil {
  308. label.attributedText = attributedText
  309. } else {
  310. label.text = text
  311. }
  312. newSize = label.sizeThatFits(maxSize)
  313. return newSize
  314. }
  315. public func textNumberOfLines(text: String, font: UIFont, maxSize _: CGSize) -> Int {
  316. let label = UILabel(frame: CGRect.zero)
  317. label.font = font
  318. label.numberOfLines = 0
  319. label.text = text
  320. return label.numberOfLines
  321. }
  322. /// 生成渐变色
  323. /// - Parameters:
  324. /// - size: <#size description#>
  325. /// - endPoint: <#endPoint description#>
  326. /// - startColor: <#startColor description#>
  327. /// - endColor: <#endColor description#>
  328. /// - Returns: <#description#>
  329. public func gradientColor(size: CGSize, endPoint: CGPoint, startColor: UIColor, endColor: UIColor) -> UIColor {
  330. let gradientLayer = CAGradientLayer()
  331. gradientLayer.frame = CGRect(origin: CGPoint(), size: size)
  332. gradientLayer.startPoint = CGPoint.zero
  333. gradientLayer.endPoint = endPoint
  334. gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
  335. UIGraphicsBeginImageContext(size)
  336. gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
  337. let image = UIGraphicsGetImageFromCurrentImageContext()!
  338. return UIColor(patternImage: image)
  339. }
  340. /// 获取设备ID
  341. /// - Returns: <#description#>
  342. public func getMachineCode() -> String {
  343. let userInfo: [String: Any]? = jsonStringToDictionary(UserDefaults.standard.string(forKey: cUserInfoStorageKey) ?? "")
  344. if userInfo != nil && ((userInfo?.keys.contains("isVirtualUser") ?? false) && !(userInfo?["isVirtualUser"] is NSNull) && ((userInfo?["isVirtualUser"] as? Bool) ?? false)) && ((userInfo?.keys.contains("mid") ?? false) && !(userInfo?["mid"] is NSNull)) {
  345. BFLog(message: "虚拟账号mid:\("\(userInfo?["mid"] ?? "")")")
  346. return "\(userInfo?["mid"] ?? "")"
  347. }
  348. let keychain = Keychain(service: "com.piaoquan.pqspeed")
  349. var uuid: String = keychain["machineCode"] ?? ""
  350. if uuid.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
  351. uuid = NSUUID().uuidString
  352. keychain["machineCode"] = uuid
  353. }
  354. BFLog(message: "正式账号mid:\(uuid)")
  355. return uuid
  356. }
  357. /// 显示加载中视图
  358. /// - Parameters:
  359. /// - superView: <#superView description#>
  360. /// - msg: <#msg description#>
  361. /// - Returns: <#description#>
  362. public func cShowHUB(superView: UIView?, msg: String?) {
  363. DispatchQueue.main.async {
  364. if superView == nil {
  365. if msg == nil {
  366. UIApplication.shared.keyWindow?.makeToastActivity(.center)
  367. } else {
  368. UIApplication.shared.keyWindow?.makeToast(msg, duration: 3.0, position: .center)
  369. }
  370. } else {
  371. if msg == nil {
  372. superView!.makeToastActivity(.center)
  373. } else {
  374. superView!.makeToast(msg, duration: 3.0, position: .center)
  375. }
  376. }
  377. }
  378. }
  379. /// 隐藏加载中视图
  380. /// - Parameter superView: <#superView description#>
  381. /// - Returns: <#description#>
  382. public func cHiddenHUB(superView: UIView?) {
  383. DispatchQueue.main.async {
  384. if superView == nil {
  385. UIApplication.shared.keyWindow?.hideAllToasts()
  386. UIApplication.shared.keyWindow?.hideToastActivity()
  387. } else {
  388. superView!.hideAllToasts()
  389. superView?.hideToastActivity()
  390. }
  391. }
  392. }
  393. /// 获取存储值
  394. /// - Parameter key: key description
  395. /// - Returns: description
  396. public func getUserDefaults(key: String) -> Any? {
  397. return UserDefaults.standard.object(forKey: key)
  398. }
  399. /// 存储数据
  400. /// - Parameters:
  401. /// - key: key description
  402. /// - value: value description
  403. /// - Returns: description
  404. public func saveUserDefaults(key: String, value: String) {
  405. UserDefaults.standard.set(value, forKey: key)
  406. UserDefaults.standard.synchronize()
  407. }
  408. /// 存储数据带版本号
  409. /// - Parameters:
  410. /// - key: <#key description#>
  411. /// - value: <#value description#>
  412. public func saveUserDefaultsToJson(key: String, value: Any) {
  413. UserDefaults.standard.set(dictionaryToJsonString([key: value, "appVersionCode": versionCode, "versionName": versionName]), forKey: key)
  414. UserDefaults.standard.synchronize()
  415. }
  416. /// 获取数据带版本号
  417. /// - Parameter key: <#key description#>
  418. /// - Returns: <#description#>
  419. public func getUserDefaultsForJson(key: String) -> Any? {
  420. let jsonStr = UserDefaults.standard.object(forKey: key)
  421. if jsonStr != nil {
  422. return jsonStringToDictionary(jsonStr as! String)?[key]
  423. }
  424. return UserDefaults.standard.object(forKey: key)
  425. }
  426. /// 清空数据
  427. /// - Parameters:
  428. /// - key: key description
  429. /// - value: value description
  430. /// - Returns: description
  431. public func removeUserDefaults(key: String) {
  432. UserDefaults.standard.removeObject(forKey: key)
  433. UserDefaults.standard.synchronize()
  434. }
  435. /// 存储数据
  436. /// - Parameters:
  437. /// - key: key description
  438. /// - value: value description
  439. /// - Returns: description
  440. public func saveUserDefaults(key: String, value: Any) {
  441. UserDefaults.standard.set(value, forKey: key)
  442. UserDefaults.standard.synchronize()
  443. }
  444. /// 保存自定义model as NSArray 当 OBJ 是数组时不能使用 Array 要使用 NSArray
  445. /// - Parameter object: <#object description#>
  446. /// - Parameter key: <#key description#>
  447. public func saveCustomObject(customObject object: NSCoding, key: String) {
  448. let encodedObject = NSKeyedArchiver.archivedData(withRootObject: object)
  449. UserDefaults.standard.set(encodedObject, forKey: key)
  450. UserDefaults.standard.synchronize()
  451. BFLog(message: "保存自定义类成功 key is \(key) \(encodedObject.count)")
  452. }
  453. /// 取自定义model
  454. /// - Parameter key: <#key description#>
  455. public func getCustomObject(forKey key: String) -> AnyObject? {
  456. let decodedObject = UserDefaults.standard.object(forKey: key) as? Data
  457. if decodedObject == nil {
  458. BFLog(message: "key is \(key) decodedObject is nil")
  459. }
  460. if let decoded = decodedObject {
  461. let object = NSKeyedUnarchiver.unarchiveObject(with: decoded as Data)
  462. return object as AnyObject?
  463. }
  464. return nil
  465. }
  466. /// 添加通知
  467. /// - Parameters:
  468. /// - observer: <#observer description#>
  469. /// - aSelectorName: <#aSelectorName description#>
  470. /// - aName: <#aName description#>
  471. /// - anObject: <#anObject description#>
  472. /// - Returns: <#description#>
  473. public func addNotification(_ observer: Any, selector aSelectorName: Selector, name aName: String, object anObject: Any?) {
  474. PQNotification.addObserver(observer, selector: aSelectorName, name: NSNotification.Name(rawValue: aName), object: anObject)
  475. }
  476. /// 发送通知
  477. /// - Parameter aName: <#aName description#>
  478. /// - Returns: <#description#>
  479. public func postNotification(name aName: String, userInfo: [AnyHashable: Any]? = nil) {
  480. PQNotification.post(name: NSNotification.Name(aName), object: nil, userInfo: userInfo)
  481. }
  482. /// 获取是否打开推送
  483. /// - Parameter completeHander: <#completeHander description#>
  484. /// - Returns: <#description#>
  485. public func pushNotificationIsOpen(completeHander: ((_ isOpen: Bool) -> Void)?) {
  486. if #available(iOS 10.0, *) {
  487. UNUserNotificationCenter.current().getNotificationSettings { setttings in
  488. completeHander!(setttings.authorizationStatus == .authorized)
  489. }
  490. } else {
  491. completeHander!(UIApplication.shared.currentUserNotificationSettings?.types.contains(UIUserNotificationType.alert) ?? false)
  492. }
  493. }
  494. /// 发送上传本地推送
  495. /// - Parameter isSuccess: 是否上传成功
  496. /// - Returns: <#description#>
  497. public func sendUploadNotification(isSuccess: Bool) {
  498. let title: String = isSuccess ? "上传完成了!" : "上传失败了!"
  499. let body: String = isSuccess ? "请点击发布,完成上传。否则,您的视频可能丢失" : "快来看看怎么了?"
  500. sendLocalNotification(title: title, body: body)
  501. }
  502. /// 发送本地推送
  503. /// - Parameters:
  504. /// - title: 标题
  505. /// - body: 内容
  506. /// - Returns: <#description#>
  507. public func sendLocalNotification(title: String, body: String) {
  508. // 设置推送内容
  509. if #available(iOS 10.0, *) {
  510. let content = UNMutableNotificationContent()
  511. content.title = title
  512. content.body = body
  513. content.badge = 1
  514. // 设置通知触发器
  515. let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
  516. // 设置请求标识符
  517. let requestIdentifier = getUniqueId(desc: "notification\(title)")
  518. // 设置一个通知请求
  519. let request = UNNotificationRequest(identifier: requestIdentifier,
  520. content: content, trigger: trigger)
  521. // 将通知请求添加到发送中心
  522. UNUserNotificationCenter.current().add(request) { error in
  523. if error == nil {
  524. print("Time Interval Notification scheduled: \(requestIdentifier)")
  525. }
  526. }
  527. } else {
  528. // Fallback on earlier versions
  529. let notification = UILocalNotification()
  530. notification.alertBody = body
  531. notification.alertTitle = title
  532. notification.applicationIconBadgeNumber = 1
  533. notification.fireDate = Date(timeIntervalSinceNow: 0)
  534. UIApplication.shared.scheduledLocalNotifications = [notification]
  535. }
  536. }
  537. /// 打开应用设置
  538. public func openAppSetting() {
  539. if UIApplication.shared.canOpenURL(URL(string: UIApplication.openSettingsURLString)!) {
  540. UIApplication.shared.openURL(URL(string: UIApplication.openSettingsURLString)!)
  541. }
  542. }
  543. /// dns解析
  544. /// - Parameter hostUrl: speed.piaoquantv.com /
  545. /// - Returns: <#description#>
  546. public func parseDNS(hostUrl: String) -> [String: Any]? {
  547. let host: CFHost? = CFHostCreateWithName(nil, hostUrl as CFString).takeRetainedValue()
  548. let start = CFAbsoluteTimeGetCurrent()
  549. var success: DarwinBoolean = false
  550. var addressList: [String] = Array<String>.init()
  551. var addresses: NSArray?
  552. if CFHostStartInfoResolution(host!, .addresses, nil) {
  553. addresses = (CFHostGetAddressing(host!, &success)?.takeUnretainedValue())
  554. }
  555. if success == true {
  556. for case let theAddress as NSData in addresses! {
  557. var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
  558. if getnameinfo(theAddress.bytes.assumingMemoryBound(to: sockaddr.self), socklen_t(theAddress.length),
  559. &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0
  560. {
  561. let numAddress = String(cString: hostname)
  562. addressList.append("\(hostUrl)/\(numAddress)")
  563. }
  564. }
  565. }
  566. let end = CFAbsoluteTimeGetCurrent()
  567. let duration = end - start
  568. BFLog(message: "duration = \(duration)")
  569. BFLog(message: "addressList = \(addressList)")
  570. if addressList.count > 0 {
  571. return ["dnsResult": arrayToJsonString(addressList), "duration": duration * 1000, "hostName": hostUrl, "networkType": networkStatus()]
  572. } else {
  573. return nil
  574. }
  575. }
  576. /// 获取当前日期
  577. /// - Returns: <#description#>
  578. public func systemCurrentDate() -> String {
  579. let dateFormatter = DateFormatter()
  580. dateFormatter.dateFormat = "YYYY-MM-dd"
  581. return dateFormatter.string(from: Date())
  582. }
  583. /// 时间戳转日期
  584. /// - Parameter timeInterval: <#timeInterval description#>
  585. /// - Returns: <#description#>
  586. public func timeIntervalToDateString(timeInterval: TimeInterval) -> String {
  587. let date = Date(timeIntervalSince1970: timeInterval)
  588. let dateFormatter = DateFormatter()
  589. dateFormatter.dateFormat = "MM月dd日 HH:mm"
  590. return dateFormatter.string(from: date)
  591. }
  592. /// 判断字符串或者字典是否为空
  593. /// - Parameter object: <#object description#>
  594. /// - Returns: <#description#>
  595. public func isEmpty(object: Any?) -> Bool {
  596. if object == nil {
  597. return true
  598. }
  599. if object is String {
  600. return (object as! String).count <= 0
  601. }
  602. if object is [String: Any] {
  603. return (object as! [String: Any]).keys.count <= 0
  604. }
  605. return false
  606. }
  607. public func isEmptyObject(object: Any?) -> Bool {
  608. if object == nil {
  609. return true
  610. }
  611. if object is String {
  612. return object == nil || ((object as? String)?.count ?? 0) <= 0
  613. }
  614. if object is [String: Any] {
  615. return object == nil || ((object as? [String: Any])?.keys.count ?? 0) <= 0
  616. }
  617. if object is List<Object> {
  618. return object == nil || ((object as? List<Object>)?.count ?? 0) <= 0
  619. }
  620. return false
  621. }
  622. /// <#Description#>
  623. /// - Parameter string: <#string description#>
  624. /// - Returns: <#description#>
  625. public func isIncludeChineseIn(string: String) -> Bool {
  626. for (_, value) in string.enumerated() {
  627. if value >= "\u{4E00}", value <= "\u{9FA5}" {
  628. return true
  629. }
  630. }
  631. return false
  632. }
  633. /// 获取文件内容的MD5
  634. /// - Parameters:
  635. /// - path: 地址
  636. /// - data: data
  637. /// - Returns: <#description#>
  638. public func contentMD5(path: String? = nil, data _: Data? = nil) -> String? {
  639. if path == nil || (path?.count ?? 0) <= 0 || !FileManager.default.fileExists(atPath: path ?? "") {
  640. BFLog(message: "生成内容md5值:地址错误或者不存在\(String(describing: path))")
  641. return ""
  642. }
  643. let att = try? FileManager.default.attributesOfItem(atPath: path ?? "")
  644. let size = Int64(att?[FileAttributeKey.size] as! UInt64)
  645. if size <= 0 {
  646. BFLog(message: "生成内容md5值:文件大小为0\(size)")
  647. return ""
  648. }
  649. let hash: String = OSSUtil.base64Md5(forFilePath: path)
  650. BFLog(message: "生成内容md5值:contentMD5 = \(hash)")
  651. return hash
  652. // let ctxLen = MemoryLayout<CC_MD5_CTX>.size
  653. // let ctx = UnsafeMutablePointer<CC_MD5_CTX>.allocate(capacity: ctxLen)
  654. // CC_MD5_Init(ctx)
  655. // if path != nil {
  656. // let handle = FileHandle(forReadingAtPath: path!)
  657. // if handle == nil {
  658. // return nil
  659. // }
  660. // var done = false
  661. // while !done {
  662. // let fileData = handle?.readData(ofLength: 256)
  663. // fileData?.withUnsafeBytes { (bytes: UnsafePointer<CChar>) -> Void in
  664. // CC_MD5_Update(ctx, bytes, CC_LONG(fileData!.count))
  665. // }
  666. //
  667. // if fileData?.count == 0 {
  668. // done = true
  669. // }
  670. // }
  671. // } else if path == nil && data != nil {
  672. // let fileData = data
  673. // fileData?.withUnsafeBytes { (bytes: UnsafePointer<CChar>) -> Void in
  674. // CC_MD5_Update(ctx, bytes, CC_LONG(fileData!.count))
  675. // }
  676. // } else {
  677. // return nil
  678. // }
  679. // // unsigned char digest[CC_MD5_DIGEST_LENGTH];
  680. // let digestLen = Int(CC_MD5_DIGEST_LENGTH)
  681. // let digest = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
  682. // CC_MD5_Final(digest, ctx)
  683. //
  684. // var hash = ""
  685. // for i in 0 ..< digestLen {
  686. // hash += String(format: "%02x", (digest[i]))
  687. // }
  688. // digest.deinitialize(count: digestLen)
  689. // ctx.deinitialize(count: ctxLen)
  690. }
  691. /// 自适应宽
  692. /// - Parameters:
  693. /// - width: <#width description#>
  694. /// - baseWidth: <#baseWidth description#>
  695. /// - Returns: <#description#>
  696. public func adapterWidth(width: CGFloat, baseWidth: CGFloat = 375) -> CGFloat {
  697. return width / baseWidth * cScreenWidth
  698. }
  699. /// 自适应高
  700. /// - Parameters:
  701. /// - height: <#height description#>
  702. /// - baseHeight: <#baseHeight description#>
  703. /// - Returns: <#description#>
  704. public func adapterHeight(height: CGFloat, baseHeight: CGFloat = 812) -> CGFloat {
  705. return height / baseHeight * cScreenHeigth
  706. }
  707. /// 检测URL
  708. /// - Parameter url: <#url description#>
  709. /// - Returns: <#description#>
  710. public func isValidURL(url: String?) -> Bool {
  711. if url == nil || (url?.count ?? 0) <= 4 || (!(url?.hasPrefix("http") ?? false) && !(url?.hasPrefix("https") ?? false)) {
  712. return false
  713. }
  714. return true
  715. }
  716. /// 相册数据按创建时间排序
  717. var creaFetchOptions: PHFetchOptions = {
  718. let fetchOptions = PHFetchOptions()
  719. fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
  720. return fetchOptions
  721. }()
  722. /// 相册数据按修改时间排序
  723. var modiFetchOptions: PHFetchOptions = {
  724. let fetchOptions = PHFetchOptions()
  725. fetchOptions.sortDescriptors = [NSSortDescriptor(key: "modificationDate", ascending: false)]
  726. return fetchOptions
  727. }()
  728. /// 获取本地素材
  729. var avAssertOptions: [String: Any]? = {
  730. [AVURLAssetPreferPreciseDurationAndTimingKey: NSNumber(value: true)]
  731. }()
  732. /// 播放动画图
  733. var playGifImages: [UIImage] = {
  734. var gifImages = Array<UIImage>.init()
  735. for i in 0 ... 44 {
  736. gifImages.append(UIImage(named: "\(i).png")!)
  737. }
  738. return gifImages
  739. }()
  740. /// 压缩图片
  741. /// - Parameter image: <#image description#>
  742. /// -
  743. /// - Returns: <#description#>
  744. public func zipImage(image: UIImage?, size: Int) -> Data? {
  745. var data = image?.pngData()
  746. var dataKBytes = Int(data?.count ?? 0) / 1000
  747. var maxQuality = 0.9
  748. while dataKBytes > size, maxQuality > 0.01 {
  749. maxQuality = maxQuality - 0.01
  750. data = image?.jpegData(compressionQuality: CGFloat(maxQuality))
  751. dataKBytes = (data?.count ?? 0) / 1000
  752. }
  753. return data
  754. }