| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945 | ////  PQCommonMethodUtil.swift//  PQSpeed////  Created by lieyunye on 2020/5/29.//  Copyright © 2020 BytesFlow. All rights reserved.//import AdSupportimport Alamofireimport Foundationimport KeychainAccessimport Kingfisherimport KingfisherWebPimport Photosimport 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/"/// 导出声音的本地沙盒目录vpublic 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.moduleImage(named: "placehold_image", moduleName: "BFCommonKit") ?? UIImage()) {    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)            }        }    }}/** 打印 */public func BFLog<T>(message: T) {//    if PQBFConfig.shared.enableBFLog {    let logger = NXLogger.shared    logger.level = .info    logger.ouput = .debuggerConsole    logger.d(message as? String ?? "")//    } else {//        BuglyLog.level(.warn, logs: message as? String)//    }}public func HHZPrint<T>(_: T, file _: String = #file, funcName _: String = #function, lineNum _: Int = #line) {    #if DEBUG//        let file = (file as NSString).lastPathComponent;////        print("hhz-\(file):(\(lineNum))--\(message)");    #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,        "mid": getMachineCode(),        "machineInfo": dictionaryToJsonString(machineInfo) ?? "",        "requestId": getUniqueId(desc: "requestId"),        "idfa": ASIdentifierManager.shared().advertisingIdentifier.uuidString,        "idfv": UIDevice.current.identifierForVendor?.uuidString ?? "",        "sessionId": PQBFConfig.shared.sessionId,        "subSessionId": PQBFConfig.shared.subSessionId ?? PQBFConfig.shared.sessionId,    ]    if PQBFConfig.shared.token != nil, (PQBFConfig.shared.token?.count ?? 0) > 0 {        commParams["token"] = PQBFConfig.shared.token ?? ""    }    if PQBFConfig.shared.loginUid != nil, (PQBFConfig.shared.loginUid?.count ?? 0) > 0 {        commParams["loginUid"] = PQBFConfig.shared.loginUid ?? ""        commParams["uid"] = PQBFConfig.shared.loginUid ?? ""    }    if PQBFConfig.shared.deviceToken != nil, (PQBFConfig.shared.deviceToken?.count ?? 0) > 0 {        commParams["deviceToken"] = PQBFConfig.shared.deviceToken ?? ""    }    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/5G"    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 == .reachable(.cellular) || NetworkReachabilityManager(host: "www.baidu.com")?.status == .reachable(.ethernetOrWiFi)}/// 获取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(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]? {    if str.count <= 0 {        return [:]    }    let data = str.data(using: String.Encoding.utf8)    if data == nil || (data?.count ?? 0) <= 0 {        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(attributedText: NSMutableAttributedString? = nil, text: String, font: UIFont, size: CGSize) -> CGSize {    let option = NSStringDrawingOptions.usesLineFragmentOrigin    if attributedText != nil {        let rect: CGRect = attributedText?.boundingRect(with: size, options: option, context: nil) ?? CGRect(origin: CGPoint.zero, size: size)        return rect.size    } else {        let attributes = [NSAttributedString.Key.font: font]        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 {        if superView == nil {            if msg == nil {                UIApplication.shared.keyWindow?.makeToastActivity(.center)            } else {                UIApplication.shared.keyWindow?.makeToast(msg, duration: 3.0, position: .center)            }        } else {            if msg == nil {                superView!.makeToastActivity(.center)            } else {                superView!.makeToast(msg, duration: 3.0, position: .center)            }        }    }}/// 隐藏加载中视图/// - 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: descriptionpublic func getUserDefaults(key: String) -> Any? {    return UserDefaults.standard.object(forKey: key)}/// 存储数据/// - Parameters:///   - key: key description///   - value: value description/// - Returns: descriptionpublic 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: descriptionpublic func removeUserDefaults(key: String) {    UserDefaults.standard.removeObject(forKey: key)    UserDefaults.standard.synchronize()}/// 存储数据/// - Parameters:///   - key: key description///   - value: value description/// - Returns: descriptionpublic 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)!) {        UIApplication.shared.openURL(URL(string: UIApplication.openSettingsURLString)!)    }}/// 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 = "yyyy年MM月dd日"    return dateFormatter.string(from: date)}public func updateTimeToCurrenTime(timeInterval: TimeInterval) -> String {    // 获取当前的时间戳    let currentTime = Date().timeIntervalSince1970    print(currentTime, timeInterval, "sdsss")    // 时间戳为毫秒级要 / 1000, 秒就不用除1000,参数带没带000//      let timeSta:TimeInterval = TimeInterval(timeInterval / 1000)    // 时间差    let reduceTime: TimeInterval = currentTime - timeInterval    // 时间差小于60秒    if reduceTime < 60 {        return "刚刚"    }    // 时间差大于一分钟小于60分钟内    let mins = Int(reduceTime / 60)    if mins < 60 {        return "\(mins)分钟前"    }    let hours = Int(reduceTime / 3600)    if hours < 24 {        return "\(hours)小时前"    }//      let days = Int(reduceTime / 3600 / 24)//      if days < 30 {//          return "\(days)天前"//      }    // 不满足上述条件---或者是未来日期-----直接返回日期    let date = NSDate(timeIntervalSince1970: timeInterval)    let dfmatter = DateFormatter()    // yyyy-MM-dd HH:mm:ss    dfmatter.dateFormat = "yyyy年M月d日 HH:mm"    var dfmatterStr = dfmatter.string(from: date as Date)    let currentDF = DateFormatter()    // yyyy-MM-dd HH:mm:ss    currentDF.dateFormat = "yyyy"    let currentDFStr = currentDF.string(from: Date())    if dfmatterStr.hasPrefix(currentDFStr) {        dfmatterStr.removeFirst(currentDFStr.count + 1)    }    return dfmatterStr}/// 判断字符串或者字典是否为空/// - 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)    let hash: String = ""    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}/// 压缩图片到指定大小/// - Parameters:///   - image: <#image description#>///   - maxLength: <#maxLength description#>///   - cyles: <#cyles description#>/// - Returns: <#description#>public func zipImageQuality(image: UIImage, maxLength: NSInteger, cyles: Int = 6) -> Data {    var compression: CGFloat = 1    var data = image.jpegData(compressionQuality: compression)!    if data.count < maxLength {        return data    }    var max: CGFloat = 1    var min: CGFloat = 0    var bestData: Data = data    for _ in 0 ..< cyles {        compression = (max + min) / 2        data = image.jpegData(compressionQuality: compression)!        if Double(data.count) < Double(maxLength) * 0.9 {            min = compression            bestData = data        } else if data.count > maxLength {            max = compression        } else {            bestData = data            break        }    }    return bestData}public func resetImgSize(sourceImage: UIImage, maxImageLenght: CGFloat, maxSizeKB: CGFloat) -> Data {    var maxSize = maxSizeKB    var maxImageSize = maxImageLenght    if maxSize <= 0.0 {        maxSize = 1024.0    }    if maxImageSize <= 0.0 {        maxImageSize = 1024.0    }    // 先调整分辨率    var newSize = CGSize(width: sourceImage.size.width, height: sourceImage.size.height)    let tempHeight = newSize.height / maxImageSize    let tempWidth = newSize.width / maxImageSize    if tempWidth > 1.0, tempWidth > tempHeight {        newSize = CGSize(width: sourceImage.size.width / tempWidth, height: sourceImage.size.height / tempWidth)    } else if tempHeight > 1.0, tempWidth < tempHeight {        newSize = CGSize(width: sourceImage.size.width / tempHeight, height: sourceImage.size.height / tempHeight)    }    UIGraphicsBeginImageContext(newSize)    sourceImage.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))    let newImage = UIGraphicsGetImageFromCurrentImageContext()    UIGraphicsEndImageContext()    var imageData = newImage!.jpegData(compressionQuality: 1.0)    var sizeOriginKB: CGFloat = CGFloat((imageData?.count)!) / 1024.0    // 调整大小    var resizeRate = 0.9    while sizeOriginKB > maxSize, resizeRate > 0.1 {        imageData = newImage!.jpegData(compressionQuality: CGFloat(resizeRate))        sizeOriginKB = CGFloat((imageData?.count)!) / 1024.0        resizeRate -= 0.1    }    return imageData!}/// 获取开屏广告图/// - Returns: <#description#>public func getLaunchImage() -> UIImage {    var lauchImg: UIImage!    var viewOrientation: String!    let viewSize = UIScreen.main.bounds.size    let orientation = UIApplication.shared.statusBarOrientation    if orientation == .landscapeLeft || orientation == .landscapeRight {        viewOrientation = "Landscape"    } else {        viewOrientation = "Portrait"    }    let imgsInfoArray = Bundle.main.infoDictionary!["UILaunchImages"]    for dict: [String: String] in imgsInfoArray as! Array {        let imageSize = NSCoder.cgSize(for: dict["UILaunchImageSize"]!)        if __CGSizeEqualToSize(imageSize, viewSize), viewOrientation == dict["UILaunchImageOrientation"]! as String {            lauchImg = UIImage(named: dict["UILaunchImageName"]!)        }    }    return lauchImg}
 |