互聯(lián)網(wǎng)產(chǎn)品對用戶行為的數(shù)據(jù)有多渴望,相信我也不用多說了漩绵,上至微信殉农,下至小作坊,每一個(gè)公司每一個(gè)有稍微專業(yè)點(diǎn)的產(chǎn)品經(jīng)理或者技術(shù)人員蟀淮,都想知道做出來的產(chǎn)品用戶到底有沒有在用那些功能用得多最住,用的頻率怎樣。淘寶灭贷、天貓温学、京東這些APP為什么每次打開的時(shí)候看到的東西感覺都挺熟悉?是不是上幾次查詢的商品甚疟?這些都是典型的用戶行為分析得出來的定制結(jié)果仗岖。
人都有惰性,都很懶览妖。技術(shù)人員更懶轧拄,都想按一個(gè)回車就不想管事情。那用戶行為的數(shù)據(jù)怎么拿到讽膏?每一個(gè)方法前后都要hard code一句話檩电?那開發(fā)不得累死。有沒有更好更聰明的辦法府树?畢竟是人都想偷懶俐末,都想上班摸魚。當(dāng)然有奄侠,下面說得內(nèi)容會涉及幾個(gè)關(guān)鍵詞:AOP卓箫、AspectJ、Gradle垄潮、plugin烹卒、ASM
基于用戶行為數(shù)據(jù)的重要性闷盔,我在公司內(nèi)部推動了一項(xiàng)全埋點(diǎn)數(shù)據(jù)收集的專項(xiàng)項(xiàng)目。主要的解決方案來自《Android全埋點(diǎn)解決方案》這本書旅急,現(xiàn)學(xué)現(xiàn)用逢勾。
一、Activity生命周期狀態(tài)監(jiān)控
通過Application的registerActivityLifecycleCallbacks方法藐吮,監(jiān)聽所有Activity的生命周期回調(diào)溺拱。書中的例子只監(jiān)聽onActivityResumed回調(diào),因?yàn)閛nResumed方法必定會執(zhí)行谣辞。
源碼:https://github.com/wangzhzh/AutoTrackAppViewScreen
二盟迟、AppStart、AppEnd事件監(jiān)控
記錄AppStart事件:依然是通過Application的registerActivityLifecycleCallbacks方法潦闲,監(jiān)聽onActivityStarted回調(diào),記錄AppStart事件迫皱。
記錄AppEnd事件:內(nèi)部實(shí)現(xiàn)一個(gè)CountDownTimer計(jì)數(shù)器歉闰,如果Activity執(zhí)行了onActivityPaused回調(diào),則計(jì)數(shù)器開始工作卓起,倒計(jì)時(shí)30秒后則是做AppEnd和敬。
這里有一個(gè)問題需要處理,由于Android是一個(gè)多進(jìn)程的實(shí)現(xiàn)邏輯戏阅,如果一個(gè)程序有多進(jìn)程的實(shí)現(xiàn)邏輯昼弟,如果另一個(gè)進(jìn)程依然在工作,則不能執(zhí)行AppEnd的事件統(tǒng)計(jì)奕筐。一個(gè)進(jìn)程怎么知道另一個(gè)進(jìn)程是否在執(zhí)行任務(wù)舱痘?可以用ContentProvider+SQLite+ContentObserver。
源碼:https://github.com/wangzhzh/AutoTrackAppStartAppEnd
三离赫、AppClick事件監(jiān)控
控件的點(diǎn)擊事件記錄是最麻煩的芭逝,實(shí)現(xiàn)方案有好幾種。
1渊胸、代理ClickListener方式
源碼:https://github.com/wangzhzh/AutoTrackAppClick1
2旬盯、代理Window.Callback
源碼:https://github.com/wangzhzh/AutoTrackAppClick2
3、4翎猛、代理View.AccessibilityDelegate胖翰、 透明層
源碼:https://github.com/wangzhzh/AutoTrackAppClick3
源碼:https://github.com/wangzhzh/AutoTrackAppClick4
以上方式或多或少都有各自的問題,要么用了反射切厘,影響性能萨咳,要么用了新api的方法,對舊系統(tǒng)不兼容迂卢。強(qiáng)伯癥的人會糾結(jié)的要死某弦。
5桐汤、AspectJ
AOP,即面向切面編程靶壮。在Spring框架上已經(jīng)存在很長時(shí)間了怔毛。
AspectJ,是一個(gè)基于AOP思想來實(shí)現(xiàn)的一個(gè)框架腾降,它能提供ajc編譯器拣度,將配置好的內(nèi)容在編譯階段寫進(jìn)源代碼中,以實(shí)現(xiàn)“織入”的操作螃壤。
要使用AspectJ框架有2種方式
1抗果、直接在Gradle腳本編寫配置信息
源碼:https://github.com/wangzhzh/AutoTrackAspectJProject1
2、通過Gradle Plugin插件的形式奸晴,配置AspectJ框架
源碼:https://github.com/wangzhzh/AutoTrackAspectJProject2
這里介紹了如何使用Gradle Extentions來擴(kuò)展Gradle配置腳本冤馏。
用AspectJ框架實(shí)現(xiàn)埋點(diǎn)監(jiān)控
源碼:https://github.com/wangzhzh/AutoTrackAppClick5
PS:call與execution的區(qū)別
call
ViewOnClickListenerAspectj.aspectOf().aopTestMethod();
this.myTestMethod();
execution
pulic void myTestMethod() {
ViewOnClickListenerAspectj.aspectOf().aopTestMethod();
// TO-DO
}
AspectJ框架有缺點(diǎn):
1、無法織入第三方庫
2寄啼、無法兼容Lambda語法
3逮光、有兼容性問題,D8墩划、Gradle4.X
6涕刚、ASM
Android應(yīng)用程序的打包流程有需要的自行查閱。Goodle提供了Transform API乙帮,用于.class文件打包成.dex文件之前實(shí)現(xiàn)想要的操作杜漠。ASM是Java字節(jié)碼操作和分析框架,可以通過ASM實(shí)現(xiàn)動態(tài)改變類或增強(qiáng)既有類的功能察净。如驾茴,在click方法后增加埋點(diǎn)記錄邏輯。
Gradle Transform操作例子:
源碼:https://github.com/wangzhzh/AutoTrackTransformProject
這里的實(shí)現(xiàn)是每次都是清除舊的構(gòu)建記錄塞绿,再新生成編譯后的代碼沟涨。
ASM核心類:ClassReader、ClassVisitor异吻、AdviceAdapter
ClassVisitor會遍歷類中的所有成員裹赴。
用ASM框架實(shí)現(xiàn)埋點(diǎn)監(jiān)控
源碼:https://github.com/wangzhzh/AutoTrackAppClick6
核心代碼:
Method visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
···
onMethodExit(int opcode) {
if ((mInterfaces != null && mInterfaces.length > 0) || isSensorsDataTrackViewOnClickAnnotation) {
if ((mInterfaces.contains('android/view/View$OnClickListener') && nameDesc == 'onClick(Landroid/view/View;)V') ||
desc == '(Landroid/view/View;)V') {
methodVisitor.visitVarInsn(ALOAD, 1)
methodVisitor.visitMethodInsn(INVOKESTATIC, SDK_API_CLASS, "trackViewOnClick", "(Landroid/view/View;)V", false)
}
}
···
}
ALOAD、ILOAD區(qū)別
ALOAD:指加載對象類型的參數(shù)诀浪,如 UserEntity
ILOAD:指加載基礎(chǔ)類型的參數(shù)棋返,如 int、long雷猪、boolean等
7睛竣、8 Javassist、AST
這兩種方式不太好理解求摇,自行查閱相關(guān)代碼射沟。
源碼:https://github.com/wangzhzh/AutoTrackAppClick7
源碼:https://github.com/wangzhzh/AutoTrackAppClick8
綜上所述殊者,最完美的解決方案是ASM,不用反射验夯,沒有兼容性問題猖吴,語法又清晰。最終確定用ASM方式進(jìn)行埋點(diǎn)數(shù)據(jù)記錄挥转。另外涉及到數(shù)據(jù)保存海蔽、清理、上報(bào)的邏輯绑谣,用Google的room進(jìn)行數(shù)據(jù)保存党窜,定期清理已上報(bào)的數(shù)據(jù),上報(bào)網(wǎng)絡(luò)組件是基本的Http請求借宵。公司項(xiàng)目暫不開源幌衣,謝謝!