iOS app內(nèi)埋點(diǎn)切面的分析思路(基于swift3)

前言

埋點(diǎn)統(tǒng)計在項目中還是比較常見的,可以用來分析用戶的習(xí)慣熏兄,從而有針對性的去優(yōu)化app秘狞。傳統(tǒng)的做法就是在每個具體的事件觸發(fā)的地方進(jìn)行埋點(diǎn),這種方法比較機(jī)械肯夏,更多的是一項體力活经宏,而且等項目越來越大犀暑,埋的點(diǎn)遍布于真?zhèn)€項目中,可能你自己都找不到烁兰,非常不利于后期的維護(hù)耐亏。當(dāng)然最好的辦法就是利用OC的runtime黑魔法,swift也是可以用的缚柏,只不過有些方法是不可用的苹熏,但是功能是可以滿足的,接下來就帶大家看一下統(tǒng)計進(jìn)行埋點(diǎn)的思路分析币喧。

runtime和Method Swizzling

用到的方法大致是:

public func class_getInstanceMethod(_ cls: Swift.AnyClass!, _ name: Selector!) -> Method!

public func class_addMethod(_ cls: Swift.AnyClass!, _ name: Selector!, _ imp: IMP!, _ types: UnsafePointer!) -> Bool

public func method_exchangeImplementations(_ m1: Method!, _ m2: Method!)

大致的思路就是:找到一個底層的方法(就是事件下發(fā)都會經(jīng)過的一個方法)轨域,然后利用runtime替換調(diào)兩個方法的實(shí)現(xiàn)。

唯一字符串——identifier生成的規(guī)則

為什么要生成identifier杀餐?這是為了保證確定某個控件觸發(fā)的事件是唯一的干发,事件唯一就能夠映射上埋點(diǎn)的事件。那么它的生成規(guī)則是什么史翘?
基本上生成規(guī)則是:當(dāng)前某個視圖名+某控件+action名稱+target名稱枉长。
注意swift是具有命名控件規(guī)則的,獲取的class名一般是這樣的:projectname.classname這種格式的琼讽,用的時候稍微注意下必峰。

具體的埋點(diǎn)實(shí)例

首先定義一個埋點(diǎn)的管理對象:

struct AspectManager {
    static func swizzle(inClass `class`: AnyClass, swizzle : Selector, original: Selector){
        
        let originalMethod = class_getInstanceMethod(`class`, original)
        let swizzleMethod = class_getInstanceMethod(`class`, swizzle)
        
        let didAddMethod = class_addMethod(`class`, original, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod))
        
        if didAddMethod {
            class_replaceMethod(`class`, swizzle, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
        } else {
            method_exchangeImplementations(originalMethod, swizzleMethod)
        }
    } 
}

用來交換某個類的兩個方法的實(shí)現(xiàn)。

UIControl

這里我們需要用到的方法是:

open func sendAction(_ action: Selector, to target: Any?, for event: UIEvent?)

只要是繼承于UIControl的事件都會經(jīng)過這個方法钻蹬,接下來直接上代碼:

extension UIControl{
    open override class func initialize() {
        super.initialize()
        
        //make sure this isn't a subclass
        if self !== UIControl.self {
            return
        }
        
        DispatchQueue.once(token: "com.moglo.niqq.UIControl") {
            swizzle()
        }
        
    }
    
    
    fileprivate class func swizzle(){
        let originalSelector = #selector(UIControl.sendAction(_:to:for:))
        let swizzleSelector = #selector(UIControl.nsh_sendAction(_:to:for:))
        AspectManager.swizzle(inClass: self, swizzle: swizzleSelector, original: originalSelector)
    }
    
    
    func nsh_sendAction(_ action: Selector, to target: Any?, for event: UIEvent?){
        //因?yàn)榻粨Q了兩個方法的實(shí)現(xiàn)所以不用擔(dān)心會死循環(huán)
        nsh_sendAction(action, to: target, for: event)
        
        //在這里做你想要處理的埋點(diǎn)事件吼蚁,identifier可以自己配置一個文件,然后按照生成的id去取定義好的一些需要埋點(diǎn)的事件名
    }
}

這樣一來所有的UIButton问欠、UITextView等的事件都會被攔截肝匆,需要處理的事情可以統(tǒng)一在這里處理

UITableView與UICollectionView

這里我們需要替換的是代理方法的cell的點(diǎn)擊事件:

optional public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)

那么首先我們需要替換的是代理的設(shè)置:

    fileprivate class func swizzle(){
        let originalSelector = #selector(setter: UITableView.delegate)
        let swizzleSelector = #selector(UITableView.nsh_set(delegate:))
        AspectManager.swizzle(inClass: self, swizzle: swizzleSelector, original: originalSelector)
    }
    
    
    func nsh_set(delegate: UITableViewDelegate?){
        nsh_set(delegate: delegate)
        
        guard let delegate =  delegate else {return}
        Logger.Debug(info: "UITableView set delegate:\(delegate)")
        
    }

其次是要給代理添加一個在自定義的方法

    func nsh_tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
         nsh_tableView(tableView, didSelectRowAt: indexPath)
         //這里添加你需要的埋點(diǎn)代碼
    }

接下來就是直接替換兩個類的實(shí)現(xiàn),完整代碼:

       func nsh_set(delegate: UITableViewDelegate?){
        nsh_set(delegate: delegate)
        
        guard let delegate =  delegate else {return}
        Logger.Debug(info: "UITableView set delegate:\(delegate)")
        //交換cell點(diǎn)擊事件
        
        let originalSelector = #selector(delegate.tableView(_:didSelectRowAt:))
        let swizzleSelector = #selector(UITableView.nsh_tableView(_:didSelectRowAt:))
        let swizzleMethod = class_getInstanceMethod(UITableView.self, swizzleSelector)
        
        let didAddMethod = class_addMethod(type(of: delegate), swizzleSelector, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod))
        if didAddMethod{
            let didSelectOriginalMethod = class_getInstanceMethod(type(of: delegate), NSSelectorFromString("nsh_tableView:didSelectRowAt:"))
            let didSelectSwizzledMethod = class_getInstanceMethod(type(of: delegate), originalSelector)
            method_exchangeImplementations(didSelectOriginalMethod, didSelectSwizzledMethod)
        }
        
    }

UICollectionView同理顺献,這里就不在贅述旗国。

這里總結(jié)的可能還有不完善的地方,希望大家批評指正

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末注整,一起剝皮案震驚了整個濱河市能曾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肿轨,老刑警劉巖寿冕,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異萝招,居然都是意外死亡蚂斤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門槐沼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來曙蒸,“玉大人捌治,你說我怎么就攤上這事∨撸” “怎么了肖油?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長臂港。 經(jīng)常有香客問我森枪,道長,這世上最難降的妖魔是什么审孽? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任县袱,我火速辦了婚禮,結(jié)果婚禮上佑力,老公的妹妹穿的比我還像新娘式散。我一直安慰自己,他們只是感情好打颤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布暴拄。 她就那樣靜靜地躺著,像睡著了一般编饺。 火紅的嫁衣襯著肌膚如雪乖篷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天透且,我揣著相機(jī)與錄音撕蔼,去河邊找鬼。 笑死石蔗,一個胖子當(dāng)著我的面吹牛罕邀,可吹牛的內(nèi)容都是我干的畅形。 我是一名探鬼主播养距,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼日熬!你這毒婦竟也來了棍厌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤竖席,失蹤者是張志新(化名)和其女友劉穎耘纱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體毕荐,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡束析,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了憎亚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片员寇。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡弄慰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蝶锋,到底是詐尸還是另有隱情陆爽,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布扳缕,位于F島的核電站慌闭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏躯舔。R本人自食惡果不足惜驴剔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望粥庄。 院中可真熱鬧仔拟,春花似錦、人聲如沸飒赃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽载佳。三九已至炒事,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蔫慧,已是汗流浹背挠乳。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留姑躲,地道東北人睡扬。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像黍析,于是被迫代替她去往敵國和親卖怜。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容