成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Android埋點(diǎn)系統(tǒng)設(shè)計(jì)

trigkit4 / 1024人閱讀

摘要:一埋點(diǎn)架構(gòu)設(shè)計(jì)埋點(diǎn)的核心邏輯抽象將生產(chǎn)的用戶數(shù)據(jù)組織發(fā)送給服務(wù)器。普通埋點(diǎn)定義頁(yè)面進(jìn)入,頁(yè)面離開,頁(yè)面元素點(diǎn)擊,頁(yè)面元素曝光。無(wú)埋點(diǎn)進(jìn)入退出都使用,如何區(qū)分增加了一個(gè)字段,用表示頁(yè)面進(jìn)入退出。如何修改字節(jié)碼庫(kù)基礎(chǔ)使用。

一、埋點(diǎn)架構(gòu)設(shè)計(jì)

埋點(diǎn)的核心邏輯抽象:將“APP生產(chǎn)”“用戶數(shù)據(jù)”組織“發(fā)送給服務(wù)器”

1.Producer是APP,生產(chǎn)各種用戶數(shù)據(jù)。
2.Consumer是埋點(diǎn)系統(tǒng)的數(shù)據(jù)上傳模塊,把各種用戶數(shù)據(jù)上傳給服務(wù)器。
3.MetaData是對(duì)用戶數(shù)據(jù)的抽象。
4.Queue是存儲(chǔ)用戶數(shù)據(jù)的隊(duì)列。

抽象邏輯分解為各個(gè)子模塊并拼裝,形成最終的架構(gòu)。

1.MetaData模塊:將用戶行為抽象為數(shù)據(jù)描述。
2.Producers模塊:生產(chǎn)用戶數(shù)據(jù),將用戶行為轉(zhuǎn)化為數(shù)據(jù)集。
3.Consumers模塊:消費(fèi)用戶數(shù)據(jù),將用戶數(shù)據(jù)上傳給服務(wù)器。
4.Storage模塊:存儲(chǔ)用戶數(shù)據(jù),將用戶數(shù)據(jù)暫存在文件中。
5.Broker模塊:管理用戶數(shù)據(jù)。

二、MetaData模塊

關(guān)鍵是特征值的提取。
設(shè)備基礎(chǔ)屬性:
設(shè)備id:udid=12345678910
APP基礎(chǔ)屬性:
版本:v=8.5.0
渠道:c=xiaomi
用戶基礎(chǔ)屬性:
用戶id:ucid=12345678910
頁(yè)面元素描述:
屬于哪個(gè)APP:pid=bigc_app_xinfang
屬于哪個(gè)頁(yè)面:key=newhouse/homeindex
屬于哪個(gè)頁(yè)面元素:為頁(yè)面元素定義唯一的code
頁(yè)面與頁(yè)面關(guān)聯(lián)邏輯:
從哪個(gè)頁(yè)面進(jìn)入當(dāng)前頁(yè)面:f=newhouse/homeindex
頁(yè)面停留時(shí)間:stt=1000
用戶行為描述:
用戶基礎(chǔ)行為描述:evt=xxx,如APP啟動(dòng)/退出,頁(yè)面進(jìn)入/離開/滑動(dòng),頁(yè)面元素點(diǎn)擊/曝光,push到達(dá)/點(diǎn)擊
用戶擴(kuò)展行為描述:action=json,如action={"project_name":"thyhwabktj", "xinfangapp_click":"10020"}
舉例:
{v=1.1.6, ts=1527067845806, ucid=null, ssid=b032222c-7105-4119-9bfe-a1aec5ba9285, pid=bigc_app_xinfang, key=newhouse/project, action={"sample_mark":"","project_name":"thyhwabktj"}, longitude=0.0, latitude=0.0, cid=110000, f=newhouse/homeindex?project_name=thyhwabktj&city_id=110000, stt=685, evt=2}

LJ由于歷史原因,有兩套MetaData
無(wú)埋點(diǎn)evt定義:app啟動(dòng)/退出=5,頁(yè)面進(jìn)入/退出=6,頁(yè)面滑動(dòng)=8,頁(yè)面元素點(diǎn)擊=7,push到達(dá)/點(diǎn)擊=9。
普通埋點(diǎn)evt定義:頁(yè)面進(jìn)入=1,3,頁(yè)面離開=2,頁(yè)面元素點(diǎn)擊=10186,頁(yè)面元素曝光=11316。
Q:無(wú)埋點(diǎn)進(jìn)入/退出都使用6,如何區(qū)分?
A:增加了一個(gè)status字段,用status=0/1表示頁(yè)面進(jìn)入/退出。
建議:統(tǒng)一dig埋點(diǎn)和無(wú)埋點(diǎn)的evt定義

三、Storage模塊

1.內(nèi)存緩存(List):每生產(chǎn)一條數(shù)據(jù)都會(huì)先進(jìn)入內(nèi)存緩存
2.數(shù)據(jù)庫(kù)存儲(chǔ)(DataBase):提供對(duì)數(shù)據(jù)庫(kù)的操作接口

四、Broker模塊

1.接收生產(chǎn)者的數(shù)據(jù),并寫入數(shù)據(jù)庫(kù)(對(duì)外提供put方法)
Q:如何控制數(shù)據(jù)由內(nèi)存寫入數(shù)據(jù)庫(kù)時(shí)機(jī)?
1.1.內(nèi)存數(shù)據(jù)超過(guò)一定數(shù)量(如20條)時(shí),缺點(diǎn)是應(yīng)用在后臺(tái)被殺,最多可能丟失20條數(shù)據(jù)
1.2.生命周期onPause時(shí),缺點(diǎn)是寫操作相對(duì)比較頻繁
1.3.利用定時(shí)器,缺點(diǎn)是后臺(tái)定時(shí)任務(wù)可能不執(zhí)行,導(dǎo)致丟數(shù)據(jù)
LJ現(xiàn)行方案:1.1+1.3
建議使用:1.1+1.2
Q:多進(jìn)程寫數(shù)據(jù)庫(kù)怎么辦?
A:多進(jìn)程向sqlite插入數(shù)據(jù)不會(huì)有問(wèn)題,只是插入順序是亂序的;如果要保證插入順序也一致,可以考慮啟動(dòng)一個(gè)獨(dú)立進(jìn)程操作sqlite,其它進(jìn)程與sqlite所在進(jìn)程進(jìn)行通信。

2.讀取數(shù)據(jù)庫(kù)中的數(shù)據(jù),并供給消費(fèi)者消費(fèi)(對(duì)外提供aquire/release方法)
Q:如何控制數(shù)據(jù)提供給消費(fèi)者消費(fèi)的時(shí)機(jī)?
A:生命周期onPause時(shí),缺點(diǎn)是消費(fèi)相對(duì)比較頻繁

五、Consumers模塊

申請(qǐng)(aquire)數(shù)據(jù),消費(fèi)(upload)數(shù)據(jù),釋放(release)數(shù)據(jù)
建議:LJ目前的代碼可以參考此設(shè)計(jì)進(jìn)行代碼優(yōu)化

六、Producers模塊

普通埋點(diǎn)數(shù)據(jù)生產(chǎn)
Producers模塊對(duì)外提供各種封裝好的add方法供開發(fā)者調(diào)用,如addClickEvent(), addPageEnterEvent(), addPageLeaveEvent()等。

無(wú)埋點(diǎn)數(shù)據(jù)生產(chǎn)
Producers模塊自動(dòng)生產(chǎn)各種埋點(diǎn)數(shù)據(jù),如app啟動(dòng)/退出,頁(yè)面進(jìn)入/退出/滑動(dòng),頁(yè)面元素點(diǎn)擊,push到達(dá)/點(diǎn)擊等。

七、LJ現(xiàn)有埋點(diǎn)庫(kù)

由于歷史原因,LJ總共有2個(gè)埋點(diǎn)庫(kù):
dig庫(kù):LJ-APP&BK-APP均在使用,用于對(duì)無(wú)埋點(diǎn)無(wú)法處理的特殊數(shù)據(jù)進(jìn)行補(bǔ)充
無(wú)埋點(diǎn)庫(kù):LJ-APP用的老版本(pid無(wú)法自定義,主工程和插件共用主工程的pid),BK-APP用的新版本(pid可以自定義,主工程和插件工程可以分別定義自己的pid)
建議:兩庫(kù)合并

八、無(wú)埋點(diǎn)實(shí)現(xiàn)原理

無(wú)埋點(diǎn)的核心是,如何通過(guò)代碼自動(dòng)搜集想要的信息:
1.設(shè)備、APP、用戶等基礎(chǔ)屬性,直接通過(guò)api獲取
2.Activity進(jìn)入/離開等生命周期相關(guān)屬性,直接通過(guò)LifeCycleCallback監(jiān)聽獲取
3.Activity的唯一標(biāo)記如pageId等屬性,直接通過(guò)注解獲取
4.UI元素點(diǎn)擊/滑動(dòng)等行為屬性,需要通過(guò)hook代碼才能實(shí)現(xiàn)

如何確定UI元素的唯一性:
方案1:為需要統(tǒng)計(jì)的元素定義唯一的code,寫入contentDescription,然后讀取這個(gè)屬性
方案2:利用ViewTree中的ViewPath唯一確定一個(gè)UI元素

核心代碼:

public static ViewPath getPath(View view) {
    do {
      //1.構(gòu)造ViewPath中于view對(duì)應(yīng)的節(jié)點(diǎn):ViewType[index]
      ViewType = view.getClass().getSimpleName();
      index = view在兄弟節(jié)點(diǎn)中的index;
      ViewPath節(jié)點(diǎn) = ViewType[index];
    } while ((view = view.getParent()) instanceof View);//2.將view指向上一級(jí)的節(jié)點(diǎn)
  }

結(jié)果示例:

DecorView/LinearLayout[0]/FrameLayout[0]/ActionBarOverlayLayout[0]/ContentFrameLayout[0]/FrameLayout[0]/LinearLayout[0]/ViewPager[0]/ButtonFragment[0]/AppCompatButton[0]

ViewPath可讀性問(wèn)題:
可以建立一個(gè)Mapping文件,將ViewPath和描述Describe對(duì)應(yīng)起來(lái),具體實(shí)現(xiàn):
寫一個(gè)工具,當(dāng)我們?cè)谑謾C(jī)上點(diǎn)擊一個(gè)按鈕的時(shí)候彈出彈窗,輸入Describe描述文字,最終生成一個(gè)ViewPath<->Describe的Mappting文件。

九、注解基礎(chǔ)知識(shí)

1.元數(shù)據(jù)metadata與注解annotation
Java中總共有4種類型:類Class、接口Interface、枚舉Enum、元數(shù)據(jù)@interface(就是注解)。
元數(shù)據(jù):是添加到包、類、方法、屬性上的額外信息,對(duì)其進(jìn)行描述,如@Override。
元注解:是最基本的注解:@Target、@Retention、@Documented、@Inherited
@Target取值:PACKAGE、TYPE、FIELD、METHOD
@Retention取值:SOURCE、CLASS、RUNTIME
注解的作用:編譯時(shí)可獲取到注解信息動(dòng)態(tài)生成代碼,運(yùn)行時(shí)科獲取到注解信息做特殊處理。

2.運(yùn)行時(shí)注解
在運(yùn)行時(shí)通過(guò)反射對(duì)注解進(jìn)行處理,比較消耗資源,性能較差。

定義:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface MethodInfo {
?
????String author() default "xiaoming";
?
????String date();
?
????int version() default 1;
}

使用:

public class App {
?
????@MethodInfo(
????????author = “[email protected]”,
????????date = "2018/05/10",
????????version = 2)
????public String getAppName() {
????????return "trinea";
????}
}

解析:

Class cls = Class.forName("com.lianjia.test.annotation.App");
for (Method method : cls.getMethods()) {
    MethodInfo methodInfo = method.getAnnotation(MethodInfo.class);
    System.out.println(“method author: ” + methodInfo.author());
}    

3.編譯時(shí)注解
在編譯時(shí)通過(guò)Java Annotation Process技術(shù)對(duì)注解進(jìn)行處理,因?yàn)椴皇褂梅瓷?,所以性能較好

模擬ButterKnife定義:

@Retention(CLASS) 
@Target(FIELD)
public @interface InjectView {
??int value();
}

模擬ButterKnife調(diào)用:

@InjectView(R.id.user) 
EditText username;

模擬ButterKnife處理:

@SupportedAnnotationTypes({"com.lianjia.InjectView "})
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class MyProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set annotations, RoundEnvironment roundEnv) {
        for (TypeElement typeElement : annotations) {    // 遍歷annotations獲取annotation類型
            for (Element element : roundEnv.getElementsAnnotatedWith(typeElement)) {    // 使用roundEnv.getElementsAnnotatedWith獲取所有被某一類型注解標(biāo)注的元素,依次遍歷
                // 在元素上調(diào)用接口獲取注解值
                int annoValue = element.getAnnotation(TestAnnotation.class).value();
                String annoWhat = element.getAnnotation(TestAnnotation.class).what();

                System.out.println("value = " + annoValue);
                System.out.println("what = " + annoWhat);

                // 向當(dāng)前環(huán)境輸出warning信息
                processingEnv.getMessager().printMessage(Kind.WARNING, "value = " + annoValue + ", what = " + annoWhat, element);
            }
        }
        return false;
    }
}
十、Hook代碼實(shí)現(xiàn)搜集用戶點(diǎn)擊數(shù)據(jù)

1.Android編譯運(yùn)行全流程

2.在onClick(View view)方法中加入埋點(diǎn)邏輯
2.1.編寫埋點(diǎn)邏輯:由埋點(diǎn)sdk(LianjiaAnalyticsSdk)完成
2.2.將埋點(diǎn)邏輯插入onClick(View view)方法中:由埋點(diǎn)插件(LianjiaAnalyticsPlugin)完成

3.埋點(diǎn)插件編寫
1.插件編寫流程?plugin編寫。
2.如何侵入編譯流程?transform庫(kù)基礎(chǔ)使用。
4.如何修改字節(jié)碼?Javassist庫(kù)基礎(chǔ)使用。

4.核心代碼

編寫埋點(diǎn)邏輯:

public class AnalyticsEventsBridge {


  /**
   * Hook onClick(View view)方法,并調(diào)用此方法
   */
  public static void onViewClick(@Nullable View view) {
    // 獲取view的唯一標(biāo)記等相關(guān)信息
    // 生成一條埋點(diǎn)日志并寫入
  }
}

編寫插件:
1.插件項(xiàng)目目錄結(jié)構(gòu)

2.build.gradle修改

apply plugin: "groovy"

dependencies {
  compile gradleApi()

  compile "com.android.tools.build:gradle:2.3.3"
  compile "org.javassist:javassist:3.21.0-GA"
}

apply from: "./gradle-mvn-push.gradle"
apply plugin: "maven-publish"

publishing {
  publications {
    mavenJava(MavenPublication) {
      groupId PROJ_GROUP
      artifactId PROJ_ARTIFACTID
      version PROJ_VERSION
      from components.java
    }
  }
}

3.插件執(zhí)行入口,相當(dāng)于Main函數(shù)

class AnalyticsPlugin implements Plugin {

  @Override
  void apply(Project project) {
    InjectAndJarMergingTransform transform = new InjectAndJarMergingTransform()
    android.registerTransform(transform)
  }
}

transform侵入編譯流程:

public class InjectAndJarMergingTransform extends Transform {
  @Override public void transform(@NonNull TransformInvocation invocation)
      throws TransformException, IOException {
    println("LianjiaJarMergingTransform, begin");
    //這里可以獲取到文件的輸入/輸出信息,并對(duì)其做相應(yīng)的更改,核心抽象為1個(gè)方法
    processClass(inputStream, outputStream);
    println("LianjiaJarMergingTransform, end");
  }
}

Javassist修改字節(jié)碼:

  private void processClass(InputStream inputStream, OutputStream outputStream) throws IOException {
    final ClassPool classPool = AndroidClassPool.getClassPool()
    final CtClass clazz = classPool.makeClass(inputStream)
    final CtMethod ctMethod
    try {
      ctMethod = ctClass.getMethod(targetMethodName, targetMethodDescriptor);
    } catch (NotFoundException e) {
      xxxxxxxx
    }
    //通過(guò)過(guò)濾器,找到android.view.View$OnClickListener的onClick(View view)方法,略
    //Hook調(diào)用AnalyticsEventsBridge.onViewClick(view)方法
 ctMethod.insertBefore("""com.lianjia.sdk.analytics.gradle.AnalyticsEventsBridge.onViewClick($1);""")
    //其中$0=this, $1=$args[0]表示方法的第一個(gè)參數(shù)
}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69519.html

相關(guān)文章

  • Android 性能監(jiān)控系列一(原理篇)

    摘要:全稱應(yīng)用性能管理監(jiān)控后面我會(huì)通過(guò)一系列的文章來(lái)介紹的原理框架設(shè)計(jì)與實(shí)現(xiàn)等等。在應(yīng)用構(gòu)建期間,通過(guò)修改字節(jié)碼的方式來(lái)進(jìn)行字節(jié)碼插樁就是實(shí)現(xiàn)自動(dòng)化的方案之一。 showImg(https://segmentfault.com/img/bVbbRX6?w=1995&h=1273); 歡迎關(guān)注微信公眾號(hào):BaronTalk,獲取更多精彩好文! 一. 前言 性能問(wèn)題是導(dǎo)致 App 用戶流失的罪魁...

    yacheng 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<