22
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Livesense - 関Advent Calendar 2017

Day 11

Androidのalibaba製UIイベントトラッキングライブラリを読む

Last updated at Posted at 2017-12-10

はじめに

サービスを成長させていく中で、機能がどんどん増えていってアプリでできることが多すぎる!なんてことはありませんか?
でも、一度追加した機能はアプリ自体のコードだけでなく、ユーザにもわっていて、無暗に削除することは難しいですよね。
また、機能は開発側の意図しない使われ方をすることも多くあると思います。

そこで、数値ベースで機能の使われ方を調べるために、ユーザの行動トラッキングで良い方法を模索しています。
UIイベントにおいて、10月末にversion 1.0.0がリリースされたalibaba製のライブラリViewTracker-Androidがサンプルを動かしてみた所、良さげでした。
しかし、まだリリースされてから日が浅い + :star:数も多くありません。
ただ、star数が少ないからと言って信頼性がないというのは、なんとも悲しいことなので、ライブラリのコードはどうなっているのか読んでみることにしました。
中国のECアプリ T-mall(天猫)のプロダクション環境で、2016年3月から利用されているようです。

公式サンプル

demo.gif

Viewに対して、view.setTag(TrackerConstants.VIEW_TAG_UNIQUE_NAME, viewName);のように、TrackerConstants.VIEW_TAG_UNIQUE_NAMEというタグにユニークな文字列を設定するだけで、
クリック,Viewが露出されていた時間を検出し、自動的にログを採ることができます。
また、ページ or View単位で、任意の値をHashMapで設定することができます。

ライブラリの処理を読み解く

利用する側から見る :eyes:

ライブラリを利用するためにApplicationクラス内でトラッキング用クラスのTrackerManagerを初期化します。

TrackerManager.getInstance().setCommit(new DemoDataCommitImpl());
TrackerManager.getInstance().init(this, true, true, true);

まず、DemoDataCommitImplのインスタンスを生成しセットしています。
DemoDataCommitImplinterface IDataCommitを実装したクラスで、クリック,Viewが露出されていた時間を検出した時の値を受け取り、サーバへログを送信するなど任意の処理を行うことができます。

どのようにしてトラッキングしているのか :thinking:

トラッキングするためのクラスとして、主に4つのクラスが登場します。

  • トラッキング処理の全体を管理、ライブラリ利用側からのインターフェースとなるTrackerManager
  • 主なトラッキング処理の起点となるTrackerFrameLayout
  • クリックトラッキングを管理するClickManager
  • Viewの露出トラッキングを管理するExposureManager

TrackerManager

TrackerManager.getInstance().init(...)が呼ばれると、Applicationクラスに対してActivityLifecycleCallbacksを実装したActivityLifecycleForTrackerが登録されます。

ActivityLifecycleForTrackerはActivityがonResume,onPauseされる時に、TrackerFrameLayoutattach,detach処理を行います。

TrackerFrameLayout

attach

  1. ActivityのルートとなるView(id: android.R.id.content)を取得する。
  2. ActivityをContextとしてTrackerFrameLayoutを生成する。
  3. View(id: android.R.id.content)の子Viewを、取得・削除しながら、全ての子Viewを 2. で生成したTrackerFrameLayoutへ移し替える。
  4. TrackerFrameLayoutをルートのViewとして、View(id: android.R.id.content)へ追加する。

つまり、既存のViewを全てトラッキング用のViewの子Viewへと移行して、トラッキングを行っています。

detach

  1. attach時に追加したTrackerFrameLayoutを削除する。

のみです。Activityのdestroy時に呼び出されるため、移し替えたViewを戻す必要はありません。

ClickManager(TrackerFrameLayoutでのクリックトラッキング)

  1. View.dispatchTouchEventのイベントがMotionEvent.ACTION_DOWNの時に処理が行われる。
  2. ClickManager.getInstance().eventAspect(...)によって、
    タップした座標に存在するかつtagTrackerConstants.VIEW_TAG_UNIQUE_NAMEが設定されている一番子供のViewに、View.AccessibilityDelegateを継承したViewDelegateを登録する。
  3. ユーザのアクションにより、登録したViewDelegatesendAccessibilityEventが呼び出される。
  4. 発生したイベントがAccessibilityEvent.TYPE_VIEW_CLICKEDだった時に
    DataProcess.processClickParams(...)を経由し、初期化時にTrackerManager.getInstance().setCommit(...)したIDataCommit.commitClickEventが呼び出される。

ExposureManager(TrackerFrameLayoutでのView露出トラッキング)

  1. ClickManagerの時と違い、Viewに変更が入る様々なタイミングで処理が行われる。
  • View.dispatchTouchEventのイベントがMotionEvent.ACTION_DOWN
  • GestureDetector.OnGestureListener.onFling(フリック処理が呼び出された1秒後)
  • View.dispatchWindowFocusChanged
  • View.dispatchVisibilityChanged
  1. ExposureManager.getInstance().triggerViewCalculate(...)によって、
    ExposureManager.traverseViewTree(...)tagTrackerConstants.VIEW_TAG_UNIQUE_NAMEが設定されている自身と子要素全てを、現在表示されているViewの一覧としてHashMapに登録する。
  2. 前回表示されていたViewの一覧の中で現在表示されているViewの一覧に存在しないViewだった時に、
    new HandlerThread("ViewTracker_exposure")で動作しているHandlerを介して、
    DataProcess.commitExposureParams(...)を経由し、初期化時にTrackerManager.getInstance().setCommit(...)したIDataCommit.commitExposureEventが呼び出される。

また、ViewPagerは他のViewに比べて特殊な構造をしているため、View.onLayout時にExposureManager.getInstance().traverseViewTree(...)によって、ReuseLayoutHookというViewPager用のトラッキング処理を発火させるためのインスタンスを設定しています。

さいごに

クラスの継承なども必要なく、他との依存が殆どないので、良さげだと思いました。 :thumbsup:
View.AccessibilityDelegateを利用することで、既存の処理に影響を与えないようにしていて、全く自分の考えになかったので驚きました。

デメリットとしては、必ずViewの階層が1つ深くなるViewのクリック・表示非表示の判定は、View自身がそのようなメソッドを持っていないので自力で計算しているということです。
UIトラッキングライブラリなのに、公式ページにライブラリを仕様した際のFPS比較が載っている理由が、コードを読んでみてわかりました。
FPS比較の結果は、影響がないと同等のようです。

画面遷移のトラッキングはできないですが、イベントのトラッキングは十分に機能があって
既にプロダクション環境で利用されていることもあり、導入しても問題なさそうだと感じています。:ok_woman:

22
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?