|
@@ -1,844 +0,0 @@
|
|
-//
|
|
|
|
-// PQCommonMethodUtil.swift
|
|
|
|
-// PQSpeed
|
|
|
|
-//
|
|
|
|
-// Created by lieyunye on 2020/5/29.
|
|
|
|
-// Copyright © 2020 BytesFlow. All rights reserved.
|
|
|
|
-//
|
|
|
|
-
|
|
|
|
-import AdSupport
|
|
|
|
-import Alamofire
|
|
|
|
-import Foundation
|
|
|
|
-import KeychainAccess
|
|
|
|
-import Kingfisher
|
|
|
|
-import KingfisherWebP
|
|
|
|
-import Photos
|
|
|
|
-import RealmSwift
|
|
|
|
-import Toast_Swift
|
|
|
|
-
|
|
|
|
-/// Home文件地址
|
|
|
|
-public let homeDirectory = NSHomeDirectory()
|
|
|
|
-/// docdocumens文件地址
|
|
|
|
-public let documensDirectory = homeDirectory + "/Documents"
|
|
|
|
-/// library文件地址
|
|
|
|
-public let libraryDirectory = homeDirectory + "/Library"
|
|
|
|
-
|
|
|
|
-/// 本地存储资源地址
|
|
|
|
-public let resourceDirectory = documensDirectory + "/Resource"
|
|
|
|
-/// 播放视频缓冲本地沙河目录
|
|
|
|
-public let videoCacheDirectory = resourceDirectory + "/VideoCache"
|
|
|
|
-/// 相册视频导出到本地沙河目录
|
|
|
|
-public let photoLibraryDirectory = resourceDirectory + "/PhotoLibrary/"
|
|
|
|
-/// 背景音乐导出到本地沙河目录
|
|
|
|
-public let bgMusicDirectory = resourceDirectory + "/BGMusic/"
|
|
|
|
-/// 网络视频素材下载到本地沙河目录
|
|
|
|
-public let downloadDirectory = resourceDirectory + "/Download/"
|
|
|
|
-/// 网络图片、GIF 素材下载到本地沙河目录
|
|
|
|
-public let downloadImagesDirectory = resourceDirectory + "/DownloadImages/"
|
|
|
|
-/// 临时缓存本地沙河目录地址
|
|
|
|
-public let tempDirectory = resourceDirectory + "/Temp/"
|
|
|
|
-/// 导出声音的本地沙盒目录v
|
|
|
|
-public let exportAudiosDirectory = resourceDirectory + "/ExportAudios/"
|
|
|
|
-/// 导出合成视频的本地沙盒目录
|
|
|
|
-public let exportVideosDirectory = resourceDirectory + "/ExportVideos/"
|
|
|
|
-// 版本构建号
|
|
|
|
-public let versionCode = "\(Bundle.main.infoDictionary?["CFBundleVersion"] ?? "1")"
|
|
|
|
-// 版本号
|
|
|
|
-public let versionName = "\(Bundle.main.infoDictionary?["CFBundleShortVersionString"] ?? "1.0.0")"
|
|
|
|
-/// 创建目录文件
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func createDirectory(path: String) {
|
|
|
|
- let fileManager = FileManager.default
|
|
|
|
- if !fileManager.fileExists(atPath: path) {
|
|
|
|
- try? fileManager.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 判断文件夹是否存在
|
|
|
|
-/// - Parameter dicPath:文件夹 目录
|
|
|
|
-public func directoryIsExists(dicPath: String) -> Bool {
|
|
|
|
- BFLog(message: " dir path is: \(dicPath)")
|
|
|
|
- var directoryExists = ObjCBool(false)
|
|
|
|
- let fileExists = FileManager.default.fileExists(atPath: dicPath, isDirectory: &directoryExists)
|
|
|
|
- return fileExists && directoryExists.boolValue
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 判断文件是否存在
|
|
|
|
-/// - Parameter filepath: 文件目录
|
|
|
|
-public func fileIsExists(filePath: String) -> Bool {
|
|
|
|
- BFLog(message: "file path is: \(filePath)")
|
|
|
|
-
|
|
|
|
- let fileExists = FileManager.default.fileExists(atPath: filePath)
|
|
|
|
- return fileExists
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 创建沙河文件地址
|
|
|
|
-/// - Parameter url: 原地址
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func createFilePath(url: String) -> Bool {
|
|
|
|
- let fileManager = FileManager.default
|
|
|
|
- if !fileManager.fileExists(atPath: url) {
|
|
|
|
- let isFinished = fileManager.createFile(atPath: url, contents: nil, attributes: nil)
|
|
|
|
- return isFinished
|
|
|
|
- }
|
|
|
|
- return true
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-public func cIPHONE_X() -> Bool {
|
|
|
|
- guard #available(iOS 11.0, *) else {
|
|
|
|
- return false
|
|
|
|
- }
|
|
|
|
- let isX = (UIApplication.shared.windows.first?.safeAreaInsets.bottom ?? 0) > 0
|
|
|
|
- return isX
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 给按钮/imageView加载网络图片
|
|
|
|
-///
|
|
|
|
-/// - Parameters:
|
|
|
|
-/// - url: 网络url
|
|
|
|
-/// - mainView: 需要加载的视图
|
|
|
|
-public func netImage(url: String, mainView: Any, placeholder: UIImage = UIImage.init().BF_Image(named: "placehold_image")) {
|
|
|
|
- if mainView is UIImageView {
|
|
|
|
- (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
|
|
|
|
-
|
|
|
|
- }) { _ in
|
|
|
|
- }
|
|
|
|
- } else if mainView is UIButton {
|
|
|
|
- (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
|
|
|
|
-
|
|
|
|
- }) { _ in
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/** 获取Kingfisher缓存的图片的data */
|
|
|
|
-public func kf_imageCacheData(originUrl: String) -> Data? {
|
|
|
|
- let diskCachePath = ImageCache.default.cachePath(forKey: originUrl)
|
|
|
|
- let data = try? Data(contentsOf: URL(fileURLWithPath: diskCachePath))
|
|
|
|
- return data
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/** 获取Kingfisher缓存的图片 */
|
|
|
|
-public func kf_imageCacheImage(originUrl: String, completeHandle: @escaping (_ image: UIImage?, _ error: Error?) -> Void) {
|
|
|
|
-
|
|
|
|
- ImageCache.default.retrieveImageInDiskCache(forKey: originUrl, options: [.cacheOriginalImage]) { result in
|
|
|
|
- DispatchQueue.main.async {
|
|
|
|
- switch result {
|
|
|
|
- case let .success(image):
|
|
|
|
- completeHandle(image, nil)
|
|
|
|
- case let .failure(error):
|
|
|
|
- completeHandle(nil, error)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/** 打印
|
|
|
|
- type = 1 : 胡志强
|
|
|
|
- type = 2 :王成
|
|
|
|
- type = 3 : 文伟伟
|
|
|
|
-
|
|
|
|
- */
|
|
|
|
-public func BFLog<T>( _ type : Int = 0, _ file:String = #file, _ line:Int = #line, message: T) {
|
|
|
|
-
|
|
|
|
- let file = (file as NSString).lastPathComponent;
|
|
|
|
- let msg = "\(file) (L:\(line)) \(message)"
|
|
|
|
- if type == 0{
|
|
|
|
- BuglyLog.level(.warn, logs: msg)
|
|
|
|
- }
|
|
|
|
-#if DEBUG
|
|
|
|
- let dateFmt = DateFormatter()
|
|
|
|
- dateFmt.dateFormat = "HH:mm:ss:SSSS"
|
|
|
|
- if type == 1 {
|
|
|
|
- print("hhz-\(dateFmt.string(from: Date())) \(msg)");
|
|
|
|
- }else if type == 2 {
|
|
|
|
- print("ak-\(dateFmt.string(from: Date())) \(msg)");
|
|
|
|
- }else if type == 3 {
|
|
|
|
- print("ww-\(dateFmt.string(from: Date())) \(msg)");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// MARK: 获取公共参数
|
|
|
|
-
|
|
|
|
-public func commonParams() -> [String: Any] {
|
|
|
|
- let model = UIDevice.current.model
|
|
|
|
- let systemName = UIDevice.current.systemName
|
|
|
|
- let systemVersion = UIDevice.current.systemVersion
|
|
|
|
- let localizedModel = UIDevice.current.localizedModel
|
|
|
|
- let machineInfo: [String: Any] = [
|
|
|
|
- "model": model, "system": systemName + " " + systemVersion, "brand": localizedModel, "platform": "iOS", "networkType": networkStatus(), "clientIp": ipAddress(),
|
|
|
|
- ]
|
|
|
|
- var commParams: [String: Any] = [
|
|
|
|
- "appVersionCode": versionCode,
|
|
|
|
- "versionCode": versionCode,
|
|
|
|
- "system": systemName + " " + systemVersion,
|
|
|
|
- "systemVersion": systemName + " " + systemVersion,
|
|
|
|
- "appType": PQBFConfig.shared.appType,
|
|
|
|
- "appId": PQBFConfig.shared.appId,
|
|
|
|
- "machineCode": getMachineCode(),
|
|
|
|
- "networkType": networkStatus(),
|
|
|
|
- "ipAddress": ipAddress(),
|
|
|
|
- "clientTimestamp": Int64(Date().timeIntervalSince1970 * 1000),
|
|
|
|
- "platform": "iOS",
|
|
|
|
- "versionName": versionName,
|
|
|
|
- "sessionId": PQSingletoMemoryUtil.shared.sessionId,
|
|
|
|
- "subSessionId": PQSingletoMemoryUtil.shared.subSessionid ?? PQSingletoMemoryUtil.shared.sessionId,
|
|
|
|
- "mid": getMachineCode(),
|
|
|
|
- "machineInfo": dictionaryToJsonString(machineInfo) ?? "",
|
|
|
|
- "abInfoData": dictionaryToJsonString(PQSingletoMemoryUtil.shared.abInfoData) ?? "",
|
|
|
|
- "requestId": getUniqueId(desc: "requestId"),
|
|
|
|
- "idfa": ASIdentifierManager.shared().advertisingIdentifier.uuidString,
|
|
|
|
- "idfv": UIDevice.current.identifierForVendor?.uuidString ?? "",
|
|
|
|
- "deviceToken": PQSingletoMemoryUtil.shared.deviceToken,
|
|
|
|
- ]
|
|
|
|
- if BFLoginUserInfo.shared.accessToken.count > 0 {
|
|
|
|
- commParams["token"] = BFLoginUserInfo.shared.accessToken
|
|
|
|
- }
|
|
|
|
- if BFLoginUserInfo.shared.uid.count > 0 {
|
|
|
|
- commParams["loginUid"] = BFLoginUserInfo.shared.uid
|
|
|
|
- commParams["uid"] = BFLoginUserInfo.shared.uid
|
|
|
|
- }
|
|
|
|
-// showAlertVc(title: "公参", message: dictionaryToJsonString(commParams))
|
|
|
|
- return commParams
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 获取网络状态
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func networkStatus() -> String {
|
|
|
|
- let status = NetworkReachabilityManager(host: "www.baidu.com")?.status
|
|
|
|
- var statusStr: String!
|
|
|
|
-
|
|
|
|
- switch status {
|
|
|
|
- case .unknown:
|
|
|
|
- statusStr = "NETWORK_UNKNOWN"
|
|
|
|
- case .notReachable:
|
|
|
|
- statusStr = "NETWORK_NO"
|
|
|
|
- case .reachable(.cellular):
|
|
|
|
- statusStr = "4G"
|
|
|
|
- case .reachable(.ethernetOrWiFi):
|
|
|
|
- statusStr = "Wi-Fi"
|
|
|
|
- default:
|
|
|
|
- statusStr = "NETWORK_UNKNOWN"
|
|
|
|
- }
|
|
|
|
- return statusStr
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 判断是否有网
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func isNetConnected() -> Bool {
|
|
|
|
- return NetworkReachabilityManager(host: "www.baidu.com")?.status != .notReachable
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 获取ip地址
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func ipAddress() -> String {
|
|
|
|
- var addresses = [String]()
|
|
|
|
- var ifaddr: UnsafeMutablePointer<ifaddrs>?
|
|
|
|
- if getifaddrs(&ifaddr) == 0 {
|
|
|
|
- var ptr = ifaddr
|
|
|
|
- while ptr != nil {
|
|
|
|
- let flags = Int32(ptr!.pointee.ifa_flags)
|
|
|
|
- var addr = ptr!.pointee.ifa_addr.pointee
|
|
|
|
- if (flags & (IFF_UP | IFF_RUNNING | IFF_LOOPBACK)) == (IFF_UP | IFF_RUNNING) {
|
|
|
|
- if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
|
|
|
|
- var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
|
|
|
|
- if getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST) == 0 {
|
|
|
|
- if let address = String(validatingUTF8: hostname) {
|
|
|
|
- addresses.append(address)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- ptr = ptr!.pointee.ifa_next
|
|
|
|
- }
|
|
|
|
- freeifaddrs(ifaddr)
|
|
|
|
- }
|
|
|
|
- return addresses.first ?? "0.0.0.0"
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 生成唯一ID / 分享跟冷启动
|
|
|
|
-/// - Parameter desc: <#desc description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func getUniqueId(desc: String) -> String {
|
|
|
|
- let timeStr: String = "\(Date().timeIntervalSince1970)"
|
|
|
|
- let uuid: String = getMachineCode()
|
|
|
|
- let code: String = "\(arc4random_uniform(1_000_000_000))"
|
|
|
|
- let uniqueId = (timeStr + desc + uuid + code).md5.md5
|
|
|
|
- BFLog(4, message: "生成唯一码:desc = \(desc),timeStr = \(timeStr),uuid = \(uuid),code = \(code),uniqueId = \(uniqueId)")
|
|
|
|
- return uniqueId
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// MARK: 字典转字符串
|
|
|
|
-
|
|
|
|
-public func dictionaryToJsonString(_ dic: [String: Any]) -> String? {
|
|
|
|
- BFLog(message: "dictionaryToJsonString = \(dic)")
|
|
|
|
- if !JSONSerialization.isValidJSONObject(dic) {
|
|
|
|
- return ""
|
|
|
|
- }
|
|
|
|
- guard let data = try? JSONSerialization.data(withJSONObject: dic, options: []) else {
|
|
|
|
- return ""
|
|
|
|
- }
|
|
|
|
- BFLog(message: "dictionaryToJsonString - data = \(data)")
|
|
|
|
- let str = String(data: data, encoding: String.Encoding.utf8)
|
|
|
|
- BFLog(message: "dictionaryToJsonString - str = \(String(describing: str))")
|
|
|
|
- return str
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// MARK: 字符串转字典
|
|
|
|
-
|
|
|
|
-public func jsonStringToDictionary(_ str: String) -> [String: Any]? {
|
|
|
|
- let data = str.data(using: String.Encoding.utf8)
|
|
|
|
- if data == nil {
|
|
|
|
- return [:]
|
|
|
|
- }
|
|
|
|
- if let dict = try? JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any] {
|
|
|
|
- return dict
|
|
|
|
- }
|
|
|
|
- return [:]
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// MARK: 字符串转数组
|
|
|
|
-
|
|
|
|
-public func jsonStringToArray(_ str: String) -> [[String: String]]? {
|
|
|
|
- let data = str.data(using: String.Encoding.utf8)
|
|
|
|
- if let array = try? JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [[String: String]] {
|
|
|
|
- return array
|
|
|
|
- }
|
|
|
|
- return nil
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 数组转为string
|
|
|
|
-/// - Parameter array: <#array description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func arrayToJsonString(_ array: [Any]) -> String {
|
|
|
|
- if !JSONSerialization.isValidJSONObject(array) {
|
|
|
|
- BFLog(message: "无法解析String")
|
|
|
|
- return ""
|
|
|
|
- }
|
|
|
|
- let data: NSData! = try? JSONSerialization.data(withJSONObject: array, options: []) as NSData?
|
|
|
|
- let JSONString = NSString(data: data as Data, encoding: String.Encoding.utf8.rawValue)
|
|
|
|
- return JSONString! as String
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// jsonString转为数组
|
|
|
|
-/// - Parameter jsonString: <#jsonString description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func jsonStringToArray(jsonString: String) -> [Any]? {
|
|
|
|
- let data = jsonString.data(using: String.Encoding.utf8)
|
|
|
|
- if data == nil {
|
|
|
|
- return nil
|
|
|
|
- }
|
|
|
|
- if let array = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [Any] {
|
|
|
|
- return array
|
|
|
|
- }
|
|
|
|
- return nil
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 计算字符串大小
|
|
|
|
-/// - Parameters:
|
|
|
|
-/// - text: <#text description#>
|
|
|
|
-/// - font: <#font description#>
|
|
|
|
-/// - size: <#size description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func sizeWithText(text: String, font: UIFont, size: CGSize) -> CGSize {
|
|
|
|
- let attributes = [NSAttributedString.Key.font: font]
|
|
|
|
- let option = NSStringDrawingOptions.usesLineFragmentOrigin
|
|
|
|
- let rect: CGRect = text.boundingRect(with: size, options: option, attributes: attributes, context: nil)
|
|
|
|
- return rect.size
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 根据行数计算字符串大小
|
|
|
|
-/// - Parameters:
|
|
|
|
-/// - text: <#text description#>
|
|
|
|
-/// - numberOfLines: <#numberOfLines description#>
|
|
|
|
-/// - font: <#font description#>
|
|
|
|
-/// - maxSize: <#maxSize description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func sizeTextFits(attributedText: NSMutableAttributedString?, text: String?, numberOfLines: Int, font: UIFont, maxSize: CGSize) -> CGSize {
|
|
|
|
- var newSize: CGSize = CGSize(width: 0, height: 0)
|
|
|
|
- let label = UILabel(frame: CGRect.zero)
|
|
|
|
- label.font = font
|
|
|
|
- label.numberOfLines = numberOfLines
|
|
|
|
- if attributedText != nil {
|
|
|
|
- label.attributedText = attributedText
|
|
|
|
- } else {
|
|
|
|
- label.text = text
|
|
|
|
- }
|
|
|
|
- newSize = label.sizeThatFits(maxSize)
|
|
|
|
-
|
|
|
|
- return newSize
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-public func textNumberOfLines(text: String, font: UIFont, maxSize _: CGSize) -> Int {
|
|
|
|
- let label = UILabel(frame: CGRect.zero)
|
|
|
|
- label.font = font
|
|
|
|
- label.numberOfLines = 0
|
|
|
|
- label.text = text
|
|
|
|
- return label.numberOfLines
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 生成渐变色
|
|
|
|
-/// - Parameters:
|
|
|
|
-/// - size: <#size description#>
|
|
|
|
-/// - endPoint: <#endPoint description#>
|
|
|
|
-/// - startColor: <#startColor description#>
|
|
|
|
-/// - endColor: <#endColor description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func gradientColor(size: CGSize, endPoint: CGPoint, startColor: UIColor, endColor: UIColor) -> UIColor {
|
|
|
|
- let gradientLayer = CAGradientLayer()
|
|
|
|
- gradientLayer.frame = CGRect(origin: CGPoint(), size: size)
|
|
|
|
- gradientLayer.startPoint = CGPoint.zero
|
|
|
|
- gradientLayer.endPoint = endPoint
|
|
|
|
- gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
|
|
|
|
- UIGraphicsBeginImageContext(size)
|
|
|
|
- gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
|
|
|
|
- let image = UIGraphicsGetImageFromCurrentImageContext()!
|
|
|
|
- return UIColor(patternImage: image)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 获取设备ID
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func getMachineCode() -> String {
|
|
|
|
- let userInfo: [String: Any]? = jsonStringToDictionary(UserDefaults.standard.string(forKey: cUserInfoStorageKey) ?? "")
|
|
|
|
- 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)) {
|
|
|
|
- BFLog(message: "虚拟账号mid:\("\(userInfo?["mid"] ?? "")")")
|
|
|
|
- return "\(userInfo?["mid"] ?? "")"
|
|
|
|
- }
|
|
|
|
- let keychain = Keychain(service: "com.piaoquan.pqspeed")
|
|
|
|
- var uuid: String = keychain["machineCode"] ?? ""
|
|
|
|
- if uuid.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
|
|
- uuid = NSUUID().uuidString
|
|
|
|
- keychain["machineCode"] = uuid
|
|
|
|
- }
|
|
|
|
-// BFLog(message: "正式账号mid:\(uuid)")
|
|
|
|
- return uuid
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 显示加载中视图
|
|
|
|
-/// - Parameters:
|
|
|
|
-/// - superView: <#superView description#>
|
|
|
|
-/// - msg: <#msg description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
- public func cShowHUB(superView: UIView?, msg: String?) {
|
|
|
|
- DispatchQueue.main.async {
|
|
|
|
- var sty : ToastStyle = ToastManager.shared.style
|
|
|
|
- sty.messageAlignment = .center
|
|
|
|
- if superView == nil {
|
|
|
|
- if msg == nil {
|
|
|
|
- UIApplication.shared.keyWindow?.makeToastActivity(.center)
|
|
|
|
- } else {
|
|
|
|
- UIApplication.shared.keyWindow?.makeToast(msg, duration: 3.0, position: .center, style: sty)
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- if msg == nil {
|
|
|
|
- superView!.makeToastActivity(.center)
|
|
|
|
- } else {
|
|
|
|
- superView!.makeToast(msg, duration: 3.0, position: .center, style: sty)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 隐藏加载中视图
|
|
|
|
-/// - Parameter superView: <#superView description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func cHiddenHUB(superView: UIView?) {
|
|
|
|
- DispatchQueue.main.async {
|
|
|
|
- if superView == nil {
|
|
|
|
- UIApplication.shared.keyWindow?.hideAllToasts()
|
|
|
|
- UIApplication.shared.keyWindow?.hideToastActivity()
|
|
|
|
- } else {
|
|
|
|
- superView!.hideAllToasts()
|
|
|
|
- superView?.hideToastActivity()
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 获取存储值
|
|
|
|
-/// - Parameter key: key description
|
|
|
|
-/// - Returns: description
|
|
|
|
-public func getUserDefaults(key: String) -> Any? {
|
|
|
|
- return UserDefaults.standard.object(forKey: key)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 存储数据
|
|
|
|
-/// - Parameters:
|
|
|
|
-/// - key: key description
|
|
|
|
-/// - value: value description
|
|
|
|
-/// - Returns: description
|
|
|
|
-public func saveUserDefaults(key: String, value: String) {
|
|
|
|
- UserDefaults.standard.set(value, forKey: key)
|
|
|
|
- UserDefaults.standard.synchronize()
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 存储数据带版本号
|
|
|
|
-/// - Parameters:
|
|
|
|
-/// - key: <#key description#>
|
|
|
|
-/// - value: <#value description#>
|
|
|
|
-public func saveUserDefaultsToJson(key: String, value: Any) {
|
|
|
|
- UserDefaults.standard.set(dictionaryToJsonString([key: value, "appVersionCode": versionCode, "versionName": versionName]), forKey: key)
|
|
|
|
- UserDefaults.standard.synchronize()
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 获取数据带版本号
|
|
|
|
-/// - Parameter key: <#key description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func getUserDefaultsForJson(key: String) -> Any? {
|
|
|
|
- let jsonStr = UserDefaults.standard.object(forKey: key)
|
|
|
|
- if jsonStr != nil {
|
|
|
|
- return jsonStringToDictionary(jsonStr as! String)?[key]
|
|
|
|
- }
|
|
|
|
- return UserDefaults.standard.object(forKey: key)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 清空数据
|
|
|
|
-/// - Parameters:
|
|
|
|
-/// - key: key description
|
|
|
|
-/// - value: value description
|
|
|
|
-/// - Returns: description
|
|
|
|
-public func removeUserDefaults(key: String) {
|
|
|
|
- UserDefaults.standard.removeObject(forKey: key)
|
|
|
|
- UserDefaults.standard.synchronize()
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 存储数据
|
|
|
|
-/// - Parameters:
|
|
|
|
-/// - key: key description
|
|
|
|
-/// - value: value description
|
|
|
|
-/// - Returns: description
|
|
|
|
-public func saveUserDefaults(key: String, value: Any) {
|
|
|
|
- UserDefaults.standard.set(value, forKey: key)
|
|
|
|
- UserDefaults.standard.synchronize()
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 保存自定义model as NSArray 当 OBJ 是数组时不能使用 Array 要使用 NSArray
|
|
|
|
-/// - Parameter object: <#object description#>
|
|
|
|
-/// - Parameter key: <#key description#>
|
|
|
|
-public func saveCustomObject(customObject object: NSCoding, key: String) {
|
|
|
|
- let encodedObject = NSKeyedArchiver.archivedData(withRootObject: object)
|
|
|
|
- UserDefaults.standard.set(encodedObject, forKey: key)
|
|
|
|
- UserDefaults.standard.synchronize()
|
|
|
|
- BFLog(message: "保存自定义类成功 key is \(key) \(encodedObject.count)")
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 取自定义model
|
|
|
|
-/// - Parameter key: <#key description#>
|
|
|
|
-public func getCustomObject(forKey key: String) -> AnyObject? {
|
|
|
|
- let decodedObject = UserDefaults.standard.object(forKey: key) as? Data
|
|
|
|
-
|
|
|
|
- if decodedObject == nil {
|
|
|
|
- BFLog(message: "key is \(key) decodedObject is nil")
|
|
|
|
- }
|
|
|
|
- if let decoded = decodedObject {
|
|
|
|
- let object = NSKeyedUnarchiver.unarchiveObject(with: decoded as Data)
|
|
|
|
-
|
|
|
|
- return object as AnyObject?
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return nil
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 添加通知
|
|
|
|
-/// - Parameters:
|
|
|
|
-/// - observer: <#observer description#>
|
|
|
|
-/// - aSelectorName: <#aSelectorName description#>
|
|
|
|
-/// - aName: <#aName description#>
|
|
|
|
-/// - anObject: <#anObject description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func addNotification(_ observer: Any, selector aSelectorName: Selector, name aName: String, object anObject: Any?) {
|
|
|
|
- PQNotification.addObserver(observer, selector: aSelectorName, name: NSNotification.Name(rawValue: aName), object: anObject)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 发送通知
|
|
|
|
-/// - Parameter aName: <#aName description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func postNotification(name aName: String, userInfo: [AnyHashable: Any]? = nil) {
|
|
|
|
- PQNotification.post(name: NSNotification.Name(aName), object: nil, userInfo: userInfo)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 获取是否打开推送
|
|
|
|
-/// - Parameter completeHander: <#completeHander description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func pushNotificationIsOpen(completeHander: ((_ isOpen: Bool) -> Void)?) {
|
|
|
|
- if #available(iOS 10.0, *) {
|
|
|
|
- UNUserNotificationCenter.current().getNotificationSettings { setttings in
|
|
|
|
- completeHander!(setttings.authorizationStatus == .authorized)
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- completeHander!(UIApplication.shared.currentUserNotificationSettings?.types.contains(UIUserNotificationType.alert) ?? false)
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 发送上传本地推送
|
|
|
|
-/// - Parameter isSuccess: 是否上传成功
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func sendUploadNotification(isSuccess: Bool) {
|
|
|
|
- let title: String = isSuccess ? "上传完成了!" : "上传失败了!"
|
|
|
|
- let body: String = isSuccess ? "请点击发布,完成上传。否则,您的视频可能丢失" : "快来看看怎么了?"
|
|
|
|
- sendLocalNotification(title: title, body: body)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 发送本地推送
|
|
|
|
-/// - Parameters:
|
|
|
|
-/// - title: 标题
|
|
|
|
-/// - body: 内容
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func sendLocalNotification(title: String, body: String) {
|
|
|
|
- // 设置推送内容
|
|
|
|
- if #available(iOS 10.0, *) {
|
|
|
|
- let content = UNMutableNotificationContent()
|
|
|
|
- content.title = title
|
|
|
|
- content.body = body
|
|
|
|
- content.badge = 1
|
|
|
|
- // 设置通知触发器
|
|
|
|
- let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
|
|
|
|
- // 设置请求标识符
|
|
|
|
- let requestIdentifier = getUniqueId(desc: "notification\(title)")
|
|
|
|
- // 设置一个通知请求
|
|
|
|
- let request = UNNotificationRequest(identifier: requestIdentifier,
|
|
|
|
-
|
|
|
|
- content: content, trigger: trigger)
|
|
|
|
- // 将通知请求添加到发送中心
|
|
|
|
- UNUserNotificationCenter.current().add(request) { error in
|
|
|
|
- if error == nil {
|
|
|
|
- print("Time Interval Notification scheduled: \(requestIdentifier)")
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- // Fallback on earlier versions
|
|
|
|
- let notification = UILocalNotification()
|
|
|
|
- notification.alertBody = body
|
|
|
|
- notification.alertTitle = title
|
|
|
|
- notification.applicationIconBadgeNumber = 1
|
|
|
|
- notification.fireDate = Date(timeIntervalSinceNow: 0)
|
|
|
|
- UIApplication.shared.scheduledLocalNotifications = [notification]
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 打开应用设置
|
|
|
|
-public func openAppSetting() {
|
|
|
|
- if UIApplication.shared.canOpenURL(URL(string: UIApplication.openSettingsURLString)!) {
|
|
|
|
- guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
- if UIApplication.shared.canOpenURL(settingsUrl) {
|
|
|
|
- UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
|
|
|
|
- BFLog(message: "Settings opened: \(success)") // Prints true
|
|
|
|
- })
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// dns解析
|
|
|
|
-/// - Parameter hostUrl: speed.piaoquantv.com /
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func parseDNS(hostUrl: String) -> [String: Any]? {
|
|
|
|
- let host: CFHost? = CFHostCreateWithName(nil, hostUrl as CFString).takeRetainedValue()
|
|
|
|
- let start = CFAbsoluteTimeGetCurrent()
|
|
|
|
- var success: DarwinBoolean = false
|
|
|
|
- var addressList: [String] = Array<String>.init()
|
|
|
|
- var addresses: NSArray?
|
|
|
|
- if CFHostStartInfoResolution(host!, .addresses, nil) {
|
|
|
|
- addresses = (CFHostGetAddressing(host!, &success)?.takeUnretainedValue())
|
|
|
|
- }
|
|
|
|
- if success == true {
|
|
|
|
- for case let theAddress as NSData in addresses! {
|
|
|
|
- var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
|
|
|
|
- if getnameinfo(theAddress.bytes.assumingMemoryBound(to: sockaddr.self), socklen_t(theAddress.length),
|
|
|
|
- &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0
|
|
|
|
- {
|
|
|
|
- let numAddress = String(cString: hostname)
|
|
|
|
- addressList.append("\(hostUrl)/\(numAddress)")
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- let end = CFAbsoluteTimeGetCurrent()
|
|
|
|
- let duration = end - start
|
|
|
|
- BFLog(message: "duration = \(duration)")
|
|
|
|
- BFLog(message: "addressList = \(addressList)")
|
|
|
|
- if addressList.count > 0 {
|
|
|
|
- return ["dnsResult": arrayToJsonString(addressList), "duration": duration * 1000, "hostName": hostUrl, "networkType": networkStatus()]
|
|
|
|
- } else {
|
|
|
|
- return nil
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 获取当前日期
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func systemCurrentDate() -> String {
|
|
|
|
- let dateFormatter = DateFormatter()
|
|
|
|
- dateFormatter.dateFormat = "YYYY-MM-dd"
|
|
|
|
- return dateFormatter.string(from: Date())
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 时间戳转日期
|
|
|
|
-/// - Parameter timeInterval: <#timeInterval description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func timeIntervalToDateString(timeInterval: TimeInterval) -> String {
|
|
|
|
- let date = Date(timeIntervalSince1970: timeInterval)
|
|
|
|
- let dateFormatter = DateFormatter()
|
|
|
|
- dateFormatter.dateFormat = "MM月dd日 HH:mm"
|
|
|
|
- return dateFormatter.string(from: date)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 判断字符串或者字典是否为空
|
|
|
|
-/// - Parameter object: <#object description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func isEmpty(object: Any?) -> Bool {
|
|
|
|
- if object == nil {
|
|
|
|
- return true
|
|
|
|
- }
|
|
|
|
- if object is String {
|
|
|
|
- return (object as! String).count <= 0
|
|
|
|
- }
|
|
|
|
- if object is [String: Any] {
|
|
|
|
- return (object as! [String: Any]).keys.count <= 0
|
|
|
|
- }
|
|
|
|
- return false
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-public func isEmptyObject(object: Any?) -> Bool {
|
|
|
|
- if object == nil {
|
|
|
|
- return true
|
|
|
|
- }
|
|
|
|
- if object is String {
|
|
|
|
- return object == nil || ((object as? String)?.count ?? 0) <= 0
|
|
|
|
- }
|
|
|
|
- if object is [String: Any] {
|
|
|
|
- return object == nil || ((object as? [String: Any])?.keys.count ?? 0) <= 0
|
|
|
|
- }
|
|
|
|
- if object is List<Object> {
|
|
|
|
- return object == nil || ((object as? List<Object>)?.count ?? 0) <= 0
|
|
|
|
- }
|
|
|
|
- return false
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// <#Description#>
|
|
|
|
-/// - Parameter string: <#string description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func isIncludeChineseIn(string: String) -> Bool {
|
|
|
|
- for (_, value) in string.enumerated() {
|
|
|
|
- if value >= "\u{4E00}", value <= "\u{9FA5}" {
|
|
|
|
- return true
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return false
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 获取文件内容的MD5
|
|
|
|
-/// - Parameters:
|
|
|
|
-/// - path: 地址
|
|
|
|
-/// - data: data
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func contentMD5(path: String? = nil, data _: Data? = nil) -> String? {
|
|
|
|
- if path == nil || (path?.count ?? 0) <= 0 || !FileManager.default.fileExists(atPath: path ?? "") {
|
|
|
|
- BFLog(message: "生成内容md5值:地址错误或者不存在\(String(describing: path))")
|
|
|
|
- return ""
|
|
|
|
- }
|
|
|
|
- let att = try? FileManager.default.attributesOfItem(atPath: path ?? "")
|
|
|
|
- let size = Int64(att?[FileAttributeKey.size] as! UInt64)
|
|
|
|
- if size <= 0 {
|
|
|
|
- BFLog(message: "生成内容md5值:文件大小为0\(size)")
|
|
|
|
- return ""
|
|
|
|
- }
|
|
|
|
- let hash: String = OSSUtil.base64Md5(forFilePath: path)
|
|
|
|
- BFLog(message: "生成内容md5值:contentMD5 = \(hash)")
|
|
|
|
- return hash
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-/// 自适应宽
|
|
|
|
-/// - Parameters:
|
|
|
|
-/// - width: <#width description#>
|
|
|
|
-/// - baseWidth: <#baseWidth description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func adapterWidth(width: CGFloat, baseWidth: CGFloat = 375) -> CGFloat {
|
|
|
|
- return width / baseWidth * cScreenWidth
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 自适应高
|
|
|
|
-/// - Parameters:
|
|
|
|
-/// - height: <#height description#>
|
|
|
|
-/// - baseHeight: <#baseHeight description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func adapterHeight(height: CGFloat, baseHeight: CGFloat = 812) -> CGFloat {
|
|
|
|
- return height / baseHeight * cScreenHeigth
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 检测URL
|
|
|
|
-/// - Parameter url: <#url description#>
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func isValidURL(url: String?) -> Bool {
|
|
|
|
- if url == nil || (url?.count ?? 0) <= 4 || (!(url?.hasPrefix("http") ?? false) && !(url?.hasPrefix("https") ?? false)) {
|
|
|
|
- return false
|
|
|
|
- }
|
|
|
|
- return true
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/// 相册数据按创建时间排序
|
|
|
|
-public var creaFetchOptions: PHFetchOptions = {
|
|
|
|
- let fetchOptions = PHFetchOptions()
|
|
|
|
- fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
|
|
|
|
- return fetchOptions
|
|
|
|
-}()
|
|
|
|
-
|
|
|
|
-/// 相册数据按修改时间排序
|
|
|
|
-public var modiFetchOptions: PHFetchOptions = {
|
|
|
|
- let fetchOptions = PHFetchOptions()
|
|
|
|
- fetchOptions.sortDescriptors = [NSSortDescriptor(key: "modificationDate", ascending: false)]
|
|
|
|
- return fetchOptions
|
|
|
|
-}()
|
|
|
|
-
|
|
|
|
-/// 获取本地素材
|
|
|
|
-public var avAssertOptions: [String: Any]? = {
|
|
|
|
- [AVURLAssetPreferPreciseDurationAndTimingKey: NSNumber(value: true)]
|
|
|
|
-}()
|
|
|
|
-
|
|
|
|
-/// 播放动画图
|
|
|
|
-public var playGifImages: [UIImage] = {
|
|
|
|
- var gifImages = Array<UIImage>.init()
|
|
|
|
- for i in 0 ... 44 {
|
|
|
|
- gifImages.append(UIImage(named: "\(i).png")!)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return gifImages
|
|
|
|
-}()
|
|
|
|
-
|
|
|
|
-/// 压缩图片
|
|
|
|
-/// - Parameter image: <#image description#>
|
|
|
|
-/// -
|
|
|
|
-/// - Returns: <#description#>
|
|
|
|
-public func zipImage(image: UIImage?, size: Int) -> Data? {
|
|
|
|
- var data = image?.pngData()
|
|
|
|
- var dataKBytes = Int(data?.count ?? 0) / 1000
|
|
|
|
- var maxQuality = 0.9
|
|
|
|
- while dataKBytes > size, maxQuality > 0.01 {
|
|
|
|
- maxQuality = maxQuality - 0.01
|
|
|
|
- data = image?.jpegData(compressionQuality: CGFloat(maxQuality))
|
|
|
|
- dataKBytes = (data?.count ?? 0) / 1000
|
|
|
|
- }
|
|
|
|
- return data
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-func currentBundlePath() -> Bundle?{
|
|
|
|
-// var associateBundleURL = Bundle.main.url(forResource: "Frameworks", withExtension: nil)
|
|
|
|
-// associateBundleURL = associateBundleURL?.appendingPathComponent("BFFramework")
|
|
|
|
-// associateBundleURL = associateBundleURL?.appendingPathExtension("framework")
|
|
|
|
-//
|
|
|
|
-// if associateBundleURL == nil {
|
|
|
|
-// print("获取bundle失败")
|
|
|
|
-// return nil
|
|
|
|
-// }
|
|
|
|
-// let associateBunle = Bundle(url: associateBundleURL!)
|
|
|
|
- let associateBundleURL = Bundle.main.url(forResource: "BFFramework_Resources", withExtension: "bundle")
|
|
|
|
- if associateBundleURL == nil {
|
|
|
|
- return nil
|
|
|
|
- }
|
|
|
|
- return Bundle(url: associateBundleURL!)
|
|
|
|
-}
|
|
|