harry 3 anos atrás
pai
commit
d5bf79e4bd

+ 4 - 3
BFCommonKit.podspec

@@ -41,8 +41,6 @@ TODO: Add long description of the pod here.
     bb.frameworks = 'UIKit', 'WebKit'
     bb.dependency 'Alamofire','5.4.3'
     bb.dependency 'SnapKit','5.0.1'
-    bb.dependency 'RealmSwift','10.7.6'
-    bb.dependency 'FDFullscreenPopGesture','1.1'
     bb.dependency 'BFCommonKit/BFUtility'
     bb.dependency 'BFCommonKit/BFConfig'
     bb.dependency 'BFCommonKit/BFCategorys'
@@ -59,10 +57,10 @@ TODO: Add long description of the pod here.
   s.subspec 'BFUtility' do |uu|
     uu.source_files = 'BFCommonKit/Classes/BFUtility/*'
     uu.frameworks = 'Foundation','UIKit','AdSupport','Photos','AudioToolbox','AVKit'
-    uu.dependency 'KingfisherWebP','1.3.0'
     uu.dependency 'Alamofire','5.4.3'
     uu.dependency 'KeychainAccess','4.2.2'
     uu.dependency 'Kingfisher','6.3.0'
+    uu.dependency 'KingfisherWebP','1.3.0'
     uu.dependency 'Toast-Swift','5.0.1'
     uu.dependency 'BFCommonKit/BFCategorys'
     uu.dependency 'BFCommonKit/BFConfig'
@@ -77,6 +75,7 @@ TODO: Add long description of the pod here.
 #      'BFCommonKit_Resources' => ['BFCommonKit/Assets/Resources/*']
 #    }
 #  end
+
    s.resource_bundles = {
       'BFCommonKit_Resources' => ['BFCommonKit/Assets/Resources/*']
     }
@@ -84,4 +83,6 @@ TODO: Add long description of the pod here.
   # s.public_header_files = 'Pod/Classes/**/*.h'
   # s.frameworks = 'UIKit', 'AVFoundation','CoreMedia', 'QuartzCore'
   # s.dependency 'Kingfisher','6.3.0'
+
+  
 end

+ 0 - 198
BFCommonKit/Classes/BFBase/Model/PQBaseModel.swift

@@ -1,198 +0,0 @@
-//
-//  PQBaseModel.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/5/25.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import UIKit
-import RealmSwift
-
-open class PQBaseModel: Object {
-    @objc dynamic public var uniqueId: String? // 唯一ID
-    @objc dynamic public var videoId: Int = 0 // 视频ID
-    @objc dynamic public var eventId: String? // 事件ID
-    @objc dynamic public var title: String? // 标题
-    @objc dynamic public var attributedTitle: NSMutableAttributedString? // 富文本标题
-    @objc dynamic public var summary: String? // 描述
-    @objc dynamic public var imageUrl: String = "" // 图片地址
-    @objc dynamic public var selectedImage: String = "" // 图片地址
-    @objc dynamic public var isSelected: Bool = false
-    @objc dynamic public var recommendLogVO: String? // 推荐日志对象
-    @objc dynamic public var abInfoData: String? // AB
-    @objc dynamic public var pageCategoryId: Int = 0 // 页面分类ID
-    @objc dynamic public var version: String = versionName // 版本号
-    @objc dynamic public var mid = getMachineCode() // 设备ID
-    @objc dynamic public var date: Int = 0 // 当前时间戳  CGFloat(Date.init().timeIntervalSince1970) * 1000
-    @objc dynamic public var itemWidth: Float = 0 // cell宽
-    @objc dynamic public var primaryKeys: String? // 区分存储唯一值
-    override class public func primaryKey() -> String? {
-        return "uniqueId"
-    }
-
-    public override required  init() {
-        super.init()
-        uniqueId = getUniqueId(desc: "uniqueId")
-    }
-
-    override class open func ignoredProperties() -> [String] {
-        return ["attributedTitle"]
-    }
-
-    @objc func toString() -> String {
-        var json: [String: Any] = [
-            "version": version,
-            "mid": mid,
-            "pageCategoryId": pageCategoryId,
-            "selectedImage": selectedImage,
-            "isSelected": isSelected,
-            "imageUrl": imageUrl,
-        ]
-        if uniqueId != nil {
-            json["uniqueId"] = uniqueId
-            json["videoId"] = videoId
-        }
-        if eventId != nil {
-            json["eventId"] = eventId
-        }
-        if title != nil {
-            json["title"] = title
-        }
-        if summary != nil {
-            json["summary"] = summary
-        }
-        if recommendLogVO != nil {
-            json["recommendLogVO"] = recommendLogVO
-        }
-        return dictionaryToJsonString(json) ?? ""
-    }
-
-    public init(jsonDict: [String: Any]) {
-        super.init()
-        if jsonDict.keys.contains("id") {
-            uniqueId = "\(jsonDict["id"] ?? "")"
-            videoId = Int(uniqueId ?? "0") ?? 0
-        }
-        if jsonDict.keys.contains("uniqueId") {
-            uniqueId = "\(jsonDict["uniqueId"] ?? "")"
-            videoId = Int(uniqueId ?? "0") ?? 0
-        }
-        if jsonDict.keys.contains("eventId") {
-            eventId = "\(jsonDict["eventId"] ?? "")"
-        }
-        if jsonDict.keys.contains("title") {
-            title = "\(jsonDict["title"] ?? "")"
-        }
-        if jsonDict.keys.contains("summary") {
-            summary = "\(jsonDict["summary"] ?? "")"
-        }
-        if jsonDict.keys.contains("imageUrl") {
-            imageUrl = "\(jsonDict["imageUrl"] ?? "")"
-        }
-        if jsonDict.keys.contains("selectedImage") {
-            selectedImage = "\(jsonDict["selectedImage"] ?? "")"
-        }
-        if jsonDict.keys.contains("isSelected") {
-            isSelected = jsonDict["isSelected"] as! Bool
-        }
-        if jsonDict.keys.contains("recommendLogVO") {
-            recommendLogVO = "\(jsonDict["recommendLogVO"] ?? "")"
-        }
-        if jsonDict.keys.contains("pageCategoryId") {
-            pageCategoryId = Int("\(jsonDict["pageCategoryId"] ?? "0")") ?? 0
-        }
-        if jsonDict.keys.contains("version") {
-            version = "\(jsonDict["version"] ?? "")"
-        }
-        if jsonDict.keys.contains("mid") {
-            mid = "\(jsonDict["mid"] ?? "")"
-        }
-    }
-}
-
-// MARK: - 当前应用本地存储的model
-
-/// 当前应用本地存储的model
-public  class PQLocalStoreModel: PQBaseModel {
-    @objc dynamic public var currentDate: String?
-    @objc required public init() {
-        super.init()
-        currentDate = systemCurrentDate()
-    }
-}
-
-// MARK: - oss上传model
-
-/// oss上传model
-public class PQOssUploadModel: NSObject {
-    public var accessKeyId: String?
-    public var secretKeyId: String?
-    public var securityToken: String?
-    public var endpoint: String?
-    public var endpoints: [String]?
-    public var bucketName: String?
-    public var fileName: String?
-    public var uploadID: String?
-    public var expiration: String? // 过期时间
-    public init(jsonDict: [String: Any]) {
-        super.init()
-
-        if jsonDict.keys.contains("AccessKeyId") {
-            accessKeyId = "\(jsonDict["AccessKeyId"] ?? "")"
-        }
-        if jsonDict.keys.contains("AccessKeySecret") {
-            secretKeyId = "\(jsonDict["AccessKeySecret"] ?? "")"
-        }
-        if jsonDict.keys.contains("SecurityToken") {
-            securityToken = "\(jsonDict["SecurityToken"] ?? "")"
-        }
-        if jsonDict.keys.contains("Hosts") {
-            endpoints = jsonDict["Hosts"] as? [String]
-        }
-        if jsonDict.keys.contains("Host") {
-            endpoint = "\(jsonDict["Host"] ?? "")"
-            if endpoint != nil {
-                if endpoints == nil {
-                    endpoints = [endpoint!]
-                } else {
-                    endpoints?.append(endpoint!)
-                }
-            }
-        }
-        if jsonDict.keys.contains("Bucket") {
-            bucketName = "\(jsonDict["Bucket"] ?? "")"
-        }
-        if jsonDict.keys.contains("FileName") {
-            fileName = "\(jsonDict["FileName"] ?? "")"
-        }
-        if jsonDict.keys.contains("Upload") {
-            uploadID = "\(jsonDict["Upload"] ?? "")"
-        }
-        if jsonDict.keys.contains("Expiration") {
-            expiration = "\(jsonDict["Expiration"] ?? "")"
-        }
-    }
-}
-
-// MARK: - 空白页面model
-
-/// 空白页面model
-public class PQEmptyModel: NSObject {
-    public var bgColor: UIColor? // 背景色
-    public var title: String? // 标题
-    public var titleColor: UIColor? // 标题颜色
-    public var summary: String? // 描述
-    public var summaryColor: UIColor? // 描述颜色
-    public var emptyImageName: String? // 空白提示图
-    public var emptySoureImage: UIImage? // 空白提示图
-    public var isRefreshHidden: Bool = true // 是否隐藏刷新按钮
-    public var refreshImageName: String? // 刷新按钮图片
-    public var refreshTitle: NSMutableAttributedString? // 刷新按钮文字
-    public var refreshBgColor: UIColor? // 刷新按钮背景颜色
-    public var netemptyDisImage: UIImage? // 无网空白提示图
-    public var netDisRefreshTitle: NSMutableAttributedString? // 无网刷新按钮文字
-    public var netDisTitle: String? // 无网标题
-    public var netDisTitleColor: UIColor? // 无网标题颜色
-    public var netDisRefreshBgColor: UIColor? // 无网刷新按钮背景颜色
-}

+ 1 - 1
BFCommonKit/Classes/BFCategorys/BFBundle+Ext.swift

@@ -10,7 +10,7 @@ import Foundation
 public extension Bundle {
     // bf main bundle url
 //    func BF_mainbundle_URL() -> URL {
-//        let bundle: Bundle = Bundle(for: BFBaseViewController.self)
+//        let bundle: Bundle = Bundle(for: PQBaseViewController.self)
 //        return bundle.url(forResource: "BFFramework", withExtension: "bundle")!
 //    }
 

+ 2 - 2
BFCommonKit/Classes/BFCategorys/BFColor+Ext.swift

@@ -10,7 +10,7 @@ import Foundation
 import UIKit
 
 public extension UIColor {
-    class func hexColor(hexadecimal: String) -> UIColor {
+    class func hexColor(hexadecimal: String, alpha:CGFloat = 1) -> UIColor {
         var cstr = hexadecimal.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).uppercased() as NSString
         if cstr.length < 6 {
             return UIColor.clear
@@ -41,7 +41,7 @@ public extension UIColor {
         Scanner(string: rStr).scanHexInt32(&r)
         Scanner(string: gStr).scanHexInt32(&g)
         Scanner(string: bStr).scanHexInt32(&b)
-        return UIColor(red: CGFloat(r) / 255.0, green: CGFloat(g) / 255.0, blue: CGFloat(b) / 255.0, alpha: 1)
+        return UIColor(red: CGFloat(r) / 255.0, green: CGFloat(g) / 255.0, blue: CGFloat(b) / 255.0, alpha: alpha)
     }
 
     // MARK: - hex (0x000000) -> UIColor

+ 1 - 1
BFCommonKit/Classes/BFCategorys/NXFundation+Ext.swift

@@ -134,7 +134,7 @@ public extension String {
     }
 }
 
-extension Data {
+public extension Data {
     func append2File(fileURL: URL) throws {
         if let fileHandle = FileHandle(forWritingAtPath: fileURL.path) {
             defer {

+ 389 - 0
BFCommonKit/Classes/BFCategorys/NXUI+Ext.swift

@@ -0,0 +1,389 @@
+//
+//  NXUI+Ext.swift
+//  NXFramework-Swift-Demo
+//
+//  Created by ak on 2020/10/26.
+//  Copyright © 2020 NXFramework-Swift. All rights reserved.
+//
+
+import UIKit
+
+public extension UIViewController {
+    func showAlert(withTitle title: String?, message: String?) {
+        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
+        let action = UIAlertAction(title: "OK", style: .cancel, handler: nil)
+        alert.addAction(action)
+
+        present(alert, animated: true, completion: nil)
+    }
+
+    var contentViewController: UIViewController {
+        if let navcon = self as? UINavigationController {
+            return navcon.visibleViewController ?? self
+        } else {
+            return self
+        }
+    }
+}
+
+// Shake oritention
+public enum ShakeDirection: Int {
+    case horizontal
+    case vertical
+}
+
+public extension UIView {
+    func shake(direction: ShakeDirection = .horizontal, times: Int = 5,
+               interval: TimeInterval = 0.1, delta: CGFloat = 2,
+               completion: (() -> Void)? = nil)
+    {
+        UIView.animate(withDuration: interval, animations: { () -> Void in
+            switch direction {
+            case .horizontal:
+                self.layer.setAffineTransform(CGAffineTransform(translationX: delta, y: 0))
+            case .vertical:
+                self.layer.setAffineTransform(CGAffineTransform(translationX: 0, y: delta))
+            }
+        }) { (_) -> Void in
+            if times == 0 {
+                // last shaking finish, reset location, callback
+                UIView.animate(withDuration: interval, animations: { () -> Void in
+                    self.layer.setAffineTransform(CGAffineTransform.identity)
+                }, completion: { (_) -> Void in
+                    completion?()
+                })
+            } else {
+                // not last shaking, continue
+                self.shake(direction: direction, times: times - 1, interval: interval,
+                           delta: delta * -1, completion: completion)
+            }
+        }
+    }
+}
+
+public extension UIView {
+    var x: CGFloat {
+        set {
+            var frame = self.frame
+            frame.origin.x = newValue
+            self.frame = frame
+        }
+        get {
+            return frame.origin.x
+        }
+    }
+
+    var y: CGFloat {
+        set {
+            var frame = self.frame
+            frame.origin.y = newValue
+            self.frame = frame
+        }
+        get {
+            return frame.origin.y
+        }
+    }
+
+    var centerX: CGFloat {
+        set {
+            var center = self.center
+            center.x = newValue
+            self.center = center
+        }
+        get {
+            return center.x
+        }
+    }
+
+    var centerY: CGFloat {
+        set {
+            var center = self.center
+            center.y = newValue
+            self.center = center
+        }
+        get {
+            return center.y
+        }
+    }
+
+    var width: CGFloat {
+        set {
+            var frame = self.frame
+            frame.size.width = newValue
+            self.frame = frame
+        }
+        get {
+            return frame.size.width
+        }
+    }
+
+    var height: CGFloat {
+        set {
+            var frame = self.frame
+            frame.size.height = newValue
+            self.frame = frame
+        }
+        get {
+            return frame.size.height
+        }
+    }
+
+    var size: CGSize {
+        set {
+            var frame = self.frame
+            frame.size = newValue
+            self.frame = frame
+        }
+        get {
+            return frame.size
+        }
+    }
+
+    var origin: CGPoint {
+        set {
+            var frame = self.frame
+            frame.origin = newValue
+            self.frame = frame
+        }
+        get {
+            return frame.origin
+        }
+    }
+
+    var bottomY: CGFloat {
+        set {
+            var frame = self.frame
+            frame.origin.y = newValue - frame.size.height
+            self.frame = frame
+        }
+        get {
+            return height + y
+        }
+    }
+
+    var rightX: CGFloat {
+        set {
+            var frame = self.frame
+            frame.origin.x = newValue - frame.size.width
+            self.frame = frame
+        }
+        get {
+            return width + x
+        }
+    }
+
+    // MARK: - UIView round corner
+
+    ///
+    /// - Parameter cornerRadius: radius
+    func roundedCorners(cornerRadius: CGFloat) {
+        roundedCorners(cornerRadius: cornerRadius, borderWidth: 0, borderColor: nil)
+    }
+
+    ///
+    /// - Parameters:
+    ///   - cornerRadius:
+    ///   - borderWidth:
+    ///   - borderColor:
+    func roundedCorners(cornerRadius: CGFloat?, borderWidth: CGFloat?, borderColor: UIColor?) {
+        layer.cornerRadius = cornerRadius!
+        layer.borderWidth = borderWidth!
+        layer.borderColor = borderColor?.cgColor
+        layer.masksToBounds = true
+    }
+
+    ///
+    /// - Parameters:
+    ///   - cornerRadius:
+    ///   - rectCorner:
+    func roundedCorners(cornerRadius: CGFloat?, rectCorner: UIRectCorner?) {
+        let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: rectCorner!, cornerRadii: CGSize(width: cornerRadius!, height: cornerRadius!))
+        let layer = CAShapeLayer()
+        layer.frame = bounds
+        layer.path = path.cgPath
+        self.layer.mask = layer
+    }
+
+    ///
+    /// - Parameters:
+    ///   - colors:
+    ///   - locations:
+    ///   - startPoint: [0...1]
+    ///   - endPoint: [0...1]
+    func gradientColor(colors: [CGColor], locations: [NSNumber], startPoint: CGPoint, endPoint: CGPoint) {
+        let gradientLayer = CAGradientLayer()
+        gradientLayer.colors = colors
+        gradientLayer.locations = locations
+        /*
+         // vertical
+         gradientLayer.startPoint = CGPoint(x: 0, y: 0)
+         gradientLayer.endPoint = CGPoint(x: 0, y: 1)
+         */
+        gradientLayer.startPoint = startPoint
+        gradientLayer.endPoint = endPoint
+        gradientLayer.frame = frame
+        layer.insertSublayer(gradientLayer, at: 0)
+    }
+
+    // MARK: - UIView blur
+
+    ///
+    /// - Parameter style: UIBlurEffectStyle
+    func addBlurEffect(style _: UIBlurEffect.Style) {
+        let effect = UIBlurEffect(style: UIBlurEffect.Style.light)
+        let effectView = UIVisualEffectView(effect: effect)
+        effectView.frame = bounds
+        backgroundColor = .clear
+        addSubview(effectView)
+        sendSubviewToBack(effectView)
+    }
+}
+
+public extension UIView {
+    /// 往当前视图添加一个子视图
+    /// - Parameters:
+    ///   - rect: 子视图大小
+    ///   - bgColor: 子视图背景色
+    /// - Returns: 子视图
+    func nx_addView(rect: CGRect = .zero, bgColor: UIColor = .white) -> UIView {
+        let view = UIView(frame: rect)
+        view.backgroundColor = bgColor
+        addSubview(view)
+        return view
+    }
+
+    /// 往当前视图添加UIImageView
+    /// - Parameters:
+    ///   - image: 图片对象
+    ///   - rect: UIImageView
+    ///   - contentMode: 图片填充模式
+    /// - Returns: 图片
+    func nx_addImageView(image: UIImage?, rect: CGRect = .zero, contentMode: ContentMode = .scaleAspectFit) -> UIImageView {
+        let imageView = UIImageView(frame: rect)
+        imageView.image = image
+        imageView.contentMode = contentMode
+        addSubview(imageView)
+        return imageView
+    }
+
+    /// 添加文本控件
+    /// - Parameters:
+    ///   - fontSize: 文本大小
+    ///   - text: 文本
+    ///   - textColor: 文本颜色
+    ///   - bgColor: 背景颜色
+    /// - Returns: 文本控件
+    func nx_addLabel(fontSize: CGFloat, text: String, textColor: UIColor, bgColor: UIColor) -> UILabel {
+        return nx_addLabel(font: UIFont.systemFont(ofSize: fontSize),
+                           text: text,
+                           textColor: textColor,
+                           bgColor: bgColor)
+    }
+
+    /// 添加文本控件
+    /// - Parameters:
+    ///   - font: 文本大小
+    ///   - text: 文本
+    ///   - textColor: 文本颜色
+    ///   - bgColor: 背景颜色
+    /// - Returns: 文本控件
+    func nx_addLabel(font: UIFont, text: String, textColor: UIColor, bgColor: UIColor) -> UILabel {
+        let label = UILabel(frame: .zero)
+        label.font = font
+        label.text = text
+        label.textColor = textColor
+        label.backgroundColor = bgColor
+        addSubview(label)
+        return label
+    }
+
+    /// 添加按钮控件
+    /// - Parameters:
+    ///   - rect: 控件大小
+    ///   - title: 标题
+    ///   - titleColor: 标题颜色
+    ///   - font: 字体
+    ///   - image: 图片
+    ///   - bgImg: 背景图片
+    ///   - target: 事件响应者
+    ///   - action: 事件响应方法
+    ///   - event: 响应事件
+    /// - Returns: 按钮
+    func nx_addButton(rect: CGRect, title: String, titleColor: UIColor, font: UIFont, image: UIImage?, bgImg: UIImage?, target: Any?, action: Selector?, event: UIControl.Event?) -> UIButton {
+        let btn = UIButton(type: .custom)
+        btn.frame = rect
+        btn.setTitle(title, for: .normal)
+        btn.setTitle(title, for: .highlighted)
+        btn.setTitleColor(titleColor, for: .normal)
+        btn.setTitleColor(titleColor, for: .highlighted)
+        btn.setImage(image, for: .normal)
+        btn.setImage(image, for: .highlighted)
+        btn.setBackgroundImage(bgImg, for: .normal)
+        btn.setBackgroundImage(bgImg, for: .highlighted)
+        btn.titleLabel?.font = font
+        if let sel = action, let e = event {
+            btn.addTarget(target, action: sel, for: e)
+        }
+        addSubview(btn)
+        return btn
+    }
+
+    /// 添加一个文本类型的按钮控件
+    /// - Parameters:
+    ///   - rect: 按钮大小
+    ///   - title: 文本
+    ///   - titleColor: 文本颜色
+    ///   - target: 事件响应者
+    ///   - action: 事件响应方法
+    ///   - event:响应事件
+    /// - Returns: 按钮控件
+    func nx_addButton(rect: CGRect, title: String, titleColor: UIColor, target: Any?, action: Selector?, event: UIControl.Event?) -> UIButton {
+        return nx_addButton(rect: rect,
+                            title: title,
+                            titleColor: titleColor,
+                            font: UIFont.systemFont(ofSize: 14),
+                            image: nil,
+                            bgImg: nil,
+                            target: target,
+                            action: action,
+                            event: event)
+    }
+
+    /// 添加图片类型按钮
+    /// - Parameters:
+    ///   - rect: 按钮大小
+    ///   - image: 图片
+    ///   - target: 事件响应者
+    ///   - action: 事件响应方法
+    ///   - event: 响应事件
+    /// - Returns: 按钮控件
+    func nx_addButton(rect: CGRect, image: UIImage, target: Any?, action: Selector?, event: UIControl.Event?) -> UIButton {
+        return nx_addButton(rect: rect,
+                            title: "",
+                            titleColor: .white,
+                            font: UIFont.systemFont(ofSize: 14),
+                            image: image,
+                            bgImg: nil,
+                            target: target,
+                            action: action,
+                            event: event)
+    }
+
+    /// 添加tableView
+    /// - Parameters:
+    ///   - rect: 大小
+    ///   - delegate: delegate对象
+    ///   - dataSource: dataSource 对象
+    /// - Returns: 表视图
+    func nx_addTableView(rect: CGRect, delegate: UITableViewDelegate?, dataSource: UITableViewDataSource?) -> UITableView {
+        let tableView = UITableView(frame: rect)
+        tableView.delegate = delegate
+        tableView.dataSource = dataSource
+        backgroundColor = .white
+        tableView.tableFooterView = UIView()
+        if #available(iOS 11.0, *) {
+            tableView.contentInsetAdjustmentBehavior = .never
+        }
+        return tableView
+    }
+}

+ 32 - 0
BFCommonKit/Classes/BFCategorys/UIControl+NXCategory.h

@@ -0,0 +1,32 @@
+//
+//  UIControl+acceptEventInterval.h
+//  NXlib
+//
+//  Created by AK on 15/9/15.
+//  Copyright (c) 2015年 AK. All rights reserved.
+//
+
+// 本类的作用
+// 防止多次连续点击事件,加一个两次点击的时间间隔,专治各种测试人员-_-!
+// 使用 addTarget:action:forControlEvents 给对象添加事件的都可以加时间间隔 如
+// UIButton、UISwitch、UITextField
+
+/*
+ *	UIButton * testBtn;
+ *  testBtn.uxy_acceptEventInterval = 2.5;
+ */
+#import <UIKit/UIKit.h>
+
+@interface UIControl (NXCategory)
+
+/**
+ *  设置重复点击加间隔。
+ */
+@property(nonatomic, assign) NSTimeInterval uxy_acceptEventInterval;
+
+/**
+ *  忽略本次点击。
+ */
+@property(nonatomic) BOOL ignoreEvent;
+
+@end

+ 68 - 0
BFCommonKit/Classes/BFCategorys/UIControl+NXCategory.m

@@ -0,0 +1,68 @@
+//
+//  UIControl+acceptEventInterval.m
+//  NXlib
+//
+//  Created by AK on 15/9/15.
+//  Copyright (c) 2015年 AK. All rights reserved.
+//
+
+#import "UIControl+NXCategory.h"
+
+#if TARGET_OS_IPHONE
+#import <objc/message.h>
+#import <objc/runtime.h>
+#else
+#import <objc/objc-class.h>
+#endif
+
+@implementation UIControl (NXCategory)
+
+static const char *UIControl_acceptEventInterval = "UIControl_acceptEventInterval";
+static const char *UIControl_ignoreEvent = "UIControl_ignoreEvent";
+
+//改变两个方法的实现。在类第一次使用的时候回调用这个方法
++ (void)load
+{
+    Method a = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
+    Method b = class_getInstanceMethod(self, @selector(__uxy_sendAction:to:forEvent:));
+    //改变两个方法的实现
+    method_exchangeImplementations(a, b);  // isnt
+}
+//通过关联对象重写get和set方法
+- (NSTimeInterval)uxy_acceptEventInterval
+{
+    return [objc_getAssociatedObject(self, UIControl_acceptEventInterval) doubleValue];
+}
+
+- (void)setUxy_acceptEventInterval:(NSTimeInterval)uxy_acceptEventInterval
+{
+    objc_setAssociatedObject(self, UIControl_acceptEventInterval, @(uxy_acceptEventInterval),
+                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+#pragma mark 现在是否可点的get和set。通过关联对象。
+- (void)setIgnoreEvent:(BOOL)ignoreEvent
+{
+    objc_setAssociatedObject(self, UIControl_ignoreEvent, @(ignoreEvent), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+- (BOOL)ignoreEvent { return [objc_getAssociatedObject(self, UIControl_ignoreEvent) boolValue]; }
+- (void)__uxy_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
+{
+    if (self.ignoreEvent)
+    {
+        NSLog(@"无效点击!!!!!!!!!!");
+        return;
+    }
+    if (self.uxy_acceptEventInterval > 0)
+    {
+        self.ignoreEvent = YES;
+        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.uxy_acceptEventInterval * NSEC_PER_SEC)),
+                       dispatch_get_main_queue(), ^{
+                           self.ignoreEvent = NO;
+                       });
+    }
+
+    //调用系统实现
+    [self __uxy_sendAction:action to:target forEvent:event];
+}
+
+@end

+ 201 - 0
BFCommonKit/Classes/BFCategorys/UIImage+NXCategory.h

@@ -0,0 +1,201 @@
+//
+//  UIImage+UIImage_NXCategory.h
+//  AKImovie
+//
+//  Created by AK on 16/2/21.
+//  Copyright © 2016年 ak. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+typedef NS_ENUM(NSInteger, NXCropImageStyle) {
+    NXCropImageStyleRight = 0,               // 右半部分
+    NXCropImageStyleCenter = 1,              // 中间部分
+    NXCropImageStyleLeft = 2,                // 左半部分
+    NXCropImageStyleRightOneOfThird = 3,     // 右侧三分之一部分
+    NXCropImageStyleCenterOneOfThird = 4,    // 中间三分之一部分
+    NXCropImageStyleLeftOneOfThird = 5,      // 左侧三分之一部分
+    NXCropImageStyleRightQuarter = 6,        // 右侧四分之一部分
+    NXCropImageStyleCenterRightQuarter = 7,  // 中间右侧四分之一部分
+    NXCropImageStyleCenterLeftQuarter = 8,   // 中间左侧四分之一部分
+    NXCropImageStyleLeftQuarter = 9,         // 左侧四分之一部分
+};
+
+@interface UIImage (NXCategory)
+
+#pragma mark - blur 效果
+/**
+ 给图片打马赛克
+ @param image 原始图片
+ @param blur 值越 blurry 就越大
+ @return 处理后的图片
+ */
++ (UIImage *)nx_blurryImage:(UIImage *)image withBlurLevel:(CGFloat)blur;
+
+/**
+  boxblur image 这个要在整理
+
+  @param toBlurImage 要处理的图片
+  @return 处理后图片
+ */
++ (UIImage *)nx_boxblurImage:(UIImage *)toBlurImage;
+
+#pragma mark - 旋转
+/**
+  照片旋转90度,如从系统相册中取出的原图要转正
+
+ @param aImage 原图
+ @param isFront YES 为前置拍照
+ @return 转正后图片
+ */
++ (UIImage *)nx_fixOrientation:(UIImage *)aImage isFront:(BOOL)isFront;
+
+/**
+ 旋转图片
+
+ @param image 原图
+ @param orientation 旋转的方向
+ @return 旋转后的图片
+ */
++ (UIImage *)nx_rotationImage:(UIImage *)image orientation:(UIImageOrientation)orientation;
+
+#pragma mark - 缩放
+/**
+ 等比缩放图片
+
+ @param size 放到的大小(单位为像素)
+ @return 处理后的图片
+ */
+- (UIImage *)nx_scaleToSize:(CGSize)size;
+
+/**
+ 等比缩放图片 按照最短边缩放
+ @param maxLength 边长最大值 (单位为像素)
+ @return 处理后的图片
+ */
+- (UIImage *)nx_scaleWithMaxLength:(float)maxLength;
+
+#pragma mark - 截取
+/**
+ 截取 uiimage 指定区域
+
+ @param style 类型为 NXCropImageStyle
+ @return 裁剪后的图片
+ */
+- (UIImage *)nx_imageByCroppingWithStyle:(NXCropImageStyle)style;
+
+/**
+  截取 uiimage 指定区域
+
+ @param rect 裁剪区域
+ @return 裁剪后的图片
+ */
+- (UIImage *)imageByCroppingWithRect:(CGRect)rect;
+
+
+/**
+ 将图片按照最短边等比截取图片中间部分
+
+ @return 截取后到正方形图片
+ */
+- (UIImage *)nx_cropImageToSquare;
+
+/**
+ *  将图片等比绘制到正方形画布中并重新生成新图
+ *
+ *  @return 处理后的图片
+ */
+- (UIImage *)nx_zoomImageToSquare;
+
+/**
+ 将图片等比缩放的指定的画布中并生成新图。(跟画布比例不一样的做 左右或者上下留白处理)
+
+ @param size 指定画布大小
+ @return 处理后的新图
+ */
+- (UIImage *)nx_zoomWithSize:(CGSize)size;
+
+/**
+ 高清截屏 opaque 为no 有透明度速度会慢一些
+
+ @param view 指定的VIEW
+ @return 截屏图片
+ */
++ (UIImage *)nx_screenHierarchyShots:(UIView *)view;
+
+/**
+ 高清截屏
+
+ @param view 指定的VIEW
+ @param opaque 透明开关,如果图形完全不用透明,设置为YES以优化位图的存储。
+ @return 截屏图片
+ */
++ (UIImage *)nx_screenHierarchyShots:(UIView *)view isOpaque:(BOOL)opaque;
+
+/**
+ 获得裁剪图片
+
+ e.g.
+ int squalWidth = MIN(self.clipImage.size.width, self.clipImage.size.height);
+
+ float clipX = _clipScroll.contentOffset.x;
+ float clipY = _clipScroll.contentOffset.y;
+ CGRect rect = CGRectMake(clipX, clipY, NX_MAIN_SCREEN_WIDTH, NX_MAIN_SCREEN_WIDTH);
+
+ clipedImage =
+ [UIImage nx_cropImageView:_bigImageView toRect:rect zoomScale:1
+ containerView:_backView outputWith:squalWidth];
+
+ @param imageView 原始VIEW
+ @param rect 截取区域
+ @param zoomScale 缩放大小
+ @param containerView 显示区域VIEW
+ @param outputWith 输出大小
+ @return 处理后图片
+ */
++ (UIImage *)nx_cropImageView:(UIImageView *)imageView
+                       toRect:(CGRect)rect
+                    zoomScale:(double)zoomScale
+                containerView:(UIView *)containerView
+                   outputWith:(CGFloat)outputWith;
+
+#pragma mark - 圆角
+/**
+ 切圆角 可防止离屏渲染
+ e.g.
+ UIImage *placeHolder = [[UIImage imageNamed:@"userIcon"] circleImage];
+
+ @param img 原图片
+ @return 处理后的图片
+ */
++ (UIImage *)nx_circleImage:(UIImage *)img;
+
+/** 切圆角 可防止离屏渲染
+ * @param image 需要进行圆角的图片
+ * @param direction 切割的方向
+ * @param cornerRadii 圆角半径
+ * @param borderWidth 边框宽度
+ * @param borderColor 边框颜色
+ * @param backgroundColor 背景色
+ * @return 处理后的图片
+ */
++ (UIImage *)nx_circleImage:(UIImage *)image cuttingDirection:(UIRectCorner)direction cornerRadii:(CGFloat)cornerRadii borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor backgroundColor:(UIColor *)backgroundColor;
+
+/**
+ 获取当前屏幕大小的的开屏页图片
+ 
+ @return 开屏页图片
+ */
++ (UIImage *)nx_launchImage;
+
+
+/**
+ 把指定颜色背景变成透明
+
+ @param image 原图数据
+ @param color 原背景色
+ @return 背景透明后的图
+ */
++ (UIImage*)transparentBackClear:(UIImage*)image color:(UIColor*)color;
+
+@end

+ 642 - 0
BFCommonKit/Classes/BFCategorys/UIImage+NXCategory.m

@@ -0,0 +1,642 @@
+//
+//  UIImage+UIImage_NXCategory.m
+//  AKImovie
+//
+//  Created by AK on 16/2/21.
+//  Copyright © 2016年 ak. All rights reserved.
+//
+
+#import "UIImage+NXCategory.h"
+#import <Accelerate/Accelerate.h>
+
+@implementation UIImage (NXCategory)
+
+#pragma mark - blur 效果
++ (UIImage *)nx_blurryImage:(UIImage *)image withBlurLevel:(CGFloat)blur
+{
+    CIImage *inputImage = [CIImage imageWithCGImage:image.CGImage];
+    CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"
+                                  keysAndValues:kCIInputImageKey, inputImage, @"inputRadius", @(blur), nil];
+
+    CIImage *outputImage = filter.outputImage;
+    CIContext *context = [CIContext contextWithOptions:nil];
+    CGImageRef outImage = [context createCGImage:outputImage fromRect:[outputImage extent]];
+    return [UIImage imageWithCGImage:outImage];
+}
+
++ (UIImage *)nx_boxblurImage:(UIImage *)toBlurImage
+{
+    UIImage *newImage =
+
+        [toBlurImage nx_scaleToSize:CGSizeMake(toBlurImage.size.width / 2., toBlurImage.size.height / 2.)];
+
+    NSData *jpgData = UIImageJPEGRepresentation(newImage, 0.01);
+
+    UIImage *image = [UIImage imageWithData:jpgData];
+    CGFloat blur = 0.3f;
+
+    int boxSize = (int)(blur * 40);
+    boxSize = boxSize - (boxSize % 2) + 1;
+
+    CGImageRef img = image.CGImage;
+    vImage_Buffer inBuffer, outBuffer;
+    vImage_Error error;
+    void *pixelBuffer;
+
+    // create vImage_Buffer with data from CGImageRef
+    CGDataProviderRef inProvider = CGImageGetDataProvider(img);
+    CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
+
+    inBuffer.width = CGImageGetWidth(img);
+    inBuffer.height = CGImageGetHeight(img);
+    inBuffer.rowBytes = CGImageGetBytesPerRow(img);
+
+    inBuffer.data = (void *)CFDataGetBytePtr(inBitmapData);
+
+    // create vImage_Buffer for output
+    pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));
+
+    if (pixelBuffer == NULL) NSLog(@"No pixelbuffer");
+
+    outBuffer.data = pixelBuffer;
+    outBuffer.width = CGImageGetWidth(img);
+    outBuffer.height = CGImageGetHeight(img);
+    outBuffer.rowBytes = CGImageGetBytesPerRow(img);
+
+    // perform convolution
+    error =
+        vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend)
+            ?: vImageBoxConvolve_ARGB8888(&outBuffer, &inBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend)
+                   ?: vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL,
+                                                 kvImageEdgeExtend);
+
+    if (error)
+    {
+        NSLog(@"error from convolution %ld", error);
+    }
+
+    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+    CGContextRef ctx = CGBitmapContextCreate(outBuffer.data, outBuffer.width, outBuffer.height, 8, outBuffer.rowBytes,
+                                             colorSpace, (CGBitmapInfo)kCGImageAlphaNoneSkipLast);
+    CGImageRef imageRef = CGBitmapContextCreateImage(ctx);
+    UIImage *returnImage = [UIImage imageWithCGImage:imageRef];
+
+    // clean up
+    CGContextRelease(ctx);
+    CGColorSpaceRelease(colorSpace);
+
+    free(pixelBuffer);
+    CFRelease(inBitmapData);
+    CGImageRelease(imageRef);
+
+    return returnImage;
+}
+
+#pragma mark - 旋转
++ (UIImage *)nx_fixOrientation:(UIImage *)aImage isFront:(BOOL)isFront;
+{
+    // No-op if the orientation is already correct
+    if (aImage.imageOrientation == UIImageOrientationUp) return aImage;
+
+    // We need to calculate the proper transformation to make the image upright.
+    // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
+    CGAffineTransform transform = CGAffineTransformIdentity;
+
+    if (isFront)
+    {
+        transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
+        transform = CGAffineTransformScale(transform, -1, 1);
+    }
+
+    switch (aImage.imageOrientation)
+    {
+        case UIImageOrientationDown:
+        case UIImageOrientationDownMirrored:
+            transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height);
+            transform = CGAffineTransformRotate(transform, M_PI);
+            break;
+
+        case UIImageOrientationLeft:
+        case UIImageOrientationLeftMirrored:
+            transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
+            transform = CGAffineTransformRotate(transform, M_PI_2);
+            break;
+
+        case UIImageOrientationRight:
+        case UIImageOrientationRightMirrored:
+            transform = CGAffineTransformTranslate(transform, 0, aImage.size.height);
+            transform = CGAffineTransformRotate(transform, -M_PI_2);
+            break;
+        default:
+            break;
+    }
+
+    switch (aImage.imageOrientation)
+    {
+        case UIImageOrientationUpMirrored:
+        case UIImageOrientationDownMirrored:
+            transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
+            transform = CGAffineTransformScale(transform, -1, 1);
+            break;
+
+        case UIImageOrientationLeftMirrored:
+        case UIImageOrientationRightMirrored:
+            transform = CGAffineTransformTranslate(transform, aImage.size.height, 0);
+            transform = CGAffineTransformScale(transform, -1, 1);
+            break;
+        default:
+            break;
+    }
+
+    // Now we draw the underlying CGImage into a new context, applying the
+    // transform
+    // calculated above.
+    CGContextRef ctx =
+        CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height, CGImageGetBitsPerComponent(aImage.CGImage),
+                              0, CGImageGetColorSpace(aImage.CGImage), CGImageGetBitmapInfo(aImage.CGImage));
+    CGContextConcatCTM(ctx, transform);
+    switch (aImage.imageOrientation)
+    {
+        case UIImageOrientationLeft:
+        case UIImageOrientationLeftMirrored:
+        case UIImageOrientationRight:
+        case UIImageOrientationRightMirrored:
+            // Grr...
+            CGContextDrawImage(ctx, CGRectMake(0, 0, aImage.size.height, aImage.size.width), aImage.CGImage);
+            break;
+
+        default:
+            CGContextDrawImage(ctx, CGRectMake(0, 0, aImage.size.width, aImage.size.height), aImage.CGImage);
+            break;
+    }
+
+    // And now we just create a new UIImage from the drawing context
+    CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
+    UIImage *img = [UIImage imageWithCGImage:cgimg];
+    CGContextRelease(ctx);
+    CGImageRelease(cgimg);
+    return img;
+}
+
+// 旋转
++ (UIImage *)nx_rotationImage:(UIImage *)image orientation:(UIImageOrientation)orientation
+{
+    long double rotate = 0.0;
+    CGRect rect;
+    float translateX = 0;
+    float translateY = 0;
+    float scaleX = 1.0;
+    float scaleY = 1.0;
+
+    switch (orientation)
+    {
+        case UIImageOrientationLeft:
+            rotate = M_PI_2;
+            rect = CGRectMake(0, 0, image.size.height, image.size.width);
+            translateX = 0;
+            translateY = -rect.size.width;
+            scaleY = rect.size.width / rect.size.height;
+            scaleX = rect.size.height / rect.size.width;
+            break;
+        case UIImageOrientationRight:
+            rotate = 3 * M_PI_2;
+            rect = CGRectMake(0, 0, image.size.height, image.size.width);
+            translateX = -rect.size.height;
+            translateY = 0;
+            scaleY = rect.size.width / rect.size.height;
+            scaleX = rect.size.height / rect.size.width;
+            break;
+        case UIImageOrientationDown:
+            rotate = M_PI;
+            rect = CGRectMake(0, 0, image.size.width, image.size.height);
+            translateX = -rect.size.width;
+            translateY = -rect.size.height;
+            break;
+        default:
+            rotate = 0.0;
+            rect = CGRectMake(0, 0, image.size.width, image.size.height);
+            translateX = 0;
+            translateY = 0;
+            break;
+    }
+
+    UIGraphicsBeginImageContext(rect.size);
+    CGContextRef context = UIGraphicsGetCurrentContext();
+    //做CTM变换
+    CGContextTranslateCTM(context, 0.0, rect.size.height);
+    CGContextScaleCTM(context, 1.0, -1.0);
+    CGContextRotateCTM(context, rotate);
+    CGContextTranslateCTM(context, translateX, translateY);
+
+    CGContextScaleCTM(context, scaleX, scaleY);
+    //绘制图片
+    CGContextDrawImage(context, CGRectMake(0, 0, rect.size.width, rect.size.height), image.CGImage);
+
+    UIImage *newPic = UIGraphicsGetImageFromCurrentImageContext();
+    NSLog(@"image size %f---%f", image.size.width, image.size.height);
+    UIGraphicsEndImageContext();
+    return newPic;
+}
+
+#pragma mark - 缩放
+- (UIImage *)nx_scaleToSize:(CGSize)size
+{
+    CGFloat width = CGImageGetWidth(self.CGImage);
+    CGFloat height = CGImageGetHeight(self.CGImage);
+
+    float verticalRadio = size.height * 1.0 / height;
+    float horizontalRadio = size.width * 1.0 / width;
+
+    float radio = 1;
+    if (verticalRadio > 1 && horizontalRadio > 1)
+    {
+        radio = verticalRadio > horizontalRadio ? horizontalRadio : verticalRadio;
+    }
+    else
+    {
+        radio = verticalRadio < horizontalRadio ? verticalRadio : horizontalRadio;
+    }
+
+    width = width * radio;
+    height = height * radio;
+
+    int xPos = (size.width - width) / 2;
+    int yPos = (size.height - height) / 2;
+
+    // 创建一个bitmap的context
+    // 并把它设置成为当前正在使用的context
+    UIGraphicsBeginImageContext(size);
+
+    // 绘制改变大小的图片
+    [self drawInRect:CGRectMake(xPos, yPos, width, height)];
+
+    // 从当前context中创建一个改变大小后的图片
+    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
+
+    // 使当前的context出堆栈
+    UIGraphicsEndImageContext();
+
+    // 返回新的改变大小后的图片
+    return scaledImage;
+}
+
+//按照最短边缩放 maxlength 边长最大值
+- (UIImage *)nx_scaleWithMaxLength:(float)maxLength
+{
+    if (self.size.width > maxLength || self.size.height > maxLength)
+    {
+        float maxWidth = maxLength;
+        float maxHeight = maxLength;
+
+        if (self.size.width != self.size.height)
+        {
+            if (self.size.width > self.size.height)
+            {
+                //按照宽 来缩放
+                float imageScale = maxLength / self.size.width;
+                maxHeight = self.size.height * imageScale;
+            }
+            else if (self.size.width < self.size.height)
+            {
+                float imageScale = maxLength / self.size.height;
+
+                maxWidth = self.size.width * imageScale;
+            }
+        }
+        // 返回新的改变大小后的图片
+        return [self nx_scaleToSize:CGSizeMake(maxWidth, maxHeight)];
+    }
+
+    return self;
+}
+
+#pragma mark - 截取
+- (UIImage *)nx_imageByCroppingWithStyle:(NXCropImageStyle)style
+{
+    CGRect rect = CGRectZero;
+    switch (style)
+    {
+        case NXCropImageStyleLeft:
+            rect = CGRectMake(0, 0, self.size.width / 2, self.size.height);
+            break;
+        case NXCropImageStyleCenter:
+            rect = CGRectMake(self.size.width / 4, 0, self.size.width / 2, self.size.height);
+            break;
+        case NXCropImageStyleRight:
+            rect = CGRectMake(self.size.width / 2, 0, self.size.width / 2, self.size.height);
+            break;
+        case NXCropImageStyleLeftOneOfThird:
+            rect = CGRectMake(0, 0, self.size.width / 3, self.size.height);
+            break;
+        case NXCropImageStyleCenterOneOfThird:
+            rect = CGRectMake(self.size.width / 3, 0, self.size.width / 3, self.size.height);
+            break;
+        case NXCropImageStyleRightOneOfThird:
+            rect = CGRectMake(self.size.width / 3 * 2, 0, self.size.width / 3, self.size.height);
+            break;
+        case NXCropImageStyleLeftQuarter:
+            rect = CGRectMake(0, 0, self.size.width / 4, self.size.height);
+            break;
+        case NXCropImageStyleCenterLeftQuarter:
+            rect = CGRectMake(self.size.width / 4, 0, self.size.width / 4, self.size.height);
+            break;
+        case NXCropImageStyleCenterRightQuarter:
+            rect = CGRectMake(self.size.width / 4 * 2, 0, self.size.width / 4, self.size.height);
+            break;
+        case NXCropImageStyleRightQuarter:
+            rect = CGRectMake(self.size.width / 4 * 3, 0, self.size.width / 4, self.size.height);
+            break;
+        default:
+            break;
+    }
+
+    return [self imageByCroppingWithRect:rect];
+}
+
+- (UIImage *)imageByCroppingWithRect:(CGRect)rect
+{
+    CGImageRef imageRef = self.CGImage;
+    CGImageRef imagePartRef = CGImageCreateWithImageInRect(imageRef, rect);
+    UIImage *cropImage = [UIImage imageWithCGImage:imagePartRef];
+    CGImageRelease(imagePartRef);
+    return cropImage;
+}
+
+- (UIImage *)nx_cropImageToSquare{
+
+    if(self.size.width == self.size.height)
+    {
+        return self;
+    }
+    double w = self.size.width;
+    double h = self.size.height;
+    double m = MIN(w, h);
+    CGRect rect = CGRectMake((self.size.width - m)/2.0f , (self.size.height - m)/2.0f, m, m);
+    return [self imageByCroppingWithRect:rect];
+}
+
+- (UIImage *)nx_zoomWithSize:(CGSize)size{
+
+    if(self == nil)
+    {
+        return nil;
+    }
+    
+    double w  = self.size.width;
+    double h =self.size.height;
+    double vRatio = w / size.width;
+    double hRatio = h / size.height;
+    double ratio = MAX(vRatio, hRatio);
+    w /= ratio;
+    h /= ratio;
+    CGRect drawRect = CGRectMake((size.width - w)/2.0f , (size.height - h)/2.0f, w, h);
+    // 创建一个bitmap的context
+    // 并把它设置成为当前正在使用的context
+    UIGraphicsBeginImageContext(size);
+    // 绘制改变大小的图片
+    [self drawInRect:drawRect];
+    // 从当前context中创建一个改变大小后的图片
+    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
+    // 使当前的context出堆栈
+    UIGraphicsEndImageContext();
+    return  scaledImage;
+    
+}
+
+
+- (UIImage *)nx_zoomImageToSquare
+{
+    if (self == nil)
+    {
+        return nil;
+    }
+    double tw = MIN(self.size.width, self.size.height);
+
+    return [self nx_scaleToSize:CGSizeMake(tw, tw)];
+}
+
+//截屏 有透明的
++ (UIImage *)nx_screenHierarchyShots:(UIView *)view { return [UIImage nx_screenHierarchyShots:view isOpaque:NO]; }
+//高清截屏 opaque 是否有透明图层
++ (UIImage *)nx_screenHierarchyShots:(UIView *)view isOpaque:(BOOL)opaque
+{
+    // size——同UIGraphicsBeginImageContext
+    // opaque—透明开关,如果图形完全不用透明,设置为YES以优化位图的存储。
+    // scale—–缩放因子
+    UIGraphicsBeginImageContextWithOptions(view.bounds.size, opaque, 0);
+    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
+    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+    return image;
+}
+
+/// 获得裁剪后的图片
++ (UIImage *)nx_cropImageView:(UIImageView *)imageView
+                       toRect:(CGRect)rect
+                    zoomScale:(double)zoomScale
+                containerView:(UIView *)containerView
+                   outputWith:(CGFloat)outputWith
+{
+    CGAffineTransform transform = CGAffineTransformIdentity;
+    // 平移的处理
+    CGRect imageViewRect = [imageView convertRect:imageView.bounds toView:containerView];
+    CGPoint point = CGPointMake(imageViewRect.origin.x + imageViewRect.size.width / 2,
+                                imageViewRect.origin.y + imageViewRect.size.height / 2);
+
+    CGPoint zeroPoint =
+        CGPointMake(CGRectGetWidth(containerView.frame) / 2., CGRectGetHeight(containerView.frame) / 2.);
+
+    CGPoint translation = CGPointMake(point.x - zeroPoint.x, point.y - zeroPoint.y);
+    transform = CGAffineTransformTranslate(transform, translation.x, translation.y);
+    // 缩放的处理
+    transform = CGAffineTransformScale(transform, zoomScale, zoomScale);
+
+    CGImageRef imageRef = [self nx_newTransformedImage:transform
+                                           sourceImage:imageView.image.CGImage
+                                            sourceSize:imageView.image.size
+                                           outputWidth:outputWith
+                                              cropSize:rect.size
+                                         imageViewSize:imageView.frame.size];
+    UIImage *cropedImage = [UIImage imageWithCGImage:imageRef];
+    CGImageRelease(imageRef);
+    return cropedImage;
+}
+
++ (CGImageRef)nx_newTransformedImage:(CGAffineTransform)transform
+                         sourceImage:(CGImageRef)sourceImage
+                          sourceSize:(CGSize)sourceSize
+                         outputWidth:(CGFloat)outputWidth
+                            cropSize:(CGSize)cropSize
+                       imageViewSize:(CGSize)imageViewSize
+{
+    CGImageRef source = [self nx_newScaledImage:sourceImage toSize:sourceSize];
+
+    CGFloat aspect = cropSize.height / cropSize.width;
+    CGSize outputSize = CGSizeMake(outputWidth, outputWidth * aspect);
+
+    CGContextRef context =
+        CGBitmapContextCreate(NULL, outputSize.width, outputSize.height, CGImageGetBitsPerComponent(source), 0,
+                              CGImageGetColorSpace(source), CGImageGetBitmapInfo(source));
+    CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
+    CGContextFillRect(context, CGRectMake(0, 0, outputSize.width, outputSize.height));
+
+    CGAffineTransform uiCoords =
+        CGAffineTransformMakeScale(outputSize.width / cropSize.width, outputSize.height / cropSize.height);
+    uiCoords = CGAffineTransformTranslate(uiCoords, cropSize.width / 2.0, cropSize.height / 2.0);
+    uiCoords = CGAffineTransformScale(uiCoords, 1.0, -1.0);
+    CGContextConcatCTM(context, uiCoords);
+
+    CGContextConcatCTM(context, transform);
+    CGContextScaleCTM(context, 1.0, -1.0);
+
+    CGContextDrawImage(context, CGRectMake(-imageViewSize.width / 2, -imageViewSize.height / 2.0, imageViewSize.width,
+                                           imageViewSize.height),
+                       source);
+    CGImageRef resultRef = CGBitmapContextCreateImage(context);
+    CGContextRelease(context);
+    CGImageRelease(source);
+    return resultRef;
+}
+
++ (CGImageRef)nx_newScaledImage:(CGImageRef)source toSize:(CGSize)size
+{
+    CGSize srcSize = size;
+    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
+    CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0, rgbColorSpace,
+                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
+    CGColorSpaceRelease(rgbColorSpace);
+
+    CGContextSetInterpolationQuality(context, kCGInterpolationNone);
+    CGContextTranslateCTM(context, size.width / 2, size.height / 2);
+
+    CGContextDrawImage(context, CGRectMake(-srcSize.width / 2, -srcSize.height / 2, srcSize.width, srcSize.height),
+                       source);
+
+    CGImageRef resultRef = CGBitmapContextCreateImage(context);
+    CGContextRelease(context);
+    return resultRef;
+}
+
+#pragma mark - 圆角
++ (UIImage *)nx_circleImage:(UIImage *)img
+{
+   return [self nx_circleImage:img cuttingDirection:UIRectCornerAllCorners cornerRadii:img.size.height/2. borderWidth:0 borderColor: [UIColor clearColor] backgroundColor: [UIColor clearColor]];
+}
+
++ (UIImage *)nx_circleImage:(UIImage *)image cuttingDirection:(UIRectCorner)direction cornerRadii:(CGFloat)cornerRadii borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor backgroundColor:(UIColor *)backgroundColor
+{
+    //处理后的数据
+    UIImage * newImage = nil;
+    if (image.size.height != 0 && image.size.width != 0)
+    {
+        if (cornerRadii == 0)
+        {
+            cornerRadii = image.size.height / 2;
+        }
+        CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
+        UIGraphicsBeginImageContextWithOptions(rect.size, NO, [UIScreen mainScreen].scale);
+        CGContextRef currnetContext = UIGraphicsGetCurrentContext();
+        if (currnetContext) {
+            
+            UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:direction cornerRadii:CGSizeMake(cornerRadii - borderWidth, cornerRadii - borderWidth)];
+            CGContextAddPath(currnetContext,path.CGPath);
+            CGContextClip(currnetContext);
+            
+            [image drawInRect:rect];
+            [borderColor setStroke];// 画笔颜色
+            [backgroundColor setFill];// 填充颜色
+            [path stroke];
+            [path fill];
+            newImage = UIGraphicsGetImageFromCurrentImageContext();
+            UIGraphicsEndImageContext();
+        }
+        
+        return newImage;
+    }
+    
+    return newImage;
+}
+
++ (UIImage *)nx_launchImage
+{
+    CGSize viewSize  = [UIScreen mainScreen].bounds.size;
+    
+    NSString * viewOrientation = @"Portrait";
+    NSString * launchImageName = nil;
+    NSArray * imageDict = [[[NSBundle mainBundle] infoDictionary]valueForKey:@"UILaunchImages"];
+    for (NSDictionary  * dict in imageDict)
+    {
+        CGSize imageSize = CGSizeFromString(dict[@"UILaunchImageSize"]);
+        if (CGSizeEqualToSize(imageSize, viewSize) && [viewOrientation isEqualToString:dict[@"UILaunchImageOrientation"]])
+        {
+            launchImageName = dict[@"UILaunchImageName"];
+        }
+    }
+    UIImage * launchImage = [UIImage imageNamed:launchImageName];
+    
+    return launchImage;
+}
+
+
++ (UIImage*)transparentBackClear:(UIImage*)image color:(UIColor*)color
+{
+    // 分配内存
+    const int imageWidth = image.size.width;
+    const int imageHeight = image.size.height;
+    size_t bytesPerRow = imageWidth * 4;
+    uint32_t* rgbImageBuf = (uint32_t*)malloc(bytesPerRow * imageHeight);
+    
+    // 创建context
+    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+    CGContextRef context = CGBitmapContextCreate(rgbImageBuf, imageWidth, imageHeight, 8, bytesPerRow, colorSpace,
+                                                 kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
+    CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), image.CGImage);
+    
+    // 遍历像素
+    int pixelNum = imageWidth * imageHeight;
+    uint32_t* pCurPtr = rgbImageBuf;
+    for (int i = 0; i < pixelNum; i++, pCurPtr++)
+    {
+        if ((*pCurPtr & 0xFFFFFF00) == 0xffffff00) {
+            
+            // 此处把白色背景颜色给变为透明
+            uint8_t* ptr = (uint8_t*)pCurPtr;
+            ptr[0] = 0;
+            
+        }else{
+            
+            // 改成下面的代码,会将图片转成想要的
+            //            uint8_t* ptr = (uint8_t*)pCurPtr;
+            //
+            //            ptr[3] = 0; //0~255
+            //
+            //            ptr[2] = 0;
+            //
+            //            ptr[1] = 0;
+        }
+    }
+    
+    // 将内存转成image
+    CGDataProviderRef dataProvider =CGDataProviderCreateWithData(NULL, rgbImageBuf, bytesPerRow * imageHeight, ProviderReleaseData);
+    
+    CGImageRef imageRef = CGImageCreate(imageWidth, imageHeight,8, 32, bytesPerRow, colorSpace,
+                                        kCGImageAlphaLast |kCGBitmapByteOrder32Little, dataProvider,
+                                        NULL, true,kCGRenderingIntentDefault);
+    CGDataProviderRelease(dataProvider);
+    
+    UIImage* resultUIImage = [UIImage imageWithCGImage:imageRef];
+    
+    // 释放
+    CGImageRelease(imageRef);
+    CGContextRelease(context);
+    CGColorSpaceRelease(colorSpace);
+    
+    return resultUIImage;
+}
+
+void ProviderReleaseData (void *info, const void *data, size_t size)
+{
+    free((void*)data);
+}
+
+@end

+ 0 - 0
BFCommonKit/Classes/BFDebug/.gitkeep


+ 0 - 114
BFCommonKit/Classes/BFDebug/NXDeviceManager.swift

@@ -1,114 +0,0 @@
-//
-//  NXDeviceManager.swift
-//  NXFramework-Swift-Demo
-//
-//  Created by ak on 2020/10/26.
-//  Copyright © 2020 NXFramework-Swift. All rights reserved.
-//
-
-import UIKit
-
-class NXDeviceManager: NSObject {
-    class func info() -> [String] {
-        var data: [String] = []
-
-        data.append("Device Name: \(deviceNameAlias())")
-        if let bundleId = Bundle.main.bundleIdentifier {
-            data.append("Bundle Identifier: \(bundleId)")
-        }
-
-        if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String,
-           let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String
-        {
-            data.append("Host App Version: \(version).\(buildNumber)")
-        }
-
-        if let venderId = UIDevice.current.identifierForVendor {
-            data.append("Identifier For Vendor: \(venderId)")
-        }
-
-        data.append("System Version: \(getSystemVersion())")
-        data.append("Model: \(platformModelString())")
-
-//        data.append("Total Disk Space(MB): \(UIDevice.totalDiskSpaceInMB)")
-//        data.append("Free Disk Space(MB): \(UIDevice.freeDiskSpaceInMB)")
-
-        let lastRestarted = Date(timeIntervalSince1970: TimeInterval(Date().timeIntervalSince1970 - Double(uptime())))
-        data.append("Uptime: \(uptime())/\(lastRestarted)")
-
-        return data
-    }
-
-    class var isIpad: Bool {
-        if #available(iOS 8.0, *) {
-            return UIScreen.main.traitCollection.userInterfaceIdiom == .pad
-        } else {
-            return UIDevice.current.userInterfaceIdiom == .pad
-        }
-    }
-
-    class var isIphone: Bool {
-        if #available(iOS 8.0, *) {
-            return UIScreen.main.traitCollection.userInterfaceIdiom == .phone
-        } else {
-            return UIDevice.current.userInterfaceIdiom == .phone
-        }
-    }
-
-    /// Name of the devices, like Baudins's Iphone
-    class func deviceNameAlias() -> String {
-        return UIDevice.current.name
-    }
-
-    class func processorCount() -> Int {
-        return ProcessInfo.processInfo.activeProcessorCount
-    }
-
-    // Verion of the OS, like 9.0.1
-    class func osVersion() -> String {
-        return UIDevice.current.systemVersion
-    }
-
-    class func platformModelString() -> String {
-        if let key = "hw.machine".cString(using: String.Encoding.utf8) {
-            var size: Int = 0
-            sysctlbyname(key, nil, &size, nil, 0)
-            var machine = [CChar](repeating: 0, count: Int(size))
-            sysctlbyname(key, &machine, &size, nil, 0)
-            return String(cString: machine)
-        }
-        return "Unknown"
-    }
-
-    /** uptime in seconds **/
-    class func uptime() -> Int {
-        var currentTime = time_t()
-        var bootTime = timeval()
-        var mib = [CTL_KERN, KERN_BOOTTIME]
-
-        var size = MemoryLayout<timeval>.stride
-
-        if sysctl(&mib, u_int(mib.count), &bootTime, &size, nil, 0) != -1, bootTime.tv_sec != 0 {
-            time(&currentTime)
-
-            if currentTime < bootTime.tv_sec {
-                return 0
-            }
-
-            return currentTime - bootTime.tv_sec
-        }
-        return 0
-    }
-
-    class func getScreenBrightness() -> CGFloat {
-        return UIScreen.main.brightness
-    }
-
-    class func getPhysicalMemory() -> UInt64 {
-        return ProcessInfo.processInfo.physicalMemory
-    }
-
-    class func getSystemVersion() -> String {
-        return UIDevice.current.systemVersion
-    }
-}

+ 0 - 41
BFCommonKit/Classes/BFDebug/NXFileManager.swift

@@ -1,41 +0,0 @@
-//
-//  NXFileManager.swift
-//  NXFramework-Swift-Demo
-//
-//  Created by ak on 2020/10/26.
-//  Copyright © 2020 NXFramework-Swift. All rights reserved.
-//
-/*
-
- 本类功能, 文件操作.(ios, mac)
-
- 一,iOS目录结构说明
- 1,沙盒目录结构
- ├── Documents - 存储用户数据或其它应该定期备份的
- ├── Library
- │   ├── Caches -
- 用于存放应用程序专用的支持文件,保存应用程序再次启动过程中需要的信息
- │   │   └── Snapshots
- │   │       └── com.youyouxingyuan.re
- │   │           ├── A85B73F0-26A8-44E4-A761-446CAB8DAB38@2x.png
- │   │           └── BFAD5885-B767-4320-9A4B-555EC881C50D@2x.png
- │   └── Preferences - 偏好设置文件 NSUserDefaults 保存的数据
- └── tmp - 这个目录用于存放临时文件,保存应用程序再次启动过程中不需要的信息
-
- 2,在iOS8之后,应用每一次重启,沙盒路径都动态的发生了变化但不用担心数据问题,苹果会把你上一个路径中的数据转移到你新的路径中。你上一个路径也会被苹果毫无保留的删除,只保留最新的路径。
-
- @see  <Foundation/NSPathUtilities.h>
-
- */
-import UIKit
-
-class NXFileManager: NSObject {
-    static var documentDirectoryURL: URL {
-        return try! FileManager.default.url(
-            for: .documentDirectory,
-            in: .userDomainMask,
-            appropriateFor: nil,
-            create: false
-        )
-    }
-}

+ 0 - 174
BFCommonKit/Classes/BFDebug/NXLogger.swift

@@ -1,174 +0,0 @@
-//
-//  NXLogger.swift
-//  NXFramework-Swift-Demo
-//
-//  Created by ak on 2020/10/26.
-//  Copyright © 2020 NXFramework-Swift. All rights reserved.
-//
-
-import UIKit
-
-
-public enum NXLoggerLevel: Int {
-    case info = 1
-    case debug = 2
-    case warning = 3
-    case error = 4
-    case none = 5
-    
-    var name: String {
-        switch self {
-            case .info: return "i"
-            case .debug: return "d"
-            case .warning: return "w"
-            case .error: return "e"
-            case .none: return "N"
-        }
-    }
-}
-
-public enum LoggerOutput: String {
-    case debuggerConsole
-    case deviceConsole
-    case fileOnly
-    case debugerConsoleAndFile
-    case deviceConsoleAndFile
-}
-
-
-private let fileExtension = "txt"
-private let LOG_BUFFER_SIZE = 10
-
-public class NXLogger: NSObject {
-
-    // MARK: - Output
-    public var tag: String?
-    public var level: NXLoggerLevel = .none
-    public var ouput: LoggerOutput = .debuggerConsole
-    public var showThread: Bool = false
-    
-    // MARK: - Init
-    private let isolationQueue = DispatchQueue(label: "com.nxframework.isolation", qos: .background, attributes: .concurrent)
-    private let serialQueue = DispatchQueue(label: "com.nxframework.swiftylog")
-    private let logSubdiretory = NXFileManager.documentDirectoryURL.appendingPathComponent(fileExtension)
-
-    public static let shared = NXLogger()
-    
-    private var _data: [String] = []
-    private var data: [String] {
-        get { return isolationQueue.sync { return _data } }
-        set { isolationQueue.async(flags: .barrier) { self._data = newValue } }
-    }
-    
-    private var logUrl: URL? {
-        let fileName = "NSFrameworkSwiftyLog"
-        try? FileManager.default.createDirectory(at: logSubdiretory, withIntermediateDirectories: false)
-        let url = logSubdiretory.appendingPathComponent(fileName).appendingPathExtension(fileExtension)
-        return url
-    }
-    
-    private override init() {
-        super.init()
-     
-        NotificationCenter.default.addObserver(self, selector: #selector(appMovedToBackground), name:   UIApplication.willResignActiveNotification, object: nil)
-   
-    }
-    
-    // MARK: - Methods
-    @objc private func appMovedToBackground() {
-         self.saveAsync()
-    }
-    
-    func saveAsync() {
-        guard let url = logUrl else { return }
-        serialQueue.async { [weak self] in
-            guard let count = self?.data.count, count > 0 else { return }
-
-            var stringsData = Data()
-            
-            self?.data.forEach { (string) in
-                if let stringData = (string + "\n").data(using: String.Encoding.utf8) {
-                    stringsData.append(stringData)
-                } else {
-                    print("MutalbeData failed")
-                }
-            }
-
-            do {
-                try stringsData.append2File(fileURL: url)
-                self?.data.removeAll()
-            } catch let error as NSError {
-                print("wrote failed: \(url.absoluteString), \(error.localizedDescription)")
-            }
-        }
-    }
-    
-    func removeAllAsync() {
-        guard let url = logUrl else { return }
-        DispatchQueue.global(qos: .userInitiated).async {
-            try? FileManager.default.removeItem(at: url)
-        }
-    }
-    
-    func load() -> [String]? {
-        guard let url = logUrl else { return nil }
-        guard let strings = try? String(contentsOf: url, encoding: String.Encoding.utf8) else { return nil }
-
-        return strings.components(separatedBy: "\n")
-    }
-
-    private func log(_ level: NXLoggerLevel, message: String, currentTime: Date, fileName: String , functionName: String, lineNumber: Int, thread: Thread) {
-        
-        guard level.rawValue >= self.level.rawValue else { return }
-        
-        
-        let _fileName = fileName.split(separator: "/")
-        let text = "\(level.name)-\(showThread ? thread.description : "")[\(_fileName.last ?? "?")#\(functionName)#\(lineNumber)]\(tag ?? ""): \(message)"
-        
-        switch self.ouput {
-            case .fileOnly:
-                addToBuffer(text: "\(currentTime.iso8601) \(text)")
-            case .debuggerConsole:
-                print("\(currentTime.iso8601) \(text)")
-            case .deviceConsole:
-                NSLog(text)
-            case .debugerConsoleAndFile:
-                print("\(currentTime.iso8601) \(text)")
-                addToBuffer(text: "\(currentTime.iso8601) \(text)")
-            case .deviceConsoleAndFile:
-                NSLog(text)
-                addToBuffer(text: "\(currentTime.iso8601) \(text)")
-        }
-    }
-    
-    private func addToBuffer(text: String) {
-        isolationQueue.async(flags: .barrier) { self._data.append(text) }
-        if data.count > LOG_BUFFER_SIZE {
-            saveAsync()
-        }
-    }
-    
-}
-
-// MARK: - Output
-extension NXLogger {
-    public func i(_ message: String, currentTime: Date = Date(), fileName: String = #file, functionName: String = #function, lineNumber: Int = #line, thread: Thread = Thread.current ) {
-        log(.info, message: message, currentTime: currentTime, fileName: fileName, functionName: functionName, lineNumber: lineNumber, thread: thread)
-    }
-    public func d(_ message: String, currentTime: Date = Date(), fileName: String = #file, functionName: String = #function, lineNumber: Int = #line, thread: Thread = Thread.current ) {
-        log(.debug, message: message, currentTime: currentTime, fileName: fileName, functionName: functionName, lineNumber: lineNumber, thread: thread)
-    }
-    public func w(_ message: String, currentTime: Date = Date(), fileName: String = #file, functionName: String = #function, lineNumber: Int = #line, thread: Thread = Thread.current ) {
-        log(.warning, message: message, currentTime: currentTime, fileName: fileName, functionName: functionName, lineNumber: lineNumber, thread: thread)
-    }
-    public func e(_ message: String, currentTime: Date = Date(), fileName: String = #file, functionName: String = #function, lineNumber: Int = #line, thread: Thread = Thread.current ) {
-        log(.error, message: message, currentTime: currentTime, fileName: fileName, functionName: functionName, lineNumber: lineNumber, thread: thread)
-    }
-    
-    public func synchronize() {
-        saveAsync()
-    }
-}
-
-
-

+ 0 - 68
BFCommonKit/Classes/BFDebug/NXLoggerManager.swift

@@ -1,68 +0,0 @@
-//
-//  NXLoggerManager.swift
-//  NXFramework-Swift-Demo
-//
-//  Created by ak on 2020/10/26.
-//  Copyright © 2020 NXFramework-Swift. All rights reserved.
-//
-
-import UIKit
-
-extension UIWindow {
-    open override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
-        guard NXLogger.shared.level != .none else { return }
-        guard NXLogger.shared.ouput == .debugerConsoleAndFile
-            || NXLogger.shared.ouput == .deviceConsoleAndFile
-            || NXLogger.shared.ouput == .fileOnly else { return }
-        
-        NXLogger.shared.saveAsync()
-        let manager = LoggerManager()
-        manager.show()
-    }
-}
-
-protocol LoggerAction {
-    func removeAll()
-}
-
-class LoggerManager: NSObject {
-    let controller = NXLoggerVC()
-    public func show() {
-        guard let topViewController = UIApplication.topViewController() else { return }
-        guard topViewController .isKind(of: NXLoggerVC.self) == false else { return }
-        
-        controller.data = " \(loadLog())\(deviceInfo())"
-        controller.delegate = self
-        
-        topViewController.present(controller, animated: true, completion: nil)
-    }
-    
-    private func loadLog() -> String {
-        var texts: [String] = []
-        
-        guard let data = NXLogger.shared.load() else { return "" }
-        
-        data.forEach { (string) in
-            texts.append("<pre style=\"line-height:8px;\">\(string)</pre>")
-        }
-        
-        return texts.joined()
-    }
-    
-    private func deviceInfo() -> String {
-        var texts:[String] = []
-        
-        texts.append("<pre style=\"line-height:8px;\">==============================================</pre>")
-        NXDeviceManager.info().forEach { (string) in
-            texts.append("<pre style=\"line-height:8px;\">\(string)</pre>")
-        }
-        return texts.joined()
-    }
-}
-
-extension LoggerManager: LoggerAction {
-    func removeAll() {
-        NXLogger.shared.removeAllAsync()
-        controller.data = deviceInfo()
-    }
-}

+ 0 - 188
BFCommonKit/Classes/BFDebug/NXLoggerVC.swift

@@ -1,188 +0,0 @@
-//
-//  NXLoggerVC.swift
-//  NXFramework-Swift-Demo
-//
-//  Created by ak on 2020/10/26.
-//  Copyright © 2020 NXFramework-Swift. All rights reserved.
-//
- 
-import UIKit
-import MessageUI
-import WebKit
-
-
-private let screenWidth = UIScreen.main.bounds.width
-private let screenHeight = UIScreen.main.bounds.height
-private let keyWindow = UIApplication.shared.keyWindow
-
-let themeColor: UIColor = UIColor.hex(hex: 0x00B3C4)
-
-class NXLoggerVC: UIViewController {
-
-    var delegate: LoggerAction?
-    
-    var data: String = "" {
-        didSet {
-            loadWebView()
-        }
-    }
-
-    var webView: WKWebView = {
-        
-        let source: String = "var meta = document.createElement('meta');" +
-            "meta.name = 'viewport';" +
-            "meta.content = 'width=device-width, initial-scale=0.6, maximum-scale=0.8, user-scalable=yes';" +
-            "var head = document.getElementsByTagName('head')[0];" + "head.appendChild(meta);";
-        let script: WKUserScript = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
-        let userContentController: WKUserContentController = WKUserContentController()
-        let conf = WKWebViewConfiguration()
-        conf.userContentController = userContentController
-        userContentController.addUserScript(script)
-        let view = WKWebView(frame: CGRect.zero, configuration: conf)
-        
-        /*
-        view.scrollView.isScrollEnabled = true               // Make sure our view is interactable
-        view.scrollView.bounces = true                    // Things like this should be handled in web code
-        view.allowsBackForwardNavigationGestures = false   // Disable swiping to navigate
-         */
-        return view
-    }()
-    
-    var textView: UITextView = {
-        let view = UITextView()
-        view.isEditable = false
-        view.backgroundColor = UIColor.lightGray
-        return view
-    }()
-    
-    var btnSend: UIButton = {
-        let button = UIButton(type: .system)
-        button.backgroundColor = themeColor
-        button.setTitleColor(.white, for: .normal)
-        button.roundedCorners(cornerRadius: 5)
-        button.setTitle("Send email", for: .normal)
-        button.addTarget(self, action: #selector(btnSendPressed(_:)), for: .touchUpInside)
-        
-        return button
-    }()
-    
-    var btnRemove: UIButton = {
-        let button = UIButton(type: .system)
-        button.backgroundColor = themeColor
-        button.setTitleColor(.white, for: .normal)
-        button.roundedCorners(cornerRadius: 5)
-        button.setTitle("Remove All", for: .normal)
-        button.addTarget(self, action: #selector(btnRemovePressed(_:)), for: .touchUpInside)
-        return button
-    }()
-    var btnCancel: UIButton = {
-        let button = UIButton(type: .system)
-        button.backgroundColor = themeColor
-        button.setTitleColor(.white, for: .normal)
-        button.roundedCorners(cornerRadius: 5)
-        button.setTitle("Cancel", for: .normal)
-        button.addTarget(self, action: #selector(btnCancelPressed(_:)), for: .touchUpInside)
-        return button
-    }()
-    
-    override func viewDidLoad() {
-        super.viewDidLoad()
-
-        addSubViews()
-        
-        loadWebView()
-
-    }
-    
-    private func addSubViews() {
-        self.view.backgroundColor = UIColor.white
-        
-        [webView, btnSend, btnRemove, btnCancel].forEach { (subView: UIView) in
-            subView.translatesAutoresizingMaskIntoConstraints = false
-            view.addSubview(subView)
-        }
-        
-        let views: [String:UIView] = ["webView": webView, "btnSend": btnSend, "btnRemove": btnRemove, "btnCancel": btnCancel]
-        
-        view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "|[webView]|", options: [], metrics: nil, views: views))
-        view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "|-(16)-[btnSend]-(16)-|", options: [], metrics: nil, views: views))
-        view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "|-(16)-[btnRemove]-(16)-|", options: [], metrics: nil, views: views))
-        view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "|-(16)-[btnCancel]-(16)-|", options: [], metrics: nil, views: views))
-        view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-(20)-[webView]-[btnSend(==32)]-[btnRemove(==32)]-[btnCancel(==32)]-(8)-|", options: [], metrics: nil, views: views))
-    }
-    
-    @objc func btnCancelPressed(_ button: UIButton) {
-        self.dismiss(animated: true, completion: nil)
-    }
-    
-    @objc func btnSendPressed(_ button: UIButton) {
-        sendEmail()
-    }
-    
-    @objc func btnRemovePressed(_ button: UIButton) {
-        delegate?.removeAll()
-    }
-    
-    private func sendEmail() {
-        guard MFMailComposeViewController.canSendMail() == true else {
-            self.showAlert(withTitle: "No email client", message: "Please configure your email client first")
-            return
-        }
-
-        let mailComposer = MFMailComposeViewController()
-        mailComposer.mailComposeDelegate = self as! MFMailComposeViewControllerDelegate
-        
-        var body = "Host App: \(Bundle.main.bundleIdentifier ?? "")\n"
-        if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String,
-            let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
-            body += "Host App Version: \(version).\(buildNumber)\n"
-        }
-        if let venderId = UIDevice.current.identifierForVendor {
-            body += "identifierForVendor: \(venderId)\n"
-        }
-
-        mailComposer.setSubject("Log of \(Bundle.main.bundleIdentifier ?? "")")
-        mailComposer.setMessageBody(body, isHTML: false)
-
-
-        webView.evaluateJavaScript("document.documentElement.outerHTML.toString()") { (html, error) in
-            if let string = html as? String, let data = string.data(using: String.Encoding.utf16) {
-                
-                mailComposer.addAttachmentData(data, mimeType: "html", fileName: "\(Bundle.main.bundleIdentifier ?? "log").html" )
-            } else {
-                NXLogger.shared.e("get data from webview failed")
-            }
-        }
-        /*
-        if let data = try? Data(html) {
-            mailComposer.addAttachmentData(data, mimeType: "text/txt", fileName: "SwiftyLog.txt")
-        }
-        */
-        self.present(mailComposer, animated: true, completion: nil)
-    }
-    
-    private func loadWebView() {
-        webView.loadHTMLString(data, baseURL: nil)
-    }
-}
-    
-extension NXLoggerVC: MFMailComposeViewControllerDelegate {
-    func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
-        controller.dismiss(animated: true, completion: nil)
-        switch result {
-            case .cancelled:
-                self.showAlert(withTitle: "Cancel", message: "Send email canceled")
-                break
-            case .sent:
-                break
-            case .failed:
-                self.showAlert(withTitle: "Failed", message: "Send email failed")
-                break
-            case .saved:
-                break
-        @unknown default:
-            fatalError("default ")
-        }
-        self.dismiss(animated: true, completion: nil)
-    }
-}

+ 1 - 1
BFCommonKit/Classes/BFUtility/PQCommonMethodUtil.swift

@@ -14,7 +14,7 @@ import Kingfisher
 import KingfisherWebP
 import Photos
 import Toast_Swift
-import RealmSwift
+//import RealmSwift
 import UIKit
 
 /// Home文件地址

+ 0 - 780
BFCommonKit/Classes/BFUtility/PQPHAssetVideoParaseUtil.swift

@@ -1,780 +0,0 @@
-//
-//  PQPHAssetVideoParaseUtil.swift
-//  PQSpeed
-//
-//  Created by SanW on 2020/8/3.
-//  Copyright © 2020 BytesFlow. All rights reserved.
-//
-
-import CoreServices
-import Photos
-import UIKit
-
-var currentExportSession: AVAssetExportSession?
-open class PQPHAssetVideoParaseUtil: NSObject {
-    static var imagesOptions: PHImageRequestOptions = {
-        let imagesOptions = PHImageRequestOptions()
-        imagesOptions.isSynchronous = false
-        imagesOptions.deliveryMode = .fastFormat
-        imagesOptions.resizeMode = .fast
-        imagesOptions.version = .current
-        return imagesOptions
-    }()
-
-    static var singleImageOptions: PHImageRequestOptions = {
-        let singleImageOptions = PHImageRequestOptions()
-        singleImageOptions.isSynchronous = true
-        singleImageOptions.isNetworkAccessAllowed = true
-        singleImageOptions.deliveryMode = .highQualityFormat
-        singleImageOptions.resizeMode = .none
-        singleImageOptions.version = .current
-        return singleImageOptions
-    }()
-
-    static var videoRequestOptions: PHVideoRequestOptions = {
-        let videoRequestOptions = PHVideoRequestOptions()
-        // 解决慢动作视频返回AVComposition而不是AVURLAsset
-//        videoRequestOptions.version = .original
-        videoRequestOptions.version = .current
-        // 下载iCloud视频
-        videoRequestOptions.isNetworkAccessAllowed = true
-        videoRequestOptions.deliveryMode = .mediumQualityFormat
-        return videoRequestOptions
-    }()
-
-    /// PHAsset解析为AVPlayerItem
-    /// - Parameters:
-    ///   - asset: <#asset description#>
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func parasToAVPlayerItem(phAsset: PHAsset, isHighQuality: Bool = false, resultHandler: @escaping (AVPlayerItem?, Float64, [AnyHashable: Any]?) -> Void) {
-        PHImageManager().requestPlayerItem(forVideo: phAsset, options: videoRequestOptions) { playerItem, info in
-            if isHighQuality, (playerItem?.asset as? AVURLAsset)?.url.absoluteString.components(separatedBy: "/").last?.contains(".medium.") ?? false {
-                let tempVideoOptions = PHVideoRequestOptions()
-                tempVideoOptions.version = .original
-                // 下载iCloud视频
-                tempVideoOptions.isNetworkAccessAllowed = true
-                tempVideoOptions.deliveryMode = .highQualityFormat
-                tempVideoOptions.progressHandler = { progress, error, pointer, info in
-                    BFLog(message: "导出playerItem-progress = \(progress),error = \(String(describing: error)),pointer = \(pointer),info = \(String(describing: info))")
-                }
-                PHImageManager().requestPlayerItem(forVideo: phAsset, options: tempVideoOptions) { playerItem, info in
-                    let size = try! (playerItem?.asset as? AVURLAsset)?.url.resourceValues(forKeys: [.fileSizeKey])
-                    BFLog(message: "size = \(String(describing: size))")
-                    resultHandler(playerItem, Float64(size?.fileSize ?? 0), info)
-                }
-            } else {
-                let size = try! (playerItem?.asset as? AVURLAsset)?.url.resourceValues(forKeys: [.fileSizeKey])
-                BFLog(message: "size = \(String(describing: size))")
-                resultHandler(playerItem, Float64(size?.fileSize ?? 0), info)
-            }
-        }
-    }
-
-    /// PHAsset解析为AVAsset
-    /// - Parameters:
-    ///   - asset: <#asset description#>
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func parasToAVAsset(phAsset: PHAsset, isHighQuality: Bool = true, resultHandler: @escaping (AVAsset?, Int, AVAudioMix?, [AnyHashable: Any]?) -> Void) {
-        PHImageManager.default().requestAVAsset(forVideo: phAsset, options: videoRequestOptions) { avAsset, audioMix, info in
-            if isHighQuality, (avAsset as? AVURLAsset)?.url.absoluteString.components(separatedBy: "/").last?.contains(".medium.") ?? false {
-                let tempVideoOptions = PHVideoRequestOptions()
-                tempVideoOptions.version = .original
-                // 下载iCloud视频
-                tempVideoOptions.isNetworkAccessAllowed = true
-                tempVideoOptions.deliveryMode = .highQualityFormat
-                tempVideoOptions.progressHandler = { progress, error, pointer, info in
-                    BFLog(message: "导出playerItem-progress = \(progress),error = \(String(describing: error)),pointer = \(pointer),info = \(String(describing: info))")
-                }
-                PHImageManager.default().requestAVAsset(forVideo: phAsset, options: tempVideoOptions) { tempAvAsset, tempAudioMix, tempInfo in
-                    let size = try! (tempAvAsset as? AVURLAsset)?.url.resourceValues(forKeys: [.fileSizeKey])
-                    BFLog(message: "size = \(String(describing: size))")
-                    resultHandler(tempAvAsset, size?.fileSize ?? 0, tempAudioMix, tempInfo)
-                }
-            } else {
-                let size = try! (avAsset as? AVURLAsset)?.url.resourceValues(forKeys: [.fileSizeKey])
-                resultHandler(avAsset, size?.fileSize ?? 0, audioMix, info)
-                BFLog(message: "size = \(String(describing: size))")
-            }
-        }
-    }
-
-    /// PHAsset 转码为.mp4保存本地
-    /// - Parameters:
-    ///   - phAsset: <#phAsset description#>
-    ///   - isAdjustRotationAngle: 是否调整旋转角度
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func exportPHAssetToMP4(phAsset: PHAsset, isAdjustRotationAngle: Bool = true, isCancelCurrentExport: Bool = false, deliveryMode: PHVideoRequestOptionsDeliveryMode? = .automatic, resultHandler: @escaping (_ phAsset: PHAsset, _ aVAsset: AVAsset?, _ filePath: String?, _ errorMsg: String?) -> Void) {
-        BFLog(message: "导出相册视频-开始导出:phAsset = \(phAsset)")
-        if isCancelCurrentExport {
-            currentExportSession?.cancelExport()
-        }
-        PQPHAssetVideoParaseUtil.parasToAVAsset(phAsset: phAsset) { avAsset, fileSize, _, _ in
-            if avAsset is AVURLAsset {
-                // 创建目录
-                createDirectory(path: photoLibraryDirectory)
-                let fileName = (avAsset as! AVURLAsset).url.absoluteString
-                let filePath = photoLibraryDirectory + fileName.md5.md5 + ".mp4"
-                let data = try? Data(contentsOf: NSURL.fileURL(withPath: filePath))
-                if FileManager.default.fileExists(atPath: filePath) && (data?.count ?? 0) > fileSize / 40 {
-                    BFLog(message: "导出相册视频-已经导出完成:\(filePath)")
-                    DispatchQueue.main.async {
-                        resultHandler(phAsset, avAsset, filePath, nil)
-                    }
-                } else {
-//                    let tempExportSession = PQSingletoMemoryUtil.shared.allExportSession[phAsset]
-                    let tempExportSession: AVAssetExportSession? = nil
-                    if tempExportSession != nil {
-                        BFLog(message: "导出相册视频-正在导出")
-                        return
-                    }
-                    BFLog(message: "导出相册视频-未导出视频过,开始导出:phAsset = \(phAsset)")
-                    // 删除以创建地址
-                    if FileManager.default.fileExists(atPath: filePath) {
-                        do {
-                            try FileManager.default.removeItem(at: NSURL.fileURL(withPath: filePath))
-                        } catch {
-                            BFLog(message: "导出相册视频-error == \(error)")
-                        }
-                    }
-                    let requestOptions = PHVideoRequestOptions()
-                    // 解决慢动作视频返回AVComposition而不是AVURLAsset
-                    //        videoRequestOptions.version = .original
-                    requestOptions.version = .current
-                    // 下载iCloud视频
-                    requestOptions.isNetworkAccessAllowed = false
-                    requestOptions.progressHandler = { progress, error, pointer, info in
-                        BFLog(message: "导出相册视频-progress = \(progress),error = \(String(describing: error)),pointer = \(pointer),info = \(String(describing: info))")
-                    }
-                    requestOptions.deliveryMode = deliveryMode ?? .automatic
-                    PHImageManager.default().requestExportSession(forVideo: phAsset, options: requestOptions, exportPreset: (deliveryMode == .automatic || deliveryMode == .mediumQualityFormat) ? AVAssetExportPresetMediumQuality : (deliveryMode == .highQualityFormat ? AVAssetExportPresetHighestQuality : AVAssetExportPresetLowQuality), resultHandler: { avAssetExportSession, _ in
-                        BFLog(message: "导出相册视频-请求到导出 avAssetExportSession = \(String(describing: avAssetExportSession))")
-                        currentExportSession = avAssetExportSession
-                        if avAssetExportSession != nil {
-//                            PQSingletoMemoryUtil.shared.allExportSession[phAsset] = avAssetExportSession!
-                        }
-                        avAssetExportSession?.outputURL = NSURL(fileURLWithPath: filePath) as URL
-                        avAssetExportSession?.shouldOptimizeForNetworkUse = true
-                        avAssetExportSession?.outputFileType = .mp4
-                        if isAdjustRotationAngle {
-                            let rotationAngle = PQPHAssetVideoParaseUtil.videoRotationAngle(assert: avAsset!)
-                            // mdf by ak 统一导出的视频为30FPS
-                            var centerTranslate: CGAffineTransform = CGAffineTransform(translationX: 0, y: 0)
-                            var mixedTransform: CGAffineTransform = CGAffineTransform()
-                            let videoComposition = AVMutableVideoComposition()
-                            videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
-                            let tracks = avAsset?.tracks(withMediaType: .video)
-                            let firstTrack = tracks?.first
-
-                            videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.width ?? 0, height: firstTrack?.naturalSize.height ?? 0)
-
-                            mixedTransform = centerTranslate.rotated(by: 0)
-
-                            if rotationAngle == 90 {
-                                centerTranslate = CGAffineTransform(translationX: firstTrack?.naturalSize.height ?? 0, y: 0)
-                                mixedTransform = centerTranslate.rotated(by: .pi / 2)
-                                videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.height ?? 0, height: firstTrack?.naturalSize.width ?? 0)
-                            } else if rotationAngle == 180 {
-                                centerTranslate = CGAffineTransform(translationX: firstTrack?.naturalSize.width ?? 0, y: firstTrack?.naturalSize.height ?? 0)
-                                mixedTransform = centerTranslate.rotated(by: .pi)
-                                videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.width ?? 0, height: firstTrack?.naturalSize.height ?? 0)
-                            } else if rotationAngle == 270 {
-                                centerTranslate = CGAffineTransform(translationX: 0, y: firstTrack?.naturalSize.width ?? 0)
-                                mixedTransform = centerTranslate.rotated(by: .pi / 2 * 3)
-                                videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.height ?? 0, height: firstTrack?.naturalSize.width ?? 0)
-                            }
-                            let roateInstruction = AVMutableVideoCompositionInstruction()
-                            roateInstruction.timeRange = CMTimeRange(start: CMTime.zero, end: avAsset?.duration ?? CMTime.zero)
-                            if firstTrack != nil {
-                                let layRoateInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: firstTrack!)
-                                layRoateInstruction.setTransform(mixedTransform, at: CMTime.zero)
-                                roateInstruction.layerInstructions = [layRoateInstruction]
-                                videoComposition.instructions = [roateInstruction]
-                                avAssetExportSession?.videoComposition = videoComposition
-                            } else {
-                                BFLog(message: "firstTrack is error !!!")
-                            }
-                        }
-                        avAssetExportSession?.exportAsynchronously(completionHandler: {
-                            BFLog(message: "导出相册视频-progress = \(avAssetExportSession?.progress ?? 0),status = \(String(describing: avAssetExportSession?.status))")
-                            switch avAssetExportSession?.status {
-                            case .unknown:
-                                DispatchQueue.main.async {
-                                    resultHandler(phAsset, avAsset, nil, avAssetExportSession?.error?.localizedDescription)
-                                }
-                                avAssetExportSession?.cancelExport()
-//                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-                                BFLog(message: "导出相册视频-发生未知错误:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-                            case .waiting:
-                                BFLog(message: "导出相册视频-等待导出mp4:\(filePath)")
-                            case .exporting:
-                                BFLog(message: "导出相册视频-导出相册视频中...:\(filePath)")
-                            case .completed:
-                                DispatchQueue.main.async {
-                                    resultHandler(phAsset, avAsset, filePath, nil)
-                                }
-                                avAssetExportSession?.cancelExport()
-//                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-                                BFLog(message: "导出相册视频-导出完成:\(filePath)")
-                            case .failed:
-                                DispatchQueue.main.async {
-                                    resultHandler(phAsset, avAsset, nil, avAssetExportSession?.error?.localizedDescription)
-                                }
-                                avAssetExportSession?.cancelExport()
-//                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-                                BFLog(message: "导出相册视频-导出失败:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-                            case .cancelled:
-                                DispatchQueue.main.async {
-                                    resultHandler(phAsset, avAsset, nil, avAssetExportSession?.error?.localizedDescription)
-                                }
-                                avAssetExportSession?.cancelExport()
-//                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-                                BFLog(message: "导出相册视频-取消导出:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-                            default:
-                                break
-                            }
-                        })
-                    })
-                }
-            } else if avAsset is AVComposition {
-                BFLog(message: "导出相册视频-是AVComposition = \(String(describing: avAsset))")
-                let assetResources = PHAssetResource.assetResources(for: phAsset)
-                var resource: PHAssetResource?
-                for assetRes in assetResources {
-                    if assetRes.type == .video || assetRes.type == .pairedVideo {
-                        resource = assetRes
-                    }
-                }
-                if phAsset.mediaType == .video, resource != nil {
-                    let fileName = (resource?.originalFilename ?? "") + (resource?.assetLocalIdentifier ?? "") + (resource?.uniformTypeIdentifier ?? "")
-                    let filePath = photoLibraryDirectory + fileName.md5 + ".mp4"
-                    let data = try? Data(contentsOf: NSURL.fileURL(withPath: filePath))
-                    if FileManager.default.fileExists(atPath: filePath) && (data?.count ?? 0) > fileSize / 40 {
-                        DispatchQueue.main.async {
-                            resultHandler(phAsset, avAsset, filePath, nil)
-                        }
-                    } else {
-                        PHAssetResourceManager.default().writeData(for: resource!, toFile: URL(fileURLWithPath: filePath), options: nil) { error in
-                            DispatchQueue.main.async {
-                                resultHandler(phAsset, avAsset, error == nil ? filePath : nil, nil)
-                            }
-                        }
-                    }
-                } else {
-                    DispatchQueue.main.async {
-                        resultHandler(phAsset, avAsset, nil, nil)
-                    }
-                }
-            } else {
-                DispatchQueue.main.async {
-                    resultHandler(phAsset, avAsset, nil, nil)
-                }
-            }
-        }
-    }
-
-    /// PHAsset 转码为.mp4保存本地
-    /// - Parameters:
-    ///   - phAsset: <#phAsset description#>
-    ///   - isAdjustRotationAngle: 是否调整旋转角度
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func writePHAssetDataToMP4(phAsset: PHAsset, isAdjustRotationAngle _: Bool = true, isCancelCurrentExport: Bool = false, deliveryMode _: PHVideoRequestOptionsDeliveryMode? = .automatic, resultHandler: @escaping (_ phAsset: PHAsset, _ aVAsset: AVAsset?, _ filePath: String?, _ errorMsg: String?) -> Void) {
-        BFLog(message: "导出相册视频-开始导出:phAsset = \(phAsset)")
-        if isCancelCurrentExport {
-            currentExportSession?.cancelExport()
-        }
-        PQPHAssetVideoParaseUtil.parasToAVAsset(phAsset: phAsset) { avAsset, fileSize, _, _ in
-            if avAsset is AVURLAsset {
-                // 创建目录
-                createDirectory(path: photoLibraryDirectory)
-                let fileName = (avAsset as! AVURLAsset).url.absoluteString
-                let filePath = photoLibraryDirectory + fileName.md5 + ".mp4"
-                let data = try? Data(contentsOf: NSURL.fileURL(withPath: filePath))
-                if FileManager.default.fileExists(atPath: filePath) && (data?.count ?? 0) > fileSize / 40 {
-                    BFLog(message: "导出相册视频-已经导出完成:\(filePath)")
-                    DispatchQueue.main.async {
-                        resultHandler(phAsset, avAsset, filePath, nil)
-                    }
-                } else {
-//                    let tempExportSession = PQSingletoMemoryUtil.shared.allExportSession[phAsset]
-                    let tempExportSession: AVAssetExportSession? = nil
-                    if tempExportSession != nil {
-                        BFLog(message: "导出相册视频-正在导出")
-                        return
-                    }
-                    BFLog(message: "导出相册视频-未导出视频过,开始导出:phAsset = \(phAsset)")
-                    // 删除以创建地址
-                    if FileManager.default.fileExists(atPath: filePath) {
-                        do {
-                            try FileManager.default.removeItem(at: NSURL.fileURL(withPath: filePath))
-                        } catch {
-                            BFLog(message: "导出相册视频-error == \(error)")
-                        }
-                    }
-                    do {
-                        try FileManager.default.copyItem(at: (avAsset as! AVURLAsset).url, to: URL(fileURLWithPath: filePath))
-                    } catch {
-                        BFLog(message: "导出相册视频-error == \(error)")
-                    }
-
-//                    NSError *error;
-//                            AVURLAsset *avurlasset = (AVURLAsset*)asset;
-//                            NSURL *fileURL = [NSURL fileURLWithPath:savePath];
-//
-//                            if ([[NSFileManager defaultManager] copyItemAtURL:avurlasset.URL toURL:fileURL error:&error]) {
-//                                CBLog(@"保存成功");
-//                                dispatch_async(dispatch_get_main_queue(), ^{
-//                                    if (result) {
-//                                        result(savePath,[savePath lastPathComponent]);
-//                                    }
-//                                });
-//                            }else{
-//                                CBLog(@"error=%@",error);
-//                                [[NSFileManager defaultManager]removeItemAtPath:savePath error:nil];
-//                                dispatch_async(dispatch_get_main_queue(), ^{
-//                                    failure(error.description);
-//                                });
-//                            }
-//                    let requestOptions = PHVideoRequestOptions()
-//                    // 解决慢动作视频返回AVComposition而不是AVURLAsset
-//                    //        videoRequestOptions.version = .original
-//                    requestOptions.version = .current
-//                    // 下载iCloud视频
-//                    requestOptions.isNetworkAccessAllowed = false
-//                    requestOptions.progressHandler = { progress, error, pointer, info in
-//                        BFLog(message: "导出相册视频-progress = \(progress),error = \(String(describing: error)),pointer = \(pointer),info = \(String(describing: info))")
-//                    }
-//                    requestOptions.deliveryMode = deliveryMode ?? .automatic
-
-//                    PHImageManager.default().requestExportSession(forVideo: phAsset, options: requestOptions, exportPreset: (deliveryMode == .automatic || deliveryMode == .mediumQualityFormat) ? AVAssetExportPreset1920x1080 :(deliveryMode == .highQualityFormat ? AVAssetExportPresetHighestQuality : AVAssetExportPresetLowQuality) , resultHandler: { avAssetExportSession, _ in
-//                        BFLog(message: "导出相册视频-请求到导出 avAssetExportSession = \(avAssetExportSession)")
-//                        currentExportSession = avAssetExportSession
-//                        if avAssetExportSession != nil {
-//                            PQSingletoMemoryUtil.shared.allExportSession[phAsset] = avAssetExportSession!
-//                        }
-//                        avAssetExportSession?.outputURL = NSURL(fileURLWithPath: filePath) as URL
-//                        avAssetExportSession?.shouldOptimizeForNetworkUse = true
-//                        avAssetExportSession?.outputFileType = .mp4
-//                        if isAdjustRotationAngle {
-//                            let rotationAngle = PQPHAssetVideoParaseUtil.videoRotationAngle(assert: avAsset!)
-//                            // mdf by ak 统一导出的视频为30FPS
-//                            var centerTranslate: CGAffineTransform = CGAffineTransform(translationX: 0, y: 0)
-//                            var mixedTransform: CGAffineTransform = CGAffineTransform()
-//                            let videoComposition = AVMutableVideoComposition()
-//                            videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
-//                            let tracks = avAsset?.tracks(withMediaType: .video)
-//                            let firstTrack = tracks?.first
-//
-//                            videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.width ?? 0, height: firstTrack?.naturalSize.height ?? 0)
-//
-//                            mixedTransform = centerTranslate.rotated(by: 0)
-//
-//                            if rotationAngle == 90 {
-//                                centerTranslate = CGAffineTransform(translationX: firstTrack?.naturalSize.height ?? 0, y: 0)
-//                                mixedTransform = centerTranslate.rotated(by: .pi / 2)
-//                                videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.height ?? 0, height: firstTrack?.naturalSize.width ?? 0)
-//                            } else if rotationAngle == 180 {
-//                                centerTranslate = CGAffineTransform(translationX: firstTrack?.naturalSize.width ?? 0, y: firstTrack?.naturalSize.height ?? 0)
-//                                mixedTransform = centerTranslate.rotated(by: .pi)
-//                                videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.width ?? 0, height: firstTrack?.naturalSize.height ?? 0)
-//                            } else if rotationAngle == 270 {
-//                                centerTranslate = CGAffineTransform(translationX: 0, y: firstTrack?.naturalSize.width ?? 0)
-//                                mixedTransform = centerTranslate.rotated(by: .pi / 2 * 3)
-//                                videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.height ?? 0, height: firstTrack?.naturalSize.width ?? 0)
-//                            }
-//                            let roateInstruction = AVMutableVideoCompositionInstruction()
-//                            roateInstruction.timeRange = CMTimeRange(start: CMTime.zero, end: avAsset?.duration ?? CMTime.zero)
-//                            if firstTrack != nil {
-//                                let layRoateInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: firstTrack!)
-//                                layRoateInstruction.setTransform(mixedTransform, at: CMTime.zero)
-//                                roateInstruction.layerInstructions = [layRoateInstruction]
-//                                videoComposition.instructions = [roateInstruction]
-//                                avAssetExportSession?.videoComposition = videoComposition
-//                            } else {
-//                                BFLog(message: "firstTrack is error !!!")
-//                            }
-//                        }
-//                        avAssetExportSession?.shouldOptimizeForNetworkUse = true
-//                        avAssetExportSession?.exportAsynchronously(completionHandler: {
-//                            BFLog(message: "导出相册视频-progress = \(avAssetExportSession?.progress ?? 0),status = \(String(describing: avAssetExportSession?.status))")
-//                            switch avAssetExportSession?.status {
-//                            case .unknown:
-//                                DispatchQueue.main.async {
-//                                    resultHandler(phAsset, avAsset, nil, avAssetExportSession?.error?.localizedDescription)
-//                                }
-//                                avAssetExportSession?.cancelExport()
-//                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-//                                BFLog(message: "导出相册视频-发生未知错误:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-//                            case .waiting:
-//                                BFLog(message: "导出相册视频-等待导出mp4:\(filePath)")
-//                            case .exporting:
-//                                BFLog(message: "导出相册视频-导出相册视频中...:\(filePath)")
-//                            case .completed:
-//                                DispatchQueue.main.async {
-//                                    resultHandler(phAsset, avAsset, filePath, nil)
-//                                }
-//                                avAssetExportSession?.cancelExport()
-//                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-//                                BFLog(message: "导出相册视频-导出完成:\(filePath)")
-//                            case .failed:
-//                                DispatchQueue.main.async {
-//                                    resultHandler(phAsset, avAsset, nil, avAssetExportSession?.error?.localizedDescription)
-//                                }
-//                                avAssetExportSession?.cancelExport()
-//                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-//                                BFLog(message: "导出相册视频-导出失败:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-//                            case .cancelled:
-//                                DispatchQueue.main.async {
-//                                    resultHandler(phAsset, avAsset, nil, avAssetExportSession?.error?.localizedDescription)
-//                                }
-//                                avAssetExportSession?.cancelExport()
-//                                PQSingletoMemoryUtil.shared.allExportSession.removeValue(forKey: phAsset)
-//                                BFLog(message: "导出相册视频-取消导出:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-//                            default:
-//                                break
-//                            }
-//                        })
-//                    })
-                }
-            } else if avAsset is AVComposition {
-                BFLog(message: "导出相册视频-是AVComposition = \(String(describing: avAsset))")
-                let assetResources = PHAssetResource.assetResources(for: phAsset)
-                var resource: PHAssetResource?
-                for assetRes in assetResources {
-                    if assetRes.type == .video || assetRes.type == .pairedVideo {
-                        resource = assetRes
-                    }
-                }
-                if phAsset.mediaType == .video, resource != nil {
-                    let fileName = (resource?.originalFilename ?? "") + (resource?.assetLocalIdentifier ?? "") + (resource?.uniformTypeIdentifier ?? "")
-                    let filePath = photoLibraryDirectory + fileName.md5 + ".mp4"
-                    let data = try? Data(contentsOf: NSURL.fileURL(withPath: filePath))
-                    if FileManager.default.fileExists(atPath: filePath) && (data?.count ?? 0) > fileSize / 40 {
-                        DispatchQueue.main.async {
-                            resultHandler(phAsset, avAsset, filePath, nil)
-                        }
-                    } else {
-                        PHAssetResourceManager.default().writeData(for: resource!, toFile: URL(fileURLWithPath: filePath), options: nil) { error in
-                            DispatchQueue.main.async {
-                                resultHandler(phAsset, avAsset, error == nil ? filePath : nil, nil)
-                            }
-                        }
-                    }
-                } else {
-                    DispatchQueue.main.async {
-                        resultHandler(phAsset, avAsset, nil, nil)
-                    }
-                }
-            } else {
-                DispatchQueue.main.async {
-                    resultHandler(phAsset, avAsset, nil, nil)
-                }
-            }
-        }
-    }
-
-    /// 导出相册视频
-    /// - Parameters:
-    ///   - aVAsset: <#aVAsset description#>
-    ///   - isAdjustRotationAngle: <#isAdjustRotationAngle description#>
-    ///   - resultHandler: <#resultHandler description#>
-    public class func exportAVAssetToMP4(aVAsset: AVURLAsset, isAdjustRotationAngle: Bool = true, resultHandler: @escaping (_ aVAsset: AVURLAsset?, _ filePath: String?, _ errorMsg: String?) -> Void) {
-        currentExportSession?.cancelExport()
-        BFLog(message: "开始导出相册视频:url = \(aVAsset.url.absoluteString)")
-        // 创建目录
-        createDirectory(path: photoLibraryDirectory)
-        let fileName = aVAsset.url.absoluteString
-        let filePath = photoLibraryDirectory + fileName.md5 + ".mp4"
-        let data = try? Data(contentsOf: NSURL.fileURL(withPath: filePath))
-        let fileSize = try! aVAsset.url.resourceValues(forKeys: [.fileSizeKey]).fileSize ?? 0
-        if FileManager.default.fileExists(atPath: filePath) && (data?.count ?? 0) > fileSize / 40 {
-            DispatchQueue.main.async {
-                resultHandler(aVAsset, filePath, nil)
-            }
-        } else {
-            BFLog(message: "未导出视频过,开始导出:aVAsset = \(aVAsset)")
-            // 删除以创建地址
-            try? FileManager.default.removeItem(at: NSURL.fileURL(withPath: filePath))
-            let avAssetExportSession = AVAssetExportSession(asset: aVAsset, presetName: AVAssetExportPreset1280x720)
-            currentExportSession = avAssetExportSession
-            avAssetExportSession?.outputURL = NSURL(fileURLWithPath: filePath) as URL
-            avAssetExportSession?.shouldOptimizeForNetworkUse = false
-            avAssetExportSession?.outputFileType = .mp4
-            if isAdjustRotationAngle {
-                let rotationAngle = PQPHAssetVideoParaseUtil.videoRotationAngle(assert: aVAsset)
-                // mdf by ak 统一导出的视频为30FPS
-                var centerTranslate: CGAffineTransform = CGAffineTransform(translationX: 0, y: 0)
-                var mixedTransform: CGAffineTransform = CGAffineTransform()
-                let videoComposition = AVMutableVideoComposition()
-                videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
-                let tracks = aVAsset.tracks(withMediaType: .video)
-                let firstTrack = tracks.first
-                videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.width ?? 0, height: firstTrack?.naturalSize.height ?? 0)
-
-                mixedTransform = centerTranslate.rotated(by: 0)
-
-                if rotationAngle == 90 {
-                    centerTranslate = CGAffineTransform(translationX: firstTrack?.naturalSize.height ?? 0, y: 0)
-                    mixedTransform = centerTranslate.rotated(by: .pi / 2)
-                    videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.height ?? 0, height: firstTrack?.naturalSize.width ?? 0)
-                } else if rotationAngle == 180 {
-                    centerTranslate = CGAffineTransform(translationX: firstTrack?.naturalSize.width ?? 0, y: firstTrack?.naturalSize.height ?? 0)
-                    mixedTransform = centerTranslate.rotated(by: .pi)
-                    videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.width ?? 0, height: firstTrack?.naturalSize.height ?? 0)
-                } else if rotationAngle == 270 {
-                    centerTranslate = CGAffineTransform(translationX: 0, y: firstTrack?.naturalSize.width ?? 0)
-                    mixedTransform = centerTranslate.rotated(by: .pi / 2 * 3)
-                    videoComposition.renderSize = CGSize(width: firstTrack?.naturalSize.height ?? 0, height: firstTrack?.naturalSize.width ?? 0)
-                }
-                let roateInstruction = AVMutableVideoCompositionInstruction()
-                roateInstruction.timeRange = CMTimeRange(start: CMTime.zero, end: aVAsset.duration)
-                let layRoateInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: firstTrack!)
-                layRoateInstruction.setTransform(mixedTransform, at: CMTime.zero)
-                roateInstruction.layerInstructions = [layRoateInstruction]
-                videoComposition.instructions = [roateInstruction]
-                avAssetExportSession?.videoComposition = videoComposition
-            }
-
-            avAssetExportSession?.shouldOptimizeForNetworkUse = true
-            avAssetExportSession?.exportAsynchronously(completionHandler: {
-                BFLog(message: "导出相册视频progress = \(avAssetExportSession?.progress ?? 0)")
-                switch avAssetExportSession?.status {
-                case .unknown:
-                    DispatchQueue.main.async {
-                        resultHandler(aVAsset, nil, avAssetExportSession?.error?.localizedDescription)
-                    }
-                    BFLog(message: "导出相册视频发生未知错误:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-                case .waiting:
-                    BFLog(message: "等待导出mp4:\(filePath)")
-                case .exporting:
-                    BFLog(message: "导出相册视频中...:\(filePath)")
-                case .completed:
-                    DispatchQueue.main.async {
-                        resultHandler(aVAsset, filePath, nil)
-                    }
-                    BFLog(message: "导出相册视频完成:\(filePath)")
-                case .failed:
-                    DispatchQueue.main.async {
-                        resultHandler(aVAsset, nil, avAssetExportSession?.error?.localizedDescription)
-                    }
-                    BFLog(message: "导出相册视频失败:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-                case .cancelled:
-                    DispatchQueue.main.async {
-                        resultHandler(aVAsset, nil, avAssetExportSession?.error?.localizedDescription)
-                    }
-                    BFLog(message: "取消导出相册视频:\(filePath),\(avAssetExportSession?.error?.localizedDescription ?? "")")
-                default:
-                    break
-                }
-            })
-        }
-    }
-
-    /// 获取视频资源的旋转角度
-    /// - Parameter assert: <#assert description#>
-    /// - Returns: <#description#>
-    public class func videoRotationAngle(assert: AVAsset) -> Int {
-        var rotationAngle: Int = 0
-
-        let tracks = assert.tracks(withMediaType: .video)
-        if tracks.count > 0 {
-            let firstTrack = tracks.first
-            let transform = firstTrack?.preferredTransform
-            if transform?.a == 0, transform?.b == 1.0, transform?.c == -1.0, transform?.d == 0 {
-                rotationAngle = 90
-            } else if transform?.a == -1.0, transform?.b == 0, transform?.c == 0, transform?.d == -1.0 {
-                rotationAngle = 180
-            } else if transform?.a == 0, transform?.b == -1.0, transform?.c == 1.0, transform?.d == 0 {
-                rotationAngle = 270
-            } else if transform?.a == 1.0, transform?.b == 0, transform?.c == 0, transform?.d == 1.0 {
-                rotationAngle = 0
-            }
-        }
-        return rotationAngle
-    }
-
-    /// 裁剪背景音乐并导出
-    /// - Parameters:
-    ///   - url: 原始地址
-    ///   - startTime: 开始时间
-    ///   - endTime: 结束时间
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func cutAudioToLocal(url: String, startTime: Float, endTime: Float, resultHandler: @escaping (_ url: String, _ filePath: String?, _ startTime: Float, _ endTime: Float, _ errorMsg: String?) -> Void) {
-        // 创建目录
-        createDirectory(path: bgMusicDirectory)
-        let filePath = bgMusicDirectory + url.md5 + ".mp3"
-        let data = try? Data(contentsOf: NSURL.fileURL(withPath: filePath))
-        if FileManager.default.fileExists(atPath: filePath) && (data?.count ?? 0) > 0 {
-            DispatchQueue.main.async {
-                resultHandler(url, filePath, startTime, endTime, nil)
-            }
-        } else {
-            // 删除以创建地址
-            try? FileManager.default.removeItem(at: NSURL.fileURL(withPath: filePath))
-            let audioAsset = AVURLAsset(url: URL(string: url)!)
-            audioAsset.loadValuesAsynchronously(forKeys: ["duration", "tracks"]) {
-                let status = audioAsset.statusOfValue(forKey: "tracks", error: nil)
-                switch status {
-                case .loaded: // 加载完成
-                    // AVAssetExportPresetPassthrough /AVAssetExportPresetAppleM4A
-                    let exportSession = AVAssetExportSession(asset: audioAsset, presetName: AVAssetExportPresetHighestQuality)
-                    exportSession?.outputURL = URL(fileURLWithPath: filePath)
-                    exportSession?.outputFileType = .mp3
-                    exportSession?.timeRange = CMTimeRange(start: CMTime(seconds: Double(startTime), preferredTimescale: 1000), end: CMTime(seconds: Double(endTime), preferredTimescale: 1000))
-                    exportSession?.exportAsynchronously(completionHandler: {
-                        switch exportSession?.status {
-                        case .waiting:
-                            BFLog(message: "等待导出mp3:\(filePath)")
-                        case .exporting:
-                            BFLog(message: "导出中...:\(filePath)")
-                        case .completed:
-                            DispatchQueue.main.async {
-                                resultHandler(url, filePath, startTime, endTime, nil)
-                            }
-                            BFLog(message: "导出完成:\(filePath)")
-
-                        case .cancelled, .failed, .unknown:
-                            DispatchQueue.main.async {
-                                resultHandler(url, nil, startTime, endTime, exportSession?.error?.localizedDescription)
-                            }
-                            BFLog(message: "导出失败:\(filePath),\(exportSession?.error?.localizedDescription ?? "")")
-                        default:
-                            break
-                        }
-                    })
-                case .loading:
-                    BFLog(message: "加载中...:\(url)")
-                case .failed, .cancelled, .unknown:
-                    DispatchQueue.main.async {
-                        resultHandler(url, nil, startTime, endTime, "导出失败")
-                    }
-                default:
-                    break
-                }
-            }
-        }
-    }
-
-    /// 创建本地保存地址
-    /// - Parameters:
-    ///   - sourceFilePath: <#sourceFilePath description#>
-    ///   - completeHandle: <#completeHandle description#>
-    /// - Returns: <#description#>
-    public class func createLocalFile(sourceFilePath: String, completeHandle: (_ isFileExists: Bool, _ isCreateSuccess: Bool, _ filePath: String) -> Void) {
-        let cLocalPath = NSString(string: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!).appendingPathComponent("\(sourceFilePath.md5).mp4")
-        if FileManager.default.fileExists(atPath: cLocalPath) {
-            BFLog(message: "文件已经存在:\(cLocalPath)")
-            completeHandle(true, false, cLocalPath)
-        } else {
-            let result = FileManager.default.createFile(atPath: cLocalPath, contents: nil, attributes: nil)
-            BFLog(message: "文件创建:\(cLocalPath),\(result)")
-            completeHandle(false, result, cLocalPath)
-        }
-    }
-
-    /// 获取图库图片
-    /// - Parameters:
-    ///   - asset: <#asset description#>
-    ///   - itemSize: <#itemSize description#>
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func requestAssetImage(asset: PHAsset, itemSize: CGSize, resultHandler: @escaping (UIImage?, [AnyHashable: Any]?) -> Void) {
-        PHCachingImageManager().requestImage(for: asset, targetSize: itemSize, contentMode: .aspectFill, options: imagesOptions, resultHandler: { image, info in
-            BFLog(message: "info = \(info ?? [:])")
-            if info?.keys.contains("PHImageResultIsDegradedKey") ?? false, "\(info?["PHImageResultIsDegradedKey"] ?? "0")" == "0" {
-                resultHandler(image, info)
-            }
-        })
-    }
-
-    /// 获取图库原图
-    /// - Parameters:
-    ///   - asset: <#asset description#>
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func requestAssetOringinImage(asset: PHAsset, resultHandler: @escaping (_ isGIF: Bool, _ data: Data?, UIImage?, [AnyHashable: Any]?) -> Void) {
-        PHCachingImageManager().requestImageData(for: asset, options: singleImageOptions) { data, _, _, info in
-            var image: UIImage?
-            if data != nil {
-                image = UIImage(data: data!)
-            }
-            if info?.keys.contains("PHImageFileUTIKey") ?? false, "\(info?["PHImageFileUTIKey"] ?? "")" == "com.compuserve.gif" {
-                resultHandler(true, data, image, info)
-            } else {
-                resultHandler(false, data, image, info)
-            }
-        }
-    }
-
-    /// 获取gif帧跟时长
-    /// - Parameters:
-    ///   - data: <#data description#>
-    ///   - isRenderingTemplate
-    ///   - resultHandler: <#resultHandler description#>
-    /// - Returns: <#description#>
-    public class func parasGIFImage(data: Data, isRenderingColor: UIColor? = nil, resultHandler: @escaping (_ data: Data, _ images: [UIImage]?, _ duration: Double?) -> Void) {
-        let info: [String: Any] = [
-            kCGImageSourceShouldCache as String: true,
-            kCGImageSourceTypeIdentifierHint as String: kUTTypeGIF,
-        ]
-        guard let imageSource = CGImageSourceCreateWithData(data as CFData, info as CFDictionary) else {
-            resultHandler(data, nil, nil)
-            BFLog(message: "获取gifimageSource 失败")
-            return
-        }
-        // 获取帧数
-        let frameCount = CGImageSourceGetCount(imageSource)
-        var gifDuration = 0.0
-        var images = [UIImage]()
-        for i in 0 ..< frameCount {
-            // 取出索引对应的图片
-            guard let imageRef = CGImageSourceCreateImageAtIndex(imageSource, i, info as CFDictionary) else {
-                BFLog(message: "取出对应的图片失败")
-                return
-            }
-            if frameCount == 1 {
-                // 单帧
-                gifDuration = .infinity
-            } else {
-                // 1.获取gif没帧的时间间隔
-                // 获取到该帧图片的属性字典
-                guard let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, i, nil) as? [String: Any] else {
-                    BFLog(message: "取出对应的图片属性失败")
-                    return
-                }
-                // 获取该帧图片中的GIF相关的属性字典
-                guard let gifInfo = properties[kCGImagePropertyGIFDictionary as String] as? [String: Any] else {
-                    BFLog(message: "取出对应的图片属性失败")
-                    return
-                }
-                let defaultFrameDuration = 0.1
-                // 获取该帧图片的播放时间
-                let unclampedDelayTime = gifInfo[kCGImagePropertyGIFUnclampedDelayTime as String] as? NSNumber
-                // 如果通过kCGImagePropertyGIFUnclampedDelayTime没有获取到播放时长,就通过kCGImagePropertyGIFDelayTime来获取,两者的含义是相同的;
-                let delayTime = gifInfo[kCGImagePropertyGIFDelayTime as String] as? NSNumber
-                let duration = unclampedDelayTime ?? delayTime
-                guard let frameDuration = duration else {
-                    BFLog(message: "获取帧时间间隔失败")
-                    return
-                }
-                // 对于播放时间低于0.011s的,重新指定时长为0.100s;
-                let gifFrameDuration = frameDuration.doubleValue > 0.011 ? frameDuration.doubleValue : defaultFrameDuration
-                // 计算总时间
-                gifDuration += gifFrameDuration
-                // 2.图片
-                var frameImage: UIImage? = UIImage(cgImage: imageRef, scale: 1.0, orientation: .up)
-                if isRenderingColor != nil {
-                    frameImage = frameImage?.tintImage(color: isRenderingColor!, blendMode: .destinationIn)
-                }
-                if frameImage != nil {
-                    images.append(frameImage!)
-                }
-            }
-        }
-        resultHandler(data, images, gifDuration)
-    }
-}