wenweiwei 3 lat temu
rodzic
commit
b508bbf719

+ 56 - 14
.gitignore

@@ -1,8 +1,22 @@
-# macOS
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
 .DS_Store
-
+.atom/
+.buildlog/
+.history
+.svn/
 # Xcode
+#
+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
+
+## Build generated
 build/
+DerivedData/
+
+## Various settings
 *.pbxuser
 !default.pbxuser
 *.mode1v3
@@ -12,26 +26,54 @@ build/
 *.perspectivev3
 !default.perspectivev3
 xcuserdata/
-*.xccheckout
-profile
+
+## Other
 *.moved-aside
-DerivedData
+*.xccheckout
+*.xcscmblueprint
+
+## Obj-C/Swift specific
 *.hmap
 *.ipa
+*.dSYM.zip
+*.dSYM
 
-# Bundler
-.bundle
+## Playgrounds
+timeline.xctimeline
+playground.xcworkspace
+
+# Swift Package Manager
+#
+# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
+# Packages/
+# Package.pins
+# Package.resolved
+.build/
 
+# CocoaPods
+#
+# We recommend against adding the Pods directory to your .gitignore. However
+# you should judge for yourself, the pros and cons are mentioned at:
+# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
+#
+Pods/
+Podfile.lock
+
+# Carthage
+#
 # Add this line if you want to avoid checking in source code from Carthage dependencies.
 # Carthage/Checkouts
 
 Carthage/Build
 
-# We recommend against adding the Pods directory to your .gitignore. However
-# you should judge for yourself, the pros and cons are mentioned at:
-# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
-# 
-# Note: if you ignore the Pods directory, make sure to uncomment
-# `pod install` in .travis.yml
+# fastlane
 #
-# Pods/
+# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
+# screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://docs.fastlane.tools/best-practices/source-control/#source-control
+
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots/**/*.png
+fastlane/test_output

+ 10 - 16
BFAnalyzeKit.podspec

@@ -9,8 +9,8 @@
 Pod::Spec.new do |s|
   s.name             = 'BFAnalyzeKit'
   s.version          = '0.1.0'
-  s.summary          = 'A short description of BFAnalyzeKit.'
-
+  s.summary          = '埋点库'
+  s.swift_version    = '5.0'
 # This description is used to generate tags and improve search results.
 #   * Think: What does it do? Why did you write it? What is the focus?
 #   * Try to keep it short, snappy and to the point.
@@ -21,22 +21,16 @@ Pod::Spec.new do |s|
 TODO: Add long description of the pod here.
                        DESC
 
-  s.homepage         = 'https://github.com/SanWCoder/BFAnalyzeKit'
+  s.homepage         = 'https://git.yishihui.com/iOS/BFAnalyzeKit'
   # s.screenshots     = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
   s.license          = { :type => 'MIT', :file => 'LICENSE' }
   s.author           = { 'SanWCoder' => 'wenweiwei@piaoquantv.com' }
-  s.source           = { :git => 'https://github.com/SanWCoder/BFAnalyzeKit.git', :tag => s.version.to_s }
-  # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'
-
-  s.ios.deployment_target = '9.0'
-
+  s.source           = { :git => 'https://git.yishihui.com/iOS/BFAnalyzeKit.git', :tag => s.version.to_s }
+  s.ios.deployment_target = '10.0'
+  s.requires_arc = true
   s.source_files = 'BFAnalyzeKit/Classes/**/*'
-  
-  # s.resource_bundles = {
-  #   'BFAnalyzeKit' => ['BFAnalyzeKit/Assets/*.png']
-  # }
-
-  # s.public_header_files = 'Pod/Classes/**/*.h'
-  # s.frameworks = 'UIKit', 'MapKit'
-  # s.dependency 'AFNetworking', '~> 2.3'
+  s.dependency 'BFCommonKit/BFEnums'
+  s.dependency 'BFCommonKit/BFEnv'
+  s.dependency 'BFCommonKit/BFProtocols'
+  s.dependency 'BFNetRequestKit'
 end

+ 66 - 0
BFAnalyzeKit/Classes/BFAnalyzeFunc.swift

@@ -0,0 +1,66 @@
+//
+//  BFAnalyzeFunc.swift
+//  BFAnalyzeKit
+//
+//  Created by SanW on 2021/12/10.
+//
+
+import BFNetRequestKit
+import UIKit
+
+// MARK: 字典转字符串
+
+public func bf_dictionaryToJsonString(_ dic: [String: Any]) -> String? {
+    if !JSONSerialization.isValidJSONObject(dic) {
+        return ""
+    }
+    guard let data = try? JSONSerialization.data(withJSONObject: dic, options: []) else {
+        return ""
+    }
+    let str = String(data: data, encoding: String.Encoding.utf8)
+    return str
+}
+
+/// 数组转为string
+/// - Parameter array: <#array description#>
+/// - Returns: <#description#>
+public func bf_arrayToJsonString(_ array: [Any]) -> String {
+    if !JSONSerialization.isValidJSONObject(array) {
+        return ""
+    }
+    let data: NSData! = try? JSONSerialization.data(withJSONObject: array, options: []) as NSData?
+    let JSONString = NSString(data: data as Data, encoding: String.Encoding.utf8.rawValue)
+    return JSONString! as String
+}
+
+/// dns解析
+/// - Parameter hostUrl: speed.piaoquantv.com /
+/// - Returns: <#description#>
+public func bf_parseDNS(hostUrl: String) -> [String: Any]? {
+    let host: CFHost? = CFHostCreateWithName(nil, hostUrl as CFString).takeRetainedValue()
+    let start = CFAbsoluteTimeGetCurrent()
+    var success: DarwinBoolean = false
+    var addressList: [String] = Array<String>.init()
+    var addresses: NSArray?
+    if CFHostStartInfoResolution(host!, .addresses, nil) {
+        addresses = (CFHostGetAddressing(host!, &success)?.takeUnretainedValue())
+    }
+    if success == true {
+        for case let theAddress as NSData in addresses! {
+            var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
+            if getnameinfo(theAddress.bytes.assumingMemoryBound(to: sockaddr.self), socklen_t(theAddress.length),
+                           &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0
+            {
+                let numAddress = String(cString: hostname)
+                addressList.append("\(hostUrl)/\(numAddress)")
+            }
+        }
+    }
+    let end = CFAbsoluteTimeGetCurrent()
+    let duration = end - start
+    if addressList.count > 0 {
+        return ["dnsResult": bf_arrayToJsonString(addressList), "duration": duration * 1000, "hostName": hostUrl, "networkType": SWNetRequest.networkStatusDescription()]
+    } else {
+        return nil
+    }
+}

+ 292 - 0
BFAnalyzeKit/Classes/BFBaseEventTrack.swift

@@ -0,0 +1,292 @@
+//
+//  BFBaseEventTrack.swift
+//  PQSpeed
+//
+//  Created by SanW on 2020/11/3.
+//  Copyright © 2020 BytesFlow. All rights reserved.
+//
+
+import BFCommonKit
+import BFNetRequestKit
+import UIKit
+
+// MARK: - 埋点数据上报
+
+/// 埋点数据上报
+public class BFBaseEventTrack: NSObject {
+    /// 基础数据上报 - frontend库上报
+    /// - Parameters:
+    ///   - logType: 数据库类型
+    ///   - businessType: businessType
+    ///   - objectType: objectType
+    ///   - eventData: eventData
+    ///   - pageSource: pageSource页面场景
+    ///   - extParams: extParams 扩展字段,为json对象
+    ///   - remindmsg: remindmsg 打印提示信息
+    /// - Returns: <#description#>
+    public class func bf_frontendReportUpload(url: String, logType: Int = 30, businessType: String?, objectType: String?, pageSource: String?, params: [String: Any]? = nil, eventData: [String: Any]? = nil, extParams: [String: Any]? = nil, commonParams: [String: Any]? = nil) {
+        DispatchQueue.global().async {
+            // LogType
+            var tempParams: [String: Any] = params ?? [:]
+            tempParams["LogType"] = logType
+            // pageSource
+            if pageSource != nil {
+                tempParams["pageSource"] = pageSource ?? ""
+            }
+            // eventData
+            var tempEventData: [String: Any] = eventData ?? [:]
+            if objectType != nil {
+                tempEventData["objectType"] = objectType ?? ""
+            }
+            if businessType != nil {
+                tempEventData["businessType"] = businessType ?? ""
+            }
+            if tempEventData.keys.count > 0 {
+                tempParams["eventData"] = bf_dictionaryToJsonString(tempEventData)
+            }
+            // extParams
+            if extParams != nil, (extParams?.keys.count ?? 0) > 0 {
+                tempParams["extParams"] = bf_dictionaryToJsonString(extParams!)
+            }
+            BFNetRequestAdaptor.postRequestData(url: url, parames: tempParams, commonParams: commonParams) { _, _, _, _ in
+            }
+        }
+    }
+
+    /// 消息数据上报
+    /// - Parameters:
+    ///   - messageIds: 消息Id,多个用逗号分隔
+    ///   - clickId: 子入口点击ID,标识一次子入口点击动作。子入口内消息列表中的消息点击行为都带有此字段,分享空间消息除外
+    ///   - messageType: 消息类型
+    ///   - messageSubType: 消息子类型
+    ///   - actionType: 动作类型(backendCreate:后端构建;backendReturn:后端返回;frontendPull:前端拉取;view:曝光;click:点击)
+    ///   - objectType: <#objectType description#>
+    ///   - pageSource: <#pageSource description#>
+    ///   - readStatus: 已读状态:1:页面上显示未读 2:页面上显示已读
+    ///   - eventData: 扩展数据,json格式,日志系统里会展开存储
+    ///   - extParams: 扩展字段 json格式
+    ///   - remindmsg: 打印提示信息
+    /// - Returns: <#description#>
+    public class func bf_messageReportUpload(url: String, messageIds: String?, clickId: String?, messageType: Int?, messageSubType: Int?, actionType: String?, readStatus: Int = 1, objectType: String?, pageSource: String?, eventData: [String: Any]? = nil, extParams: [String: Any]? = nil, commonParams: [String: Any]? = nil) {
+        DispatchQueue.global().async {
+            var tempParams: [String: Any] = extParams ?? [:]
+            if messageIds != nil {
+                tempParams["messageIds"] = messageIds
+            }
+            if messageType != nil {
+                tempParams["messageType"] = messageType ?? ""
+            }
+            if messageSubType != nil {
+                tempParams["messageSubType"] = messageSubType ?? ""
+            }
+            if actionType != nil {
+                tempParams["actionType"] = actionType ?? ""
+            }
+            tempParams["readStatus"] = readStatus + 1
+            if pageSource != nil {
+                tempParams["pageSource"] = pageSource ?? ""
+            }
+            // eventData
+            var tempEventData: [String: Any] = eventData ?? [:]
+            if objectType != nil {
+                tempEventData["objectType"] = objectType ?? ""
+            }
+            if tempEventData.keys.count > 0 {
+                tempParams["eventData"] = bf_dictionaryToJsonString(tempEventData)
+            }
+            // extParams
+            var tempExtParams: [String: Any] = extParams ?? [:]
+            if clickId != nil {
+                tempExtParams["clickId"] = clickId
+            }
+            if tempExtParams.keys.count > 0 {
+                tempParams["extParams"] = bf_dictionaryToJsonString(tempExtParams)
+            }
+            BFNetRequestAdaptor.postRequestData(url: url, parames: tempParams, commonParams: commonParams) { _, _, _, _ in
+            }
+        }
+    }
+
+    /// 视频相关数据上报
+    /// - Parameters:
+    ///   - reportLogType: 日志类型
+    ///   - videoId: 视频Id
+    ///   - headVideoId: 当前的相关推荐视频是属于哪个视频的相关推荐,值为那个头部视频的videoId
+    ///   - videoIds: reportLogType_view时传
+    ///   - pageSource: 页面
+    ///   - playId: 播放ID 对于每一次播放操作,生成唯一playid,标示唯一一次播放操作,视频播放中暂停,再继续播放时,不算一次新的播放,不需要生成新的playid。重播视频算一次新的播放,即需要生成新的playid。
+    ///   - recommendId: 推荐链路ID 列表返回
+    ///   - recommendLogVO: 推荐日志对象 列表返回
+    ///   - abInfoData: AB信息 列表返回
+    ///   - measureType:
+    ///   - measureId:
+    ///   - businessType: 操作类型
+    ///   - targetUid: 视频用户ID
+    /// - Returns: <#description#>
+    public class func bf_videoReportUpload(url: String, videoId: String?, headVideoId: String?, playId: String?, recommendId: String?, recommendLogVO: String?, flowPool: String?, abInfoData: String?, measureType: Int?, measureId: Int?, targetUid: Int = 0, businessType: String?, objectType: String?, pageSource: String?, eventData: [String: Any]? = nil, extParams: [String: Any]? = nil, commonParams: [String: Any]? = nil) {
+        DispatchQueue.global().async {
+            var params: [String: Any] = ["videoId": videoId ?? "", "pageSource": pageSource ?? "", "playId": playId ?? "", "targetUid": targetUid]
+            if measureType != nil {
+                params["measureType"] = measureType
+            }
+            if measureId != nil {
+                params["measureId"] = measureId
+            }
+            if recommendId != nil, !(recommendId?.isEmpty ?? true) {
+                params["recommendId"] = recommendId
+            }
+            if recommendLogVO != nil, !(recommendLogVO?.isEmpty ?? true) {
+                params["recommendLogVO"] = recommendLogVO
+            }
+            if flowPool != nil, (flowPool?.count ?? 0) > 0 {
+                params["flowPool"] = flowPool
+            }
+            if abInfoData != nil, !(abInfoData?.isEmpty ?? true) {
+                params["abInfoData"] = abInfoData
+            }
+            if pageSource?.contains("speedApp-category") ?? false {
+                params["pageCategoryId"] = 55
+            }
+            // eventData
+            var tempEventData: [String: Any] = eventData ?? [:]
+            if objectType != nil {
+                tempEventData["objectType"] = objectType ?? ""
+            }
+            if businessType != nil {
+                tempEventData["businessType"] = businessType ?? ""
+            }
+            tempEventData["pageSource"] = pageSource ?? ""
+            // extParams
+            var tempExtParams: [String: Any] = extParams ?? [:]
+            if headVideoId != nil, (headVideoId?.count ?? 0) > 0 {
+                tempExtParams["headVideoId"] = (headVideoId ?? "0")
+            }
+            if videoId != nil, (videoId?.count ?? 0) > 0 {
+                tempExtParams["videoId"] = videoId ?? ""
+            }
+            if tempEventData.keys.count > 0 {
+                params["eventData"] = bf_dictionaryToJsonString(tempEventData)
+            }
+            if tempExtParams.keys.count > 0 {
+                params["extParams"] = bf_dictionaryToJsonString(tempExtParams)
+            }
+            BFNetRequestAdaptor.postRequestData(url: url, parames: params, commonParams: commonParams) { _, _, _, _ in
+            }
+        }
+    }
+
+    // 分享数据上报
+    // - Parameters:
+    //   - isShareVideo: 是否是分享视频
+    //   - screenType: 分享场景 1-分享视频/用户 2-分享视频到朋友圈 3-分享视频到好友
+    //   - videoId: 视频Id
+    //   - pageSource: 页面枚举
+    //   - recommendId: <#recommendId description#>
+    //   - recommendLogVO: <#recommendLogVO description#>
+    //   - abInfoData: <#abInfoData description#>
+    //   - measureType: <#measureType description#>
+    //   - measureId: <#measureId description#>
+    //   - businessType: <#businessType description#>
+    //   - targetUid: <#targetUid description#>
+    //   - shareId: <#shareId description#>
+    public class func bf_shareReportUpload(url: String, isShareVideo: Bool = true, screenType: Int = 1, videoId: String?, recommendId: String?, recommendLogVO: String?, flowPool: String?, abInfoData: String?, measureType: Int?, measureId: Int?, targetUid: Int?, shareId: String = "", playId: String?, wxOpenId: String?, businessType: String?, pageSource: String?, extParams: [String: Any]? = nil, commonParams: [String: Any]? = nil) {
+        DispatchQueue.global().async {
+            var params: [String: Any] = ["type": isShareVideo ? "1" : "2", "videoId": videoId ?? "", "pageSource": pageSource ?? "", "playId": playId ?? "", "targetUid": targetUid ?? 0, "shareDepth": "0"]
+            if extParams != nil {
+                params["extParams"] = bf_dictionaryToJsonString(extParams!)
+            }
+            if measureType != nil {
+                params["measureType"] = measureType
+            }
+            if measureId != nil {
+                params["measureId"] = measureId
+            }
+            params["shareId"] = shareId
+            params["rootLaunchShareId"] = shareId
+            params["parentShareId"] = shareId
+            params["rootShareId"] = shareId
+            if wxOpenId != nil {
+                params["shareUi"] = wxOpenId ?? ""
+            }
+            if pageSource?.contains("speedApp-category") ?? false {
+                params["pageCategoryId"] = 55
+            }
+            if isShareVideo {
+                params["shareObjectId"] = videoId
+            } else {
+                params["shareObjectId"] = targetUid
+            }
+            if businessType != nil {
+                params["businessType"] = businessType ?? ""
+            }
+            if recommendId != nil, !(recommendId?.isEmpty ?? true) {
+                params["recommendId"] = recommendId
+            }
+            if recommendLogVO != nil, !(recommendLogVO?.isEmpty ?? true) {
+                params["recommendLogVO"] = recommendLogVO
+            }
+            if flowPool != nil, (flowPool?.count ?? 0) > 0 {
+                params["flowPool"] = flowPool
+            }
+            if abInfoData != nil, !(abInfoData?.isEmpty ?? true) {
+                params["abInfoData"] = abInfoData
+            }
+            BFNetRequestAdaptor.postRequestData(url: url, parames: params, commonParams: commonParams) { _, _, _, _ in
+            }
+        }
+    }
+
+    /// 推送点击数据上报
+    /// - Parameters:
+    ///   - pushId: 推送Id
+    ///   - pushTargetType: 1-推送单个视频 2-整体关注有更新 3-关注单个up主有更新(暂废弃) 4-订阅某人有更新
+    ///   - pushBrand: 推送平台 APPLE_TYPE
+    ///   - pushTargetId: pushTargetType == 1 视频ID,pushTargetType == 4 用户ID
+    ///   - bizParam 扩展参数
+    /// - Returns: <#description#>
+    public class func bf_pushActionReportUpload(url: String, pushId: String, pushTargetType: Int, pushBrand: String?, pushTargetId: String?, bizParam: [String: Any]? = nil, commonParams: [String: Any]? = nil) {
+        DispatchQueue.global().async {
+            var params: [String: Any] = bizParam ?? Dictionary<String, Any>.init()
+            if pushTargetId != nil {
+                params["pushTargetId"] = pushTargetId
+            }
+            if pushId.count > 0 {
+                params["pushId"] = pushId
+            }
+            params["pushTargetType"] = pushTargetType
+            params["pushBrand"] = pushBrand
+            params["pushReportType"] = "click"
+            if params.keys.contains("aps") {
+                params.removeValue(forKey: "aps")
+            }
+            BFNetRequestAdaptor.postRequestData(url: url, parames: params, commonParams: commonParams) { _, _, _, _ in
+            }
+        }
+    }
+
+    /// deviceToken数据上报
+    /// - Parameter registerId: 设备id
+    /// - Parameter deviceToken: <#deviceToken description#>
+    /// - Returns: <#description#>
+    public class func bf_deviceTokenReportUpload(url: String, registerId: String, deviceToken: String, brand: String, commonParams: [String: Any]? = nil, completeHander: @escaping (_ isSuccess: Bool) -> Void) {
+        DispatchQueue.global().async {
+            BFNetRequestAdaptor.postRequestData(url: url, parames: ["registerId": registerId, "deviceToken": deviceToken, "brand": brand], commonParams: commonParams) { _, _, error, _ in
+                completeHander(error == nil ? true : false)
+            }
+        }
+    }
+
+    /// 搜索数据上报
+    /// - Parameters:
+    ///   - keyWord: 搜索词
+    ///   - searchType: 1 热搜词搜索 2 历史记录 3 普通搜索
+    ///   - searchNumber: 数量
+    ///   - reportType: 1 into 2 click 3 show
+    /// - Returns: <#description#>
+    public class func bf_searchReportUpload(url: String, keyWord: String, searchType: Int, searchNumber: Int = 10, reportType: Int = 2, commonParams: [String: Any]? = nil) {
+        DispatchQueue.global().async {
+            BFNetRequestAdaptor.postRequestData(url: url, parames: ["keyWord": keyWord, "searchType": searchType, "searchNumber": searchNumber, "reportType": reportType], commonParams: commonParams) { _, _, _, _ in
+            }
+        }
+    }
+}

+ 352 - 0
BFAnalyzeKit/Classes/BFEventTrackAdaptor.swift

@@ -0,0 +1,352 @@
+//
+//  BFEventTrackAdaptor.swift
+//  BFAnalyzeKit
+//
+//  Created by SanW on 2021/12/10.
+//
+
+import BFCommonKit
+import BFNetRequestKit
+import UIKit
+
+class BFEventTrackAdaptor: NSObject {
+    /// 基础埋点上报
+    /// - Parameters:
+    ///   - logType: 数据库类型
+    ///   - businessType: businessType
+    ///   - objectType: objectType
+    ///   - eventData: eventData
+    ///   - pageSource: 页面场景
+    ///   - extParams: extParams 扩展字段,为json对象
+    ///   - remindmsg: remindmsg 打印提示信息
+    /// - Returns: <#description#>
+    public class func baseReportUpload(logType: statisticsLogType = .st_log_type_simpleevent, businessType: businessType?, objectType: objectType?, pageSource: PAGESOURCE?, params: [String: Any]? = nil, eventData: [String: Any]? = nil, extParams: [String: Any]? = nil, commonParams: [String: Any]? = nil) {
+        BFBaseEventTrack.bf_frontendReportUpload(url: PQENVUtil.shared.commonapi + staticsFrontendReportUrl, logType: logType.rawValue, businessType: businessType?.rawValue, objectType: objectType?.rawValue, pageSource: pageSource?.rawValue, params: params, eventData: eventData, extParams: extParams, commonParams: commonParams)
+    }
+
+    /// 视频相关上报
+    /// - Parameters:
+    ///   - reportLogType: 上报库类型
+    ///   - videoData: 视频数据
+    ///   - pageSource: 页面
+    ///   - businessType: <#businessType description#>
+    ///   - objectType: <#objectType description#>
+    ///   - extParams: <#extParams description#>
+    ///   - shareId: <#shareId description#>
+    ///   - videoIds: <#videoIds description#>
+    ///   - playId: <#playId description#>
+    ///   - headVideoId: <#headVideoId description#>
+    public class func videoRelationReportUpload(reportLogType: reportLogType, videoData: BFVideoItemProtocol?, pageSource: PAGESOURCE? = nil, businessType: businessType?, objectType: objectType? = nil, extParams: [String: Any]? = nil, shareId: String? = nil, videoIds: String? = nil, playId: String? = nil, headVideoId: String? = nil, projectId: String?, parentProjectId: String?, rootProjectId: String?, canProduce: String?, parentVideoId: String?, commonParams: [String: Any]? = nil) {
+        DispatchQueue.global().async {
+            var tempExtParams: [String: Any] = extParams ?? [:]
+            if videoData?.topicData != nil {
+                if videoData?.pageSource == .sp_cmunit_joinTopic || pageSource == .sp_cmunit_joinTopic, "\(tempExtParams["topicId"] ?? "")".count <= 0 {
+                    tempExtParams["topicId"] = "\(videoData?.topicData?["id"] ?? "")"
+                } else if videoData?.pageSource == .sp_cmunit_follow || pageSource == .sp_cmunit_follow, "\(tempExtParams["followedUid"] ?? "")".count <= 0 {
+                    tempExtParams["followedUid"] = "\(videoData?.user?["uid"] ?? "")"
+                }
+            }
+            if projectId != nil && (projectId?.count ?? 0) > 0 {
+                tempExtParams["projectId"] = projectId ?? ""
+            }
+            if parentProjectId != nil && (parentProjectId?.count ?? 0) > 0 {
+                tempExtParams["parentProjectId"] = parentProjectId ?? ""
+            }
+            if rootProjectId != nil && (rootProjectId?.count ?? 0) > 0 {
+                tempExtParams["rootProjectId"] = rootProjectId ?? ""
+            }
+            if canProduce != nil && (canProduce?.count ?? 0) > 0 {
+                tempExtParams["canProduce"] = canProduce ?? ""
+            }
+            if parentVideoId != nil && (parentVideoId?.count ?? 0) > 0 {
+                tempExtParams["parentVideoId"] = parentVideoId ?? ""
+            }
+            if !tempExtParams.keys.contains("clickedVideoId") {
+                tempExtParams["videoId"] = "\(videoData?.id ?? 0)"
+            }
+            if objectType == .ot_reproduce_clickButton || objectType == .ot_reproduce_collectionBar || objectType == .ot_reproduce_collectionClicButton || objectType == .ot_reproduce_sameSourceButton {
+                baseReportUpload(businessType: businessType, objectType: objectType, pageSource: pageSource != nil ? pageSource! : (videoData?.pageSource ?? .sp_category), extParams: tempExtParams)
+            } else {
+                var url: String = PQENVUtil.shared.longvideoapi
+                var params: [String: Any] = [:]
+                switch reportLogType {
+                case .reportLogType_view:
+                    url = url + videoViewReportUrl
+                    if videoIds != nil, !videoIds!.isEmpty {
+                        params["videoIds"] = videoIds
+                    } else {
+                        params["videoIds"] = "\(videoData?.id ?? 0)"
+                    }
+                    params["viewId"] = ("\(Date().timeIntervalSince1970)" + "\(videoData?.id ?? 0)viewId" + "\(arc4random_uniform(1_000_000_000))")
+                case .reportLogType_realPlay:
+                    url = url + videoRealPlayReportUrl
+                    if businessType != nil {
+                        params["actionTriggerType"] = businessType?.rawValue
+                    }
+                case .reportLogType_play:
+                    url = url + videoPlayReportUrl
+                case .reportLogType_Action:
+                    url = url + videoActionReportUrl
+                    if businessType != nil, businessType == .bt_videoShareH5 || businessType == .bt_videoShareFriend {
+                        params["shareId"] = shareId
+                        params["rootLaunchShareId"] = shareId
+                        params["parentShareId"] = shareId
+                        params["shareDepth"] = "0"
+                        params["videoId"] = videoIds
+                    }
+                    if businessType != nil {
+                        params["businessType"] = businessType?.rawValue
+                    }
+                case .reportLogType_Frontend:
+                    url = PQENVUtil.shared.commonapi + staticsFrontendReportUrl
+                    params["LogType"] = 30
+                    params["eventData"] = bf_dictionaryToJsonString(["businessType": businessType?.rawValue ?? ""])
+                }
+                BFBaseEventTrack.bf_videoReportUpload(url: url, videoId: "\(videoData?.id ?? 0)", headVideoId: headVideoId ?? videoData?.headVideoId, playId: playId ?? "", recommendId: videoData?.recommendId, recommendLogVO: videoData?.recommendLogVO, flowPool: videoData?.flowPool, abInfoData: videoData?.abInfoData, measureType: videoData?.measureType, measureId: videoData?.measureId, businessType: businessType?.rawValue, objectType: objectType?.rawValue, pageSource: (videoData?.pageSource ?? .sp_category).rawValue, extParams: tempExtParams, commonParams: commonParams)
+            }
+        }
+    }
+
+    // 分享上报
+    // - Parameters:
+    //   - isShareVideo: 是否是分享视频
+    //   - screenType: 分享场景 1-分享视频/用户 2-分享视频到朋友圈 3-分享视频到好友
+    //   - videoId: 视频Id
+    //   - pageSource: 页面枚举
+    //   - recommendId: <#recommendId description#>
+    //   - recommendLogVO: <#recommendLogVO description#>
+    //   - abInfoData: <#abInfoData description#>
+    //   - measureType: <#measureType description#>
+    //   - measureId: <#measureId description#>
+    //   - businessType: <#businessType description#>
+    //   - targetUid: <#targetUid description#>
+    //   - shareId: <#shareId description#>
+    public class func shareReportUpload(isShareVideo: Bool = true, screenType: Int = 1, videoId: String, pageSource: PAGESOURCE, recommendId: String?, recommendLogVO: String?, flowPool: String?, abInfoData: String?, measureType: Int?, measureId: Int?, businessType: businessType?, targetUid: Int?, shareId: String = "", playId: String?, wxOpenId: String?, extParams: [String: Any]? = nil, commonParams: [String: Any]? = nil) {
+        DispatchQueue.global().async {
+            var url: String = PQENVUtil.shared.longvideoapi
+            switch screenType {
+            case 1:
+                url = url + userShareReportUrl
+            case 2:
+                url = url + userShareH5ReportUrl
+            case 3:
+                url = url + userShareFriendReportUrl
+            default:
+                break
+            }
+            BFBaseEventTrack.bf_shareReportUpload(url: url, isShareVideo: isShareVideo, screenType: screenType, videoId: videoId, recommendId: recommendId, recommendLogVO: recommendLogVO, flowPool: flowPool, abInfoData: abInfoData, measureType: measureType, measureId: measureId, targetUid: targetUid, shareId: shareId, playId: playId, wxOpenId: wxOpenId, businessType: businessType?.rawValue, pageSource: pageSource.rawValue, extParams: extParams, commonParams: commonParams)
+        }
+    }
+
+    /// DNS上报
+    /// - Returns: <#description#>
+    public class func dnsReportUpload(commonParams: [String: Any]? = nil) {
+        DispatchQueue.global().async {
+            let speedExtParams = bf_parseDNS(hostUrl: "speed.piaoquantv.com")
+            let rescdnExtParams = bf_parseDNS(hostUrl: "rescdn.yishihui.com")
+            if speedExtParams != nil {
+                baseReportUpload(businessType: .bt_dnsParseCostTime, objectType: nil, pageSource: nil, eventData: nil, extParams: speedExtParams, commonParams: commonParams)
+            }
+            if rescdnExtParams != nil {
+                baseReportUpload(businessType: .bt_dnsParseCostTime, objectType: nil, pageSource: nil, eventData: nil, extParams: rescdnExtParams, commonParams: commonParams)
+            }
+        }
+    }
+
+    /// 冷热启动数据上报
+    /// - Parameters:
+    ///   - isHotLaunch 是否是热启动
+    ///   - logType: <#logType description#>
+    ///   - eventId: <#eventId description#>
+    ///   - eventData: <#eventData description#>
+    ///   - extParams: <#extParams description#>
+    ///   - pageSource: <#pageSource description#>
+    /// - Returns: <#description#>
+//     class public func reportStatisticsUpload(isHotLaunch: Bool = false, logType: statisticsLogType, coldLaunchType _: coldLaunchType = .coldLaunchType_userActiveOpen, eventId _: String?, eventData _: String?, pageSource: PAGESOURCE?) {
+//        DispatchQueue.global().async {
+//            var params: [String: Any] = ["LogType": logType.rawValue]
+//            if PQSingletoMemoryUtil.shared.isColdLaunch {
+//                // 1-请求中 2-请求成功 3-请求失败
+//                if PQSingletoMemoryUtil.shared.coldLaunchStatus != 2 {
+//                    PQSingletoMemoryUtil.shared.coldLaunchStatus = 1
+//                } else {
+//                    return
+//                }
+//            }
+//            params["eventData"] = dictionaryToJsonString(["tabIndex": PQSingletoMemoryUtil.shared.selectedTabIndex ?? "categoryTab"])
+//            // 参数
+//            var extParams: [String: Any] = Dictionary<String, Any>.init()
+//            extParams["downloadChannel"] = channelID
+//            extParams["launchParams"] = PQSingletoMemoryUtil.shared.commandLaunchParams
+//            if pageSource?.rawValue.contains("speedApp-category") ?? false {
+//                params["pageCategoryId"] = 55
+//            }
+//            if PQSingletoMemoryUtil.shared.commandReportParams != nil {
+//                for (key, value) in PQSingletoMemoryUtil.shared.commandReportParams!.reversed() {
+//                    extParams[key] = value
+//                }
+//            }
+//            if !isHotLaunch {
+//                extParams["coldLaunchType"] = (PQSingletoMemoryUtil.shared.coldLaunchType ?? .coldLaunchType_userActiveOpen).rawValue
+//            } else {
+//                extParams["hotLaunchType"] = (PQSingletoMemoryUtil.shared.coldLaunchType ?? .coldLaunchType_userActiveOpen).rawValue
+//            }
+//            if pageSource != nil {
+//                params["pageSource"] = pageSource!.rawValue
+//            }
+//            // 是否第一次安装
+//            let firstInstall: String? = getUserDefaults(key: cFirstInstall) as? String
+//            if firstInstall == nil || (firstInstall?.count ?? 0 <= 0) || firstInstall != "1" {
+//                extParams["isFirstLaunch"] = 1
+//            } else {
+//                extParams["isFirstLaunch"] = 0
+//            }
+//            params["extParams"] = dictionaryToJsonString(extParams)
+//            // 是否第一次安装
+//            let firstParams: String? = getUserDefaults(key: cFirstParams) as? String
+//            if (firstInstall == nil || firstInstall?.count ?? 0 <= 0 || firstInstall != "1") && (firstParams != nil && ((firstParams?.count ?? 0) > 0)) {
+//                params = jsonStringToDictionary(firstParams!) ?? Dictionary<String, Any>.init()
+//            }
+//            if firstParams == nil || ((firstParams?.count ?? 0) <= 0) {
+//                saveUserDefaults(key: cFirstParams, value: dictionaryToJsonString(params) ?? "")
+//            }
+//            BFNetRequestAdaptor.postRequestData(url: PQENVUtil.shared.commonapi + staticsFrontendReportUrl, parames: params,commonParams: commonParams()) { response, _, error, _ in
+//                BFLog(message: "冷热启动上报:\(String(describing: error)),\(response ?? [:]),params = \(params)")
+//                if PQSingletoMemoryUtil.shared.isColdLaunch {
+//                    PQSingletoMemoryUtil.shared.coldLaunchStatus = error == nil ? 2 : 3
+//                }
+//                // 清空启动数据
+//                PQSingletoMemoryUtil.shared.coldLaunchType = nil
+//                if error == nil, firstInstall == nil || firstInstall?.count ?? 0 <= 0 || firstInstall != "1" {
+//                    saveUserDefaults(key: cFirstInstall, value: "1")
+//                }
+//                saveUserDefaults(key: cSelectedTabIndex, value: "categoryTab")
+//            }
+//        }
+//    }
+//
+    /// 推送点击数据上报
+    /// - Parameters:
+    ///   - pushId: 推送Id
+    ///   - pushTargetType: 1-推送单个视频 2-整体关注有更新 3-关注单个up主有更新(暂废弃) 4-订阅某人有更新
+    ///   - pushBrand: 推送平台 APPLE_TYPE
+    ///   - pushTargetId: pushTargetType == 1 视频ID,pushTargetType == 4 用户ID
+    ///   - bizParam 扩展参数
+    /// - Returns: <#description#>
+    public class func reportPushActionUpload(pushId: String, pushTargetType: Int, pushBrand: String, pushTargetId: String?, bizParam: [String: Any]? = nil, commonParams: [String: Any]? = nil) {
+        BFBaseEventTrack.bf_pushActionReportUpload(url: PQENVUtil.shared.longvideoapi + pushActionReportUrl, pushId: pushId, pushTargetType: pushTargetType, pushBrand: pushBrand, pushTargetId: pushTargetId, bizParam: bizParam, commonParams: commonParams)
+    }
+
+    /// 上报deviceToken
+    /// - Parameter registerId: 设备id
+    /// - Parameter deviceToken: <#deviceToken description#>
+    /// - Returns: <#description#>
+    public class func reportPushDeviceTokenUpload(registerId: String, deviceToken: String, brand: String, commonParams: [String: Any]? = nil, completeHander: @escaping (_ isSuccess: Bool) -> Void) {
+        BFBaseEventTrack.bf_deviceTokenReportUpload(url: PQENVUtil.shared.longvideoapi + pushDeviceTokenReportUrl, registerId: registerId, deviceToken: deviceToken, brand: brand, commonParams: commonParams, completeHander: completeHander)
+    }
+
+    /// 搜索上报
+    /// - Parameters:
+    ///   - keyWord: 搜索词
+    ///   - searchType: 1 热搜词搜索 2 历史记录 3 普通搜索
+    ///   - searchNumber: 数量
+    ///   - reportType: 1 into 2 click 3 show
+    /// - Returns: <#description#>
+    public class func searchReportUpload(keyWord: String, searchType: Int, searchNumber: Int = 10, reportType: Int = 2, commonParams: [String: Any]? = nil) {
+        BFBaseEventTrack.bf_searchReportUpload(url: PQENVUtil.shared.longvideoapi + searchReportUrl, keyWord: keyWord, searchType: searchType, searchNumber: searchNumber, reportType: reportType, commonParams: commonParams)
+    }
+
+    /// 发布视频的上报
+    /// - Parameters:
+    ///   - projectId:项目ID-发布创作的视频时必传,会在进入创作工具页时生成,以app_no_projectdata为前缀
+    ///   - businessType: <#businessType description#>
+    ///   - ossInfo: <#ossInfo description#>
+    ///   - params: <#params description#>
+    /// - Returns: <#description#>
+    public class func publishReportUpload(projectId: String?, businessType: businessType, ossInfo: [String: Any], params: [String: Any], commonParams: [String: Any]? = nil) {
+        var extParams: [String: Any] = ["ossInfo": bf_dictionaryToJsonString(ossInfo) ?? "", "params": bf_dictionaryToJsonString(params) ?? ""]
+        if projectId != nil {
+            extParams["projectId"] = projectId
+        }
+        if !extParams.keys.contains("source") {
+            extParams["source"] = projectId != nil ? "videoCompose" : "videoUpload"
+        }
+        baseReportUpload(businessType: businessType, objectType: nil, pageSource: nil, extParams: extParams, commonParams: commonParams)
+    }
+
+    // MARK: SanW--待修改-2021.12.09--挪到业务层- mediaKit
+
+    /// 处理视频创作素材搜索上报
+    /// - Parameters:
+    ///   - businessType: <#businessType description#>
+    ///   - materialList: <#materialList description#>
+    /// - Returns: <#description#>
+//    public class func dealWithMaterialSearchReportUpload(businessType: businessType, materialList: [PQEditVisionTrackMaterialsModel]) {
+//        if materialList.count > 0 {
+//            DispatchQueue.global().async {
+//                for item in materialList {
+//                    materialReportUpload(material: item, businessType: businessType)
+//                }
+//            }
+//        }
+//    }
+
+    //// MARK: SanW--待修改-2021.12.09--挪到业务层- mediaKit
+//    /// 视频创作素材搜索上报
+//    /// - Parameters:
+//    ///   - material:搜索素材
+//    ///   - searchId:搜索ID
+//    ///   - businessType: <#businessType description#>
+//    ///   - pageSource: <#pageSource description#>
+//    /// - Returns: <#description#>
+//    public class func materialReportUpload(material: PQEditVisionTrackMaterialsModel?, businessType: businessType?, objectType: objectType? = nil) {
+//        DispatchQueue.global().async {
+//            var params: [String: Any] = [:]
+//            var eventData: [String: Any] = [:]
+//            var tempObjectType: objectType? = objectType
+//            if tempObjectType == nil, material != nil {
+//                if material?.type == StickerType.GIF.rawValue {
+//                    tempObjectType = .ot_makevideo_gif
+//                } else if material?.type == StickerType.VIDEO.rawValue {
+//                    tempObjectType = .ot_makevideo_video
+//                } else if material?.type == StickerType.IMAGE.rawValue {
+//                    tempObjectType = .ot_makevideo_jpg
+//                }
+//            }
+//            if material?.searchId != nil {
+//                params["searchId"] = material?.searchId
+//                eventData["searchId"] = material?.searchId
+//            }
+//            if material?.localSearchId != nil {
+//                params["localSearchId"] = material?.localSearchId
+//                eventData["localSearchId"] = material?.localSearchId
+//            }
+//            if material?.sliceId != nil {
+//                params["sliceId"] = material?.sliceId
+//                params["videoId"] = material?.sliceId
+//            }
+//            if material?.sourceType != nil {
+//                params["sourceType"] = material?.sourceType
+//            }
+//            PQEventTrackViewModel.baseReportUpload(logType: .st_log_type_videoCompose, businessType: businessType, objectType: tempObjectType, pageSource: .sp_material_search, params: params, eventData: eventData, remindmsg: "视频创作素材搜索")
+//        }
+//    }
+
+    /// 站内消息埋点上报
+    /// - Parameters:
+    ///   - messageIds: 消息Id,多个用逗号分隔
+    ///   - clickId: 子入口点击ID,标识一次子入口点击动作。子入口内消息列表中的消息点击行为都带有此字段,分享空间消息除外
+    ///   - messageType: 消息类型
+    ///   - messageSubType: 消息子类型
+    ///   - actionType: 动作类型(backendCreate:后端构建;backendReturn:后端返回;frontendPull:前端拉取;view:曝光;click:点击)
+    ///   - objectType: <#objectType description#>
+    ///   - pageSource: <#pageSource description#>
+    ///   - readStatus: 已读状态:1:页面上显示未读 2:页面上显示已读
+    ///   - eventData: 扩展数据,json格式,日志系统里会展开存储
+    ///   - extParams: 扩展字段 json格式
+    ///   - remindmsg: 打印提示信息
+    /// - Returns: <#description#>
+    public class func messageReportUpload(messageIds: String?, clickId: String?, messageType: messageType?, messageSubType: messageSubType?, actionType: actionType?, objectType: objectType?, pageSource: PAGESOURCE?, readStatus: Int = 1, eventData: [String: Any]? = nil, extParams: [String: Any]? = nil, commonParams: [String: Any]? = nil) {
+        BFBaseEventTrack.bf_messageReportUpload(url: PQENVUtil.shared.longvideoapi + messagePeportUrl, messageIds: messageIds, clickId: clickId, messageType: messageType?.rawValue, messageSubType: messageSubType?.rawValue, actionType: actionType?.rawValue, readStatus: readStatus, objectType: objectType?.rawValue, pageSource: pageSource?.rawValue, eventData: eventData, extParams: extParams, commonParams: commonParams)
+    }
+}

+ 335 - 0
BFAnalyzeKit/Classes/PQVideoMakeEventTrackModel.swift

@@ -0,0 +1,335 @@
+//
+//  PQVideoMakeEventTrackModel.swift
+//  PQSpeed
+//
+//  Created by SanW on 2021/3/3.
+//  Copyright © 2021 BytesFlow. All rights reserved.
+//
+
+import UIKit
+import BFCommonKit
+import BFNetRequestKit
+
+public class PQVideoMakeEventTrackModel: NSObject {
+//    // 进入创作工具的入口
+//    public var entrance: videoMakeEntranceType = .entrancePublicTabCompose {
+//        didSet {
+//            isPureUploadVideo = entrance == .entrancePublicTabUpload
+//            isReproduction = entrance == .entranceReproduction
+//        }
+//    }
+//
+//    // 草稿 Id
+//    public var draftId: String?
+//    // 项目 Id
+//    public var projectId: String?
+//    // 再创作视频的父 projectId - 仅「再创作」视频存在
+//    public var fatherProjectId: String?
+//    // 再创作视频的根 projectId - 仅「再创作」视频存在
+//    public var rootProjectId: String?
+//    // 再编辑视频的父 draftId - 仅「再编辑」视频存在
+//    public var fatherDraftId: String?
+//
+//    // 发布标题
+//    public var title: String?
+//    // 发布描述
+//    public var videoDes: String?
+//    // 发布封面的 URL
+//    public var coverUrl: String?
+//    // 发布的视频 Id
+//    public var videoId: String?
+//
+//    /**
+//      用户创作视频所用的时间成本,单位:毫秒(ms)
+//      (仅包含合成前的时间段,不包含合成后选择封面等时间消耗)
+//     如果是草稿箱项目,不包含之前累计的时间消耗,仅记录发布这一次的时间消耗
+//     如果是再创作项目,不包含别人创作的时间消耗,仅记录发布这一次的时间消耗
+//     如果是多次发布的项目,不包含之前累计的时间消耗,仅记录发布这一次的时间消耗
+//     */
+//    public var editTimeCost: Float64 = 0
+//    // 合成视频所用的时间成本,单位:毫秒(ms)
+//    public var composeTimeCost: Float64 = 0
+//    // 上传视频所用的时间成本,单位:毫秒(ms)
+//    public var uploadTimeCost: Float64 = 0
+//
+//    // 是否为纯上传视频 纯上传视频:true 加工工具视频:false
+//    public var isPureUploadVideo: Bool = false
+//    // 是否为再创作视频 再创作视频:true 非再创作视频:false
+//    public var isReproduction: Bool = false
+//    // 是否为再编辑视频 再编辑视频:true 非再编辑视频:false
+//    public var isCopyVideo: Bool = false
+//    // 段落相关-视频中存在的段落个数:number
+//    public var sectionNum: Int = 1
+//    // 文字相关 段落中的文字长度信息:number[] [​ section1-text-length, section2-text-length, ... ]
+//    public var secTextLength: [Int] = Array<Int>.init()
+//    // 图片 / 视频素材相关 段落中的(本地素材)图片数量:number[] [ section1-localImage-num, section2-localImage-num, ... ]
+//    public var secLocalImageNum: [Int] = Array<Int>.init()
+//    // 图片 / 视频素材相关 段落中的(本地素材)动图数量:number[] [ section1-localGif-num, section2-localGif-num, ... ]
+//    public var secLocalGifNum: [Int] = Array<Int>.init()
+//    // 图片 / 视频素材相关 段落中的(本地素材)视频数量:number[] [ section1-localVideo-num, section2-localVideo-num, ... ]
+//    public var secLocalVideoNum: [Int] = Array<Int>.init()
+//    // 图片/视频素材相关 -段落中的(网络素材)图片数量
+//    public var secCloudImageNum: [Int] = Array<Int>.init()
+//    // 图片/视频素材相关 -段落中(网络素材)动图数量
+//    public var secCloudGifNum: [Int] = Array<Int>.init()
+//    // 图片/视频素材相关 -段落中(网络素材)视频数量
+//    public var secCloudVideoNum: [Int] = Array<Int>.init()
+//    // 文字转语音相关 -段落中使用的语音素材名称,若段落中没有使用则报""
+//    public var secTextToSpeechMaterial: [String] = Array<String>.init()
+//    // 文字转语音相关 -段落中文字转语音的毫秒数
+//    public var secTextToSpeechTime: [Int64] = Array<Int64>.init()
+//    // 语音转文字相关 -每个段落中使用录音的毫秒数
+//    public var secSpeechToTextTime: [Int64] = Array<Int64>.init()
+//
+//    // 开始上传时间
+//    public var startUploadDate: Float64 = 0
+//    // 结束上传时间
+//    public var endUploadDate: Float64 = 0 {
+//        didSet {
+//            uploadTimeCost = (endUploadDate - startUploadDate) * 1000
+//        }
+//    }
+//
+//    // 使用音乐的名称(未使用音乐默认为 "")
+//    public var musicName: String = ""
+//    // 使用音乐Id
+//    public var musicId: String = ""
+//    // 使用音乐的地址(未使用音乐默认为 "")
+//    public var musicUrl: String = ""
+//    // 音乐的类型(未使用音乐默认为 "") - original - 原唱 - accompaniment - 伴奏
+//    public var musicType: String = ""
+//    // 音乐是否为片段(未使用音乐默认为 "")- true - 音乐片段 - false - 完整音乐
+//    public var isMusicClip: Bool = false
+//    // 画布比例
+//    public var canvasRatio: String = "original"
+//    // 卡点视频 使用视频素材数量
+//    public var syncedUpVideoNumber: Int = 0
+//    // 卡点视频 使用图片素材数量
+//    public var syncedUpImageNumber: Int = 0
+//    // 卡点视频 使用音乐Id
+//    public var syncedUpMusicId: String = ""
+//    // 卡点视频 使用音乐名称
+//    public var syncedUpMusicName: String = ""
+//    // 卡点视频 合成后视频长度(单位:毫秒)
+//    public var syncedUpVideoDuration: Float64 = 0
+//    // 卡点视频 原素材总时长(单位:毫秒)视频:报视频时长 图片:一张图报 1000ms
+//    public var syncedUpOriginalMaterialDuration: Float64 = 0
+//    // 卡点视频 视频选用节奏名称(快节奏 1、适中 2、慢节奏 3))
+//    public var syncedUpRhythmNumber: Int = 2
+//    public var syncedUpVideoType:createStickersModel = .createStickersModelPoint
+//    public var syncedUpVideoSpeedMax:Float = 0.0
+//    public var syncedUpVideoSpeedMin:Float = 0.0
+//    
+//    override public init() {
+//        super.init()
+//    }
+
+    /// 初始化
+    /// - Parameter projectModel: <#projectModel description#>
+//   public init(projectModel: PQEditProjectModel?, reCreateData: PQReCreateModel?) {
+//        super.init()
+//        if projectModel != nil {
+//            draftId = projectModel?.draftboxId
+//            projectId = projectModel?.projectId
+//            sectionNum = projectModel?.sData?.sections.count ?? 1
+//            if projectModel?.sData?.sections != nil, (projectModel?.sData?.sections.count ?? 0) > 0 {
+//                for section in (projectModel?.sData?.sections)! {
+//                    if section.sectionType == "normal" {
+//                        // 段落中的文字长度信息
+//                        let voiceType: VOICETYPT? = VOICETYPT(rawValue: section.sectionTimeline?.audioTrack?.audioTrackMaterials.first?.voiceType ?? "")
+//                        if voiceType == .SPEECH || voiceType == .LOCAL {
+//                            secTextLength.append(section.getInputSubtitle().count)
+//                        } else {
+//                            secTextLength.append(section.sectionText.count)
+//                        }
+//                        // 段落中使用的语音素材名称
+//                        secTextToSpeechMaterial.append(section.sectionTimeline?.audioTrack?.audioTrackMaterials.first?.produceVoiceConfig?.voice ?? "")
+//                        // 段落中文字转语音的毫秒数
+//                        var duration: Float64 = 0
+//                        if voiceType != nil && section.audioFilePath.count > 0 {
+//                            let audioAsset = AVURLAsset(url: URL(fileURLWithPath: documensDirectory + section.audioFilePath), options: avAssertOptions)
+//                            duration = Float64(audioAsset.duration.seconds * 1000)
+//                        }
+//                        if voiceType == .SPEECH || voiceType == .LOCAL {
+//                            secSpeechToTextTime.append(Int64(duration))
+//                            secTextToSpeechTime.append(0)
+//                        } else {
+//                            secTextToSpeechTime.append(Int64(duration))
+//                            secSpeechToTextTime.append(0)
+//                        }
+//                        // 本地图片数量
+//                        var localImageCount: Int = 0
+//                        // 本地gif数量
+//                        var localGifCount: Int = 0
+//                        // 本地视频数量
+//                        var localVideoCount: Int = 0
+//                        // 网络图片数量
+//                        var netImageCount: Int = 0
+//                        // 网络gif数量
+//                        var netGifCount: Int = 0
+//                        // 网络视频数量
+//                        var netVideoCount: Int = 0
+//                        if section.sectionTimeline?.visionTrack?.visionTrackMaterials != nil, (section.sectionTimeline?.visionTrack?.visionTrackMaterials.count ?? 0) > 0 {
+//                            for visionMaterial in (section.sectionTimeline?.visionTrack?.visionTrackMaterials)! {
+//                                switch visionMaterial.type {
+//                                case "image":
+//                                    if visionMaterial.netResCoverImageURL != nil, (visionMaterial.netResCoverImageURL?.count ?? 0) > 0 {
+//                                        netImageCount += 1
+//                                    } else {
+//                                        localImageCount += 1
+//                                    }
+//                                case "gif":
+//                                    if visionMaterial.netResCoverImageURL != nil, (visionMaterial.netResCoverImageURL?.count ?? 0) > 0 {
+//                                        netGifCount += 1
+//                                    } else {
+//                                        localGifCount += 1
+//                                    }
+//                                case "video":
+//                                    if visionMaterial.netResUrl.count > 0 {
+//                                        netVideoCount += 1
+//                                    } else {
+//                                        localVideoCount += 1
+//                                    }
+//                                default:
+//                                    break
+//                                }
+//                            }
+//                        }
+//                        // 本地素材图片数量
+//                        secLocalImageNum.append(localImageCount)
+//                        // 本地素材动图数量
+//                        secLocalGifNum.append(localGifCount)
+//                        // 本地素材视频数量
+//                        secLocalVideoNum.append(localVideoCount)
+//                        // 网络素材图片数量
+//                        secCloudImageNum.append(netImageCount)
+//                        // 网络素材动图数量
+//                        secCloudGifNum.append(netGifCount)
+//                        // 网络素材视频数量
+//                        secCloudVideoNum.append(netVideoCount)
+//                    } else {
+//                        sectionNum = sectionNum - 1
+//                        if sectionNum <= 0 {
+//                            sectionNum = 1
+//                        }
+//                    }
+//                }
+//            }
+//        }
+//        if reCreateData != nil {
+//            fatherProjectId = reCreateData?.projectId
+//            rootProjectId = reCreateData?.rootProjectId ?? reCreateData?.projectId
+//            fatherDraftId = reCreateData?.draftboxId
+//        }
+//    }
+
+//    /// 转换为字典
+//    /// - Returns: <#description#>
+//    public func toParams() -> [String: Any] {
+//        var eventTrackDic = Dictionary<String, Any>.init()
+//        // 进入创作工具的入口
+//        eventTrackDic["entrance"] = entrance.rawValue
+//        // 发布的视频 Id
+//        eventTrackDic["videoId"] = videoId ?? ""
+//        // 草稿 Id
+//        eventTrackDic["draftId"] = draftId ?? ""
+//        // 项目 Id
+//        eventTrackDic["projectId"] = projectId ?? ""
+//        // 再创作视频的父 projectId - 仅「再创作」视频存在
+//        eventTrackDic["fatherProjectId"] = fatherProjectId ?? ""
+//        // 再创作视频的根 projectId - 仅「再创作」视频存在
+//        eventTrackDic["rootProjectId"] = rootProjectId ?? ""
+//        // 再编辑视频的父 draftId - 仅「再编辑」视频存在
+//        eventTrackDic["fatherDraftId"] = fatherDraftId ?? ""
+//        // 发布标题
+//        eventTrackDic["title"] = title ?? ""
+//        // 发布描述
+//        eventTrackDic["description"] = videoDes ?? ""
+//        // 发布封面的 URL
+//        eventTrackDic["coverUrl"] = coverUrl ?? ""
+//        /**
+//          用户创作视频所用的时间成本,单位:毫秒(ms)
+//          (仅包含合成前的时间段,不包含合成后选择封面等时间消耗)
+//         如果是草稿箱项目,不包含之前累计的时间消耗,仅记录发布这一次的时间消耗
+//         如果是再创作项目,不包含别人创作的时间消耗,仅记录发布这一次的时间消耗
+//         如果是多次发布的项目,不包含之前累计的时间消耗,仅记录发布这一次的时间消耗
+//         */
+//        eventTrackDic["editTimeCost"] = Int64(editTimeCost)
+//        // 合成视频所用的时间成本,单位:毫秒(ms)
+//        eventTrackDic["composeTimeCost"] = Int64(composeTimeCost)
+//        // 上传视频所用的时间成本,单位:毫秒(ms)
+//        eventTrackDic["uploadTimeCost"] = Int64(uploadTimeCost)
+//        // 是否为纯上传视频 纯上传视频:true 加工工具视频:false
+//        eventTrackDic["isPureUploadVideo"] = isPureUploadVideo
+//        // 是否为再创作视频 再创作视频:true 非再创作视频:false
+//        eventTrackDic["isReproduction"] = isReproduction
+//        // 是否为再编辑视频 再编辑视频:true 非再编辑视频:false
+//        eventTrackDic["isCopyVideo"] = isCopyVideo
+//        // 段落相关-视频中存在的段落个数:number
+//        eventTrackDic["sectionNum"] = entrance == .entrancePublicTabUpload ? 0 : sectionNum
+//        // 文字相关 -段落中的文字长度信息
+//        eventTrackDic["secTextLength"] = secTextLength
+//        // 图片/视频素材相关 -段落中的(本地素材)图片数量
+//        eventTrackDic["secLocalImageNum"] = secLocalImageNum
+//        // 图片/视频素材相关 -段落中的(本地素材)动图数量
+//        eventTrackDic["secLocalGifNum"] = secLocalGifNum
+//        // 图片/视频素材相关 -段落中的(本地素材)视频数量
+//        eventTrackDic["secLocalVideoNum"] = secLocalVideoNum
+//        // 图片/视频素材相关 -段落中的(网络素材)图片数量
+//        eventTrackDic["secCloudImageNum"] = secCloudImageNum
+//        // 图片/视频素材相关 -段落中(网络素材)动图数量
+//        eventTrackDic["secCloudGifNum"] = secCloudGifNum
+//        // 图片/视频素材相关 -段落中(网络素材)视频数量
+//        eventTrackDic["secCloudVideoNum"] = secCloudVideoNum
+//        // 文字转语音相关 -段落中使用的语音素材名称,若段落中没有使用则报""
+//        eventTrackDic["secTextToSpeechMaterial"] = secTextToSpeechMaterial
+//        // 文字转语音相关 -段落中文字转语音的毫秒数
+//        eventTrackDic["secTextToSpeechTime"] = secTextToSpeechTime
+//        // 语音转文字相关 -每个段落中使用录音的毫秒数
+//        eventTrackDic["secSpeechToTextTime"] = secSpeechToTextTime
+//        // 实验数据abInfoData
+//        eventTrackDic["abInfoData"] = dictionaryToJsonString(bf_a) ?? ""
+//        // 使用音乐的名称(未使用音乐默认为 "")
+//        eventTrackDic["musicName"] = musicName
+//        // 使用音乐Id
+//        eventTrackDic["musicId"] = musicId
+//        // 使用音乐的地址(未使用音乐默认为 "")
+//        eventTrackDic["musicUrl"] = musicUrl
+//        // 音乐的类型(未使用音乐默认为 "") - original - 原唱 - accompaniment - 伴奏
+//        eventTrackDic["musicType"] = musicType
+//        // 音乐是否为片段(未使用音乐默认为 "")- true - 音乐片段 - false - 完整音乐
+//        if musicType.count > 0 {
+//            eventTrackDic["isMusicClip"] = isMusicClip
+//        } else {
+//            eventTrackDic["isMusicClip"] = ""
+//        }
+//        // 画布比例
+//        eventTrackDic["canvasRatio"] = canvasRatio
+//        // 卡点视频 使用视频素材数量
+//        eventTrackDic["syncedUpVideoNumber"] = syncedUpVideoNumber
+//        // 卡点视频 使用图片素材数量
+//        eventTrackDic["syncedUpImageNumber"] = syncedUpImageNumber
+//        // 卡点视频 使用音乐Id
+//        eventTrackDic["syncedUpMusicId"] = syncedUpMusicId
+//        // 卡点视频 使用音乐名称
+//        eventTrackDic["syncedUpMusicName"] = syncedUpMusicName
+//        // 卡点视频 合成后视频长度(单位:毫秒)
+//        eventTrackDic["syncedUpVideoDuration"] = syncedUpVideoDuration
+//        // 卡点视频 原素材总时长(单位:毫秒)视频:报视频时长 图片:一张图报 1000ms
+//        eventTrackDic["syncedUpOriginalMaterialDuration"] = syncedUpOriginalMaterialDuration
+//        // 卡点视频 视频选用节奏名称(快节奏 1、适中 2、慢节奏 3))
+//        eventTrackDic["syncedUpRhythmNumber"] = syncedUpRhythmNumber
+//
+//        //-     1:跳跃卡点,2:快慢速,3:仅配乐
+//        if(syncedUpVideoType == .createStickersModelOnlyMusic){
+//            eventTrackDic["syncedUpVideoType"] = "3"
+//        }else if(syncedUpVideoType == .createStickersModelPoint){
+//            eventTrackDic["syncedUpVideoType"] = "1"
+//        }else if(syncedUpVideoType == .createStickersModelSpeed){
+//            eventTrackDic["syncedUpVideoType"] = "2"
+//            eventTrackDic["syncedUpVideoSpeed"] = "[\(syncedUpVideoSpeedMax),\(syncedUpVideoSpeedMin)]"
+//        }
+//        NTLog(message: "创作工具埋点信息数据-\(eventTrackDic)")
+//        return eventTrackDic
+//    }
+}

+ 0 - 0
BFAnalyzeKit/Classes/ReplaceMe.swift


+ 34 - 6
Example/BFAnalyzeKit.xcodeproj/project.pbxproj

@@ -28,7 +28,7 @@
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
-		1B4BAFEAD7F25CCC2E56DD19 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
+		1B4BAFEAD7F25CCC2E56DD19 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
 		3F9EAF45E7CA5269730608FF /* Pods_BFAnalyzeKit_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BFAnalyzeKit_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		4E58B07D9DF8CCF267CB8562 /* Pods-BFAnalyzeKit_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BFAnalyzeKit_Example.release.xcconfig"; path = "Target Support Files/Pods-BFAnalyzeKit_Example/Pods-BFAnalyzeKit_Example.release.xcconfig"; sourceTree = "<group>"; };
 		607FACD01AFB9204008FA782 /* BFAnalyzeKit_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BFAnalyzeKit_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -41,9 +41,9 @@
 		607FACE51AFB9204008FA782 /* BFAnalyzeKit_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BFAnalyzeKit_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		607FACEB1AFB9204008FA782 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = "<group>"; };
-		6299DB3344C00E68A0F8CAC0 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; name = README.md; path = ../README.md; sourceTree = "<group>"; };
+		6299DB3344C00E68A0F8CAC0 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
 		6A3AA4F124BA1B0F3B1249AC /* Pods-BFAnalyzeKit_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BFAnalyzeKit_Example.debug.xcconfig"; path = "Target Support Files/Pods-BFAnalyzeKit_Example/Pods-BFAnalyzeKit_Example.debug.xcconfig"; sourceTree = "<group>"; };
-		D1A20F98AE8B0607DA426B0D /* BFAnalyzeKit.podspec */ = {isa = PBXFileReference; includeInIndex = 1; name = BFAnalyzeKit.podspec; path = ../BFAnalyzeKit.podspec; sourceTree = "<group>"; };
+		D1A20F98AE8B0607DA426B0D /* BFAnalyzeKit.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = BFAnalyzeKit.podspec; path = ../BFAnalyzeKit.podspec; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
 		D9DE263D6EC80BE439016F05 /* Pods-BFAnalyzeKit_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BFAnalyzeKit_Tests.debug.xcconfig"; path = "Target Support Files/Pods-BFAnalyzeKit_Tests/Pods-BFAnalyzeKit_Tests.debug.xcconfig"; sourceTree = "<group>"; };
 		EA52F3C9F956E68BF49A920B /* Pods-BFAnalyzeKit_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BFAnalyzeKit_Tests.release.xcconfig"; path = "Target Support Files/Pods-BFAnalyzeKit_Tests/Pods-BFAnalyzeKit_Tests.release.xcconfig"; sourceTree = "<group>"; };
 		F8E16AE867F99CF362603E00 /* Pods_BFAnalyzeKit_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BFAnalyzeKit_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -147,7 +147,6 @@
 				D9DE263D6EC80BE439016F05 /* Pods-BFAnalyzeKit_Tests.debug.xcconfig */,
 				EA52F3C9F956E68BF49A920B /* Pods-BFAnalyzeKit_Tests.release.xcconfig */,
 			);
-			name = Pods;
 			path = Pods;
 			sourceTree = "<group>";
 		};
@@ -213,10 +212,12 @@
 				TargetAttributes = {
 					607FACCF1AFB9204008FA782 = {
 						CreatedOnToolsVersion = 6.3.1;
+						DevelopmentTeam = UH52C8A7SN;
 						LastSwiftMigration = 0900;
 					};
 					607FACE41AFB9204008FA782 = {
 						CreatedOnToolsVersion = 6.3.1;
+						DevelopmentTeam = UH52C8A7SN;
 						LastSwiftMigration = 0900;
 						TestTargetID = 607FACCF1AFB9204008FA782;
 					};
@@ -227,6 +228,7 @@
 			developmentRegion = English;
 			hasScannedForEncodings = 0;
 			knownRegions = (
+				English,
 				en,
 				Base,
 			);
@@ -269,11 +271,33 @@
 			);
 			inputPaths = (
 				"${PODS_ROOT}/Target Support Files/Pods-BFAnalyzeKit_Example/Pods-BFAnalyzeKit_Example-frameworks.sh",
+				"${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework",
 				"${BUILT_PRODUCTS_DIR}/BFAnalyzeKit/BFAnalyzeKit.framework",
+				"${BUILT_PRODUCTS_DIR}/BFCommonKit/BFCommonKit.framework",
+				"${BUILT_PRODUCTS_DIR}/BFNetRequestKit/BFNetRequestKit.framework",
+				"${BUILT_PRODUCTS_DIR}/KeychainAccess/KeychainAccess.framework",
+				"${BUILT_PRODUCTS_DIR}/Kingfisher/Kingfisher.framework",
+				"${BUILT_PRODUCTS_DIR}/KingfisherWebP/KingfisherWebP.framework",
+				"${BUILT_PRODUCTS_DIR}/ObjectMapper/ObjectMapper.framework",
+				"${BUILT_PRODUCTS_DIR}/Realm/Realm.framework",
+				"${BUILT_PRODUCTS_DIR}/RealmSwift/RealmSwift.framework",
+				"${BUILT_PRODUCTS_DIR}/Toast-Swift/Toast_Swift.framework",
+				"${BUILT_PRODUCTS_DIR}/libwebp/libwebp.framework",
 			);
 			name = "[CP] Embed Pods Frameworks";
 			outputPaths = (
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BFAnalyzeKit.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BFCommonKit.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BFNetRequestKit.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KeychainAccess.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Kingfisher.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KingfisherWebP.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ObjectMapper.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Realm.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RealmSwift.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Toast_Swift.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
@@ -419,7 +443,7 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.0;
 				MTL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = iphoneos;
@@ -465,7 +489,7 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+				IPHONEOS_DEPLOYMENT_TARGET = 10.0;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				SDKROOT = iphoneos;
 				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
@@ -478,6 +502,7 @@
 			baseConfigurationReference = 6A3AA4F124BA1B0F3B1249AC /* Pods-BFAnalyzeKit_Example.debug.xcconfig */;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				DEVELOPMENT_TEAM = UH52C8A7SN;
 				INFOPLIST_FILE = BFAnalyzeKit/Info.plist;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 				MODULE_NAME = ExampleApp;
@@ -493,6 +518,7 @@
 			baseConfigurationReference = 4E58B07D9DF8CCF267CB8562 /* Pods-BFAnalyzeKit_Example.release.xcconfig */;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				DEVELOPMENT_TEAM = UH52C8A7SN;
 				INFOPLIST_FILE = BFAnalyzeKit/Info.plist;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 				MODULE_NAME = ExampleApp;
@@ -507,6 +533,7 @@
 			isa = XCBuildConfiguration;
 			baseConfigurationReference = D9DE263D6EC80BE439016F05 /* Pods-BFAnalyzeKit_Tests.debug.xcconfig */;
 			buildSettings = {
+				DEVELOPMENT_TEAM = UH52C8A7SN;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(PLATFORM_DIR)/Developer/Library/Frameworks",
 					"$(inherited)",
@@ -529,6 +556,7 @@
 			isa = XCBuildConfiguration;
 			baseConfigurationReference = EA52F3C9F956E68BF49A920B /* Pods-BFAnalyzeKit_Tests.release.xcconfig */;
 			buildSettings = {
+				DEVELOPMENT_TEAM = UH52C8A7SN;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(PLATFORM_DIR)/Developer/Library/Frameworks",
 					"$(inherited)",

+ 10 - 0
Example/BFAnalyzeKit.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "group:BFAnalyzeKit.xcodeproj">
+   </FileRef>
+   <FileRef
+      location = "group:Pods/Pods.xcodeproj">
+   </FileRef>
+</Workspace>

+ 8 - 0
Example/BFAnalyzeKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IDEDidComputeMac32BitWarning</key>
+	<true/>
+</dict>
+</plist>

+ 6 - 1
Example/Podfile

@@ -1,9 +1,14 @@
 use_frameworks!
 
-platform :ios, '9.0'
+platform :ios, '10.0'
 
 target 'BFAnalyzeKit_Example' do
+  source 'https://git.yishihui.com/iOS/BFSpecs.git'
+  source 'https://github.com/CocoaPods/Specs.git'
+  
   pod 'BFAnalyzeKit', :path => '../'
+  pod 'BFCommonKit',            :path => '../../../BFCommonKit/Trunk'
+  pod 'BFNetRequestKit',        :path => '../../../BFNetRequestKit/Trunk'
 
   target 'BFAnalyzeKit_Tests' do
     inherit! :search_paths