Androidオートメーション埋め込み技術探索-1

9848 ワード

前言:
前の文章は主に埋点の基本的な概念といくつかの埋点技術の実現方式の原理と違いを紹介し、本文章は自動化埋点技術の探索の第1編であり、主にページ閲覧事件、APPがフロントにあるのか、バックグラウンドにあるのかの2種類の事件が埋点技術の理論分析と実践を紹介した.
埋め込みなしテクノロジー-ページブラウズイベントの処理
AppViewScreenイベント、すなわちページブラウズイベント.Androidでは、ページブラウズとは、実は異なるActivityを切り替えることです.ライフサイクルはActivityにとって非常に意味があります.それはライフサイクルとは何ですか.ライフサイクルは「ゆりかごから墓まで」(Cradle-to-Grave)の全過程と通俗的に理解されている.Activityのライフサイクルを知ることで、ページのブラウズイベントとは、ActivityのonResume()のことを指します.ActivityがonResume()を実行すると、フロントに表示されてアクティビティが開始されたことを示すため、ページの閲覧イベントをどのように傍受しますか?埋め込みポイントはクリック可能なイベントに基づいて内部ロジックを実行するため、現在実行中のActivityを最初に見つけてから後続の操作を行うことができます.
質問:
Activityのすべてのライフサイクルイベントを集中的に処理(またはリスニング)できる案はありますか?
解決方法:
Activity LifecycleCallbacksは、API 14から提供されるアプリケーションの内部インタフェースである.Applicationはこのインタフェースを通じて、開発者がActivityのすべてのライフサイクルイベントを集中的に処理できるようにするコールバック方法を提供しています.まず、Activity LifecycleCallbackの内部ソースコードを見てみましょう.
public interface ActivityLifecycleCallbacks {
    void onActivityCreated(Activity activity, Bundle savedInstanceState);
    void onActivityStarted(Activity activity);
    void onActivityResumed(Activity activity);
    void onActivityPaused(Activity activity);
    void onActivityStopped(Activity activity);
    void onActivitySaveInstanceState(Activity activity, Bundle outState);
    void onActivityDestroyed(Activity activity);
}


Activity LifecycleCallbacksの簡単な使用は以下の通りです.
public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        this.registerActivityLifecycleCallbacks(new StuActivityLifecycle());
    }

    private class StuActivityLifecycle implements ActivityLifecycleCallbacks {

        @Override
        public void onActivityCreated(Activity activity, Bundle bundle) {

        }

        @Override
        public void onActivityStarted(Activity activity) {

        }

        @Override
        public void onActivityResumed(Activity activity) {

        }

        @Override
        public void onActivityPaused(Activity activity) {

        }

        @Override
        public void onActivityStopped(Activity activity) {

        }

        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {

        }

        @Override
        public void onActivityDestroyed(Activity activity) {
        }
    }

}


なぜActivityライフサイクルメソッドが呼び出されると、Application内部のActivity LifecycleCallbackに対応するメソッドがトリガーされるのかと聞かれるかもしれません.
問題を解決する最善の方法は、ActivityおよびApplicationのシステムソースコードを探索することです.たとえば、ActivityのonCreate()で、ソースコードを次に示します.
    @MainThread
    @CallSuper
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);

        if (mLastNonConfigurationInstances != null) {
            mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
        }
        if (mActivityInfo.parentActivityName != null) {
            if (mActionBar == null) {
                mEnableDefaultActionBarUp = true;
            } else {
                mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
            }
        }
        if (savedInstanceState != null) {
            mAutoFillResetNeeded = savedInstanceState.getBoolean(AUTOFILL_RESET_NEEDED, false);
            mLastAutofillId = savedInstanceState.getInt(LAST_AUTOFILL_ID,
                    View.LAST_APP_AUTOFILL_ID);

            if (mAutoFillResetNeeded) {
                getAutofillManager().onCreate(savedInstanceState);
            }

            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                    ? mLastNonConfigurationInstances.fragments : null);
        }
        mFragments.dispatchCreate();
        getApplication().dispatchActivityCreated(this, savedInstanceState);
        if (mVoiceInteractor != null) {
            mVoiceInteractor.attachActivity(this);
        }
        mRestoredFromBundle = savedInstanceState != null;
        mCalled = true;
    }


ここでは主にActivityとApplicationの関係を分析するため、getApplication()という行に素早くナビゲートする.dispatchActivityCreated(this, savedInstanceState); アプリケーションのdispatchActivity Createdメソッドが呼び出され、dispatchActivity Createdソースコードは次のようになります.
void dispatchActivityCreated(Activity activity, Bundle savedInstanceState) {
        Object[] callbacks = collectActivityLifecycleCallbacks();
        if (callbacks != null) {
            for (int i=0; i

ここにc o l l e c t Activity LifecycleCallbacks()が現れましたが、Application内部のc o l e c t Activity LifecycleCallbacksという方法は何をしているのか、ソースコードをポイントし続けます.
    private Object[] collectActivityLifecycleCallbacks() {
        Object[] callbacks = null;
        synchronized (mActivityLifecycleCallbacks) {
            if (mActivityLifecycleCallbacks.size() > 0) {
                callbacks = mActivityLifecycleCallbacks.toArray();
            }
        }
        return callbacks;
    }

従来,ここでは付与配列の操作を行い,同期コードブロックの操作を行ったが,同期コードブロックの目的は同時操作による異常を解決することである(すべてのActivityを傍受しているため).ソースコードに表示されるmActivity LifecycleCallbacksは、実際にはApplication内部で定義されているプライベートメンバー変数です.
private ArrayList mActivityLifecycleCallbacks =
            new ArrayList();

ArrayListはjava集合フレームワークでよく使われるデータ構造であることはよく知られています.AbstractListから継承され、Listインタフェースを実現します.下位層は配列に基づいて容量サイズの動的変化を実現しnullの存在を許容する.では、ここで定義したArrayListはどのようにして追加と削除されますか?
これはアプリケーションの内部のコードです.一目瞭然です.

public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
        synchronized (mActivityLifecycleCallbacks) {
            mActivityLifecycleCallbacks.add(callback);
        }
    }

    public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
        synchronized (mActivityLifecycleCallbacks) {
            mActivityLifecycleCallbacks.remove(callback);
        }
    }


以上のように、Activityのライフサイクル毎にActivity LifecycleCallbackインタフェースの1つのメソッドに対応するため、上述のonActivity CreatedコールバックはActivityのonCreateメソッドでgetApplication()を呼び出す.dispatchActivity Created(this,savedInstanceState)はActivityライフサイクルの追跡リスニングを完了します.また、Applicationもregisterの複数のActivity LifecycleCallbacksを使用できます.これもソースコードです.
特筆すべきは、Activity LifecycleCallbacksには次の機能があります.
  • 新規オープンプロセス偽再起動処理(低メモリ回収、修正権限)
  • を適用する.
  • Activityページスタック
  • の管理
  • 現在のActivityページ
  • を取得
  • 判定アプリケーションフロントバックグラウンド
  • リカバリステータス値savedInstanceState
  • を保存
  • ページ分析統計埋め込み点
  • ソリューション:
    では、ページブラウズイベントの埋め込みなしテクノロジーの実装については、次の手順に従います.
  • アプリケーションがカスタマイズしたアプリケーションオブジェクトのonCreate()メソッドで埋め込み点SDKを初期化し、現在のアプリケーションオブジェクトに転送します.
  • SDKがApplicationオブジェクトを取得する後、r e g i s t e r A c t i vityLifecycleCallbackメソッドでApplicationを登録する.ActivityLifecycleCall-backs.これにより、SDKは、App内のすべてのActivityのライフサイクルイベントを集中的に処理(監視)することができます.
  • に登録されているApplication.Activity LifecycleCallbackのonActivity Re-sumedコールバックメソッドでは、現在表示されているActivityオブジェクトを取得し、SDKの関連インタフェースを呼び出してページブラウズイベント
  • をトリガーすることができます.
    埋め込みなしテクノロジー-AppStart、AppEndイベントの処理
    AppStart、AppEndイベントとは、実際には現在のAppがフロントにあるかバックグラウンドにあるかを判断することです.Androidシステム自体は、これらの状態を判断するためにAppに関連するインタフェースを提供していない.
    質問:
    一般的に、現在のAppがフロントにあるかバックグラウンドにあるかを判断するには、まず2つの問題に直面しなければなりません.
  • Appは複数のプロセスをどのように判断しますか?
  • Appが崩壊したり、強殺されたりしたらどう判断しますか?

  • 解決方法:
    ContentProvider(コンテンツプロバイダ)はAndroidの4つのコンポーネントの1つであり、プロセス間でデータの相互作用&共有、すなわちプロセス間通信を行うことが主な役割を果たしています.ContentProviderの下位層はBinderメカニズムを採用し,Binderメカニズムに設計する役割は前述したようにプロセス間のデータ共有問題の解決である.また、AndroidシステムはContentProviderのデータコールバックリスニング、すなわちContentObserverを提供しており、このような設計は、プロセス間のデータ通信をより完備させる.
    Appがクラッシュしたり、アプリケーションが強制的に殺されたりするシーンについて、神策データ技術チームが与えた解決策はSessionの概念を導入することである.注意:このSessionは他のSessionではありません.Sessionの公式概念については、筆者のもう一つの文章を参考にすることができます.Cookie、Session、Tokenの神策データチームは、Appについて、1つのページが終了すると、30 s以内に新しいページを開かなければ、Appがバックグラウンドにあると認識しています.1つのページが表示状態にある場合、前のページからの終了時間の間隔が30 sを超えると、Appは再びフロントにあると考えられます.
    神策データ技術チームのこのようなタイムスタンプで判断を計算する方式では、多くの場合のデータ収集を解決することができるが、個別に収集できない場合があり、具体的な原因は30 sの設定である.反例を挙げると、25 s、35 s、40 sを設定すれば採集がより正確になるのではないでしょうか.ページの内容の違い、ユーザーの客観的な条件(ハードウェア、知識アーキテクチャ、脳感度)の違いなど、より科学的に実現できる方法の一つは、内容の違いに対して、異なる設定時間を動的に下げることです.もちろん、これは私個人の考えです.もう1つの可能性は、30 sの設定が、大量のユーザ行動を統計し、データ判断計算を行った後に得られる算術平均値であり、30 sは他の値よりも良い設定である可能性がある.
    ソリューション:
    以上、Appがフロントにあるかバックグラウンドにあるかのイベントが埋め込まれていない技術で実現されるには、以下の手順があります.
  • まずActivity LifecycleCallbacksコールバックを登録し、アプリケーション内のすべてのActivityのライフサイクルをリスニングします.業務を処理する際にタグビットの保存及びスパン間のデータ通信に関し、ContentProvider+SharedPreferences方式でプロセス間のデータ共有を実現するとともに、ContentObserverを登録してスパン間のデータ通信を傍受する.
  • ページが終了するとonPause()となり、カウントダウン30 sタイマを起動し、30 s以内に新しいページが表示されなければAppEndイベントをトリガーする.新しいページが入ってきたら、新しいページをマークするタグビットを格納します.なお、Activity間はプロセス間である可能性があるため、タグビットはプロセス間の共有、すなわちContentProvider+SharedPreferencesによる記憶を実現する必要がある.
  • は次に、ContentObserverを介して新しいページに入ってきたタグビットの変更を傍受し、タイマをキャンセルする.30 s以内に新しいページが入ってこない場合(ユーザーがホームキー/戻りキーを押してAppを終了し、Appがクラッシュし、Appが強殺された場合など)、次回起動時にAppEndイベントを再発行します.

  • バックグラウンドでの埋め込み処理について話しました.フロントでの埋め込み処理について話しています.
  • ページ起動時であるonStart()は、まず、前ページとの終了時間間隔が30 sを超えているか否かを論理的に判断し、30 sを超えていなければAppEndイベントを再発行することなく、AppScreen(ページブラウズ)イベントを直接トリガーする.次に、AppEndイベントのタグビットがトリガーされたかどうかを判断し、タグビットがtrueの場合、AppStartイベントがトリガーされ、逆にトリガーされない.30 sを超えると、論理的にAppEndイベントがトリガーされたかどうかを判断し、そうでない場合はAppEndイベントをトリガーしてからAppStartイベントとAppScreenイベントをトリガーします.

  • 文章の一部の内容は:神策データユーザー行為洞察研究院「安卓全埋点技術白書」から選ばれ、技術の共有に感謝している.
    もしこの文章があなたに開発or学習上の少しの助けがあれば、各位の見官が貴重なstarを残しておくことを望んで、ありがとうございます.
    Ps:著作権は作者の所有で、転載は作者を明記してください.商業転載は作者に連絡して授権を得てください.非商業転載は出典(冒頭または末尾に転載出典を追加してください.原文urlアドレスを追加してください)を明記してください.文章は乱用しないでください.筆者の労働の成果を尊重してください.