秘密!高い正解率を設計する方法のフラッタフレームワークを埋没

著者:ビジー魚の技術 - Landhold

背景

埋もれたユーザーの行動は、一連の操作中にユーザーの行動を記録するために、だけでなく、欠落または不正確な回復不能な損失がビジネスにもたらすかどうかを判断するためにコアデータに基づいてビジネスを行うために使用されます。忙しい魚はフラッターシステムの上に適用することはできませんネイティブのポイントシステム上の元のプログラムに埋もれ見つかりネイティブフラッターを処理するために、ビジネスコードから移行します。私たちだけのビジネス機能は、ビジネスのラインに移行した場合、それは非常に無責任です。そのため、継続的な探査を通じて、我々はフラッター埋没プログラムのセットにユーザーの行動の高精度を沈殿させます。

ユーザー定義の振る舞い埋設

私たちはここにしようとするだろうポイントを埋めるユーザーの行動を定義する方法です。次のユーザーのタイムラインでは、ユーザーがページを入力し、ボタンXを参照して、このボタンをクリックすると、新しいページBを開いた後

このタイムラインに次の5つのポイントイベントを埋葬しました:

  • 入力するページ。最初のページフレームのレンダリングが完了し、フォーカスを持っています。
  • 露出ピット位置X. Xの携帯電話の画面でボタンを押すと、ユーザーが目に見える触れることができるように、いくつかの時間のために滞在。
  • ピット位置Xをクリック ユーザーは、それをクリックし、Xボタンの内容に興味を持っています。応答でXボタンをクリックし、新しいページを開く必要があります。
  • 左ページ。ページがフォーカスを失いました。
  • ページにB。最初のページB-フレームのレンダリングが完了し、フォーカス。

ここでは、埋もれた最も重要なことは、タイミングで遊んで、それがどの時点トリガでどのタイミングの下に埋もれイベント、以下の魚は、実装のフラッターに忙しい見て、です。

実装

入口/出口ページ

ネイティブネイティブ開発では、Androidは着信と発信のイベントのページを行うにはonResumeアクティビティモニタイベントとonPauseの終わりがあり、共感は着信と発信のイベントのページのために行うためにviewWillAppearとviewDidDisappearイベントののUIViewControllerのiOSの端を聞いています。同時に、ページ全体のスタックは、AndroidとiOSのオペレーティング・システムによって維持されています。

フラッターでは、AndroidとiOS FlutterActivity端はコンテナ船とFlutterViewControllerフラッタページを行うために使用され、このコンテナを通じてページ(FlutterActivity / FlutterViewController)でフラッターネイティブネイティブページを切り替えることができます。そのスタックは、フラッターフラッター自身のページのページを維持します。このように、我々は、フラッター直接一緒に動作しないのネイティブネイティブにオリジナルのプログラムの中で最も身近なセットです。

この問題に対処するために、多くの人々は、あなたがフラッタページ(プッシュ)、ポップ(ポップ)イベントを押す知っているので、NavigatorObserverフラッターを登録するには聞いて考えることがあります。しかし、それは2つの質問があります:

  • ( - >休暇 - > Bを入力してください入力)A、Bがスタックに2つのページを持っていると仮定します。Bページは再度、この時間はページ目に見える、出口(B休暇)を返すが、この時間は、イベントは、ページプッシュ(入力)A未満で受信されます。
  • 仮定すると、そのページにダイアログやBottomSheetをポップアップ表示し、操作のこれらの2つのタイプをプッシュして行くだろうが、実際にはページはありません。

最初の質問のために、私たちはインデックス付きのページやスタックマッチのリストを維持できるように、幸いなことに、フラッターページのページスタックは、Androidのネイティブとは異なり、非常に複雑スタック。イベントプッシュページを受信すると、インデックスのキューに詰め。あなたがプッシュイベントBのページを受信すると、ページ内で検出されたのリストがあり、そうであれば、リストの最後のページは、ページを残してイベントログを実行するために、その後、ページBのページを入力し、イベントログを行い、その後、キューBに詰めインデックス。ページBポップイベントを受信すると、ページBのうち最初のイベント・レコードは、ページ上で実行され、その後、最終的な指標は、(Aとする)ページキュースタックの最上部か決意(ModalRoute.of(コンテキスト)の存在に対応します.isCurrent
)、そうであれば、ページを入力するページでは、イベントログを行います。

第二の問題のために、ルートクラスのメンバ変数overlayEntriesがあり、ルートOverlayEntry電流に対応する全ての層を得ることができ、メンバ変数不透明層が存在する現在のフルスクリーンカバーOverlayEntryオブジェクトかどうかを決定することができるので、ダイアログを排除することができますBottomSheetこのタイプ。図1は、問題と組み合わせるが、ページには、上述した実施の形態では、有効なページを行うと判断されたかどうかも新しい着信プッシュを追加します。ページが有効であれば、インデックスにページを与える前に、ページイベントを離れる前に、リストを行うには、効果的にリストのインデックスページに追加されます。ページが有効でない場合、インデックスリストが動作していません。

上記は、忙しい魚のプログラム、作者によって与えられただけの提案ではありません。フロアフラッタフレームワークの冒頭に魚無料アプリなので、代わりにネイティブプログラムフラッター+の複合用途開発を使用してのフラッターネイティブは使用ページスタック管理方式は、ありません。具体的に以前の記事を参照してください「となっているオープンソース|フラッター複合用途開発を開始し、コードの上にそれを使用--FlutterBoost」したがって、以下は忙しい魚を説明するために、このシナリオに基づいています。

(アンドロイド、iOSの共感を持つ例えば)以下のように無料の魚のプログラム:

注意:あなたが最初に開いたときは、新しいページを開く混在スタックに基づいており指し、オープンによって、初めてではないが、フォールバック・ページを参照して、ページを再度表示フォアグラウンドにバックグラウンドで。

看似我们将何时去触发进入/离开页面事件的判断交给Flutter侧,实际上依然跟Native侧的页面栈管理保持了一致,将原先在Native侧做打埋点的时机告知Flutter侧,然后Flutter侧再立刻通过channel来调用Native侧的打埋点方法。那么可能会有人问,为什么这么绕,不全部交给Native侧去直接管理呢?交给Native侧去直接管理这样做针对非首次打开这个场景是合适的,但是对首次打开这个场景却是不合适的。因为在首次打开这个场景下,onResume时Flutter页面尚未初始化,此时还不知道页面信息,因此也就不知道进入了什么页面,所以需要在Flutter页面初始化(init)时再回过来调Native侧的进入页面埋点接口。为了避免开发人员去关注是否为首次打开Flutter页面,因此我们统一在Flutter侧来直接触发进入/离开页面事件。

曝光坑位

先讲下曝光坑位在我们这里的定义,我们认为图片和文本是有曝光意义的,其他用户看不见的是没有曝光意义的,在此之上,当一个坑位同时满足以下两点时才会被认为是一次有效曝光:

  • 坑位在屏幕可见区域中的面积大于等于坑位整体面积的一半。
  • 坑位在屏幕可见区域中停留超过500ms。

基于此定义,我们可以很快得出如下图所示的场景,在一个可以滚动的页面上有A、B、C、D共4个坑位。其中:

  • 坑位A已经滑出了屏幕可见区域,即invisible;
  • 坑位B即将向上从屏幕中可见区域滑出,即visible->invisible;
  • 坑位C还在屏幕中央可视区域内,即visible;
  • 坑位D即将滑入屏幕中可见区域,invisible->visible;

那么我们的问题就是如何算出坑位在屏幕内曝光面积的比例。要算出这个值,需要知道以下几个数值:

  • 容器相对屏幕的偏移量
  • 坑位相对容器的偏移量
  • 坑位的位置和宽高
  • 容器的位置和宽高

其中坑位和容器的宽和高很容易获取和计算,这里就不再累述。

获取容器相对屏幕的偏移量
//监听容器滚动,得到容器的偏移量
double _scrollContainerOffset = scrollNotification.metrics.pixels;
获取坑位相对容器的偏移量
//曝光坑位Widget的context
final RenderObject childRenderObject = context.findRenderObject();
final RenderAbstractViewport viewport = RenderAbstractViewport.of(childRenderObject);
if (viewport == null) {
  return;
}
if (!childRenderObject.attached) {
  return;
}
//曝光坑位在容器内的偏移量
final RevealedOffset offsetToRevealTop = viewport.getOffsetToReveal(childRenderObject, 0.0);
逻辑判断
if (当前坑位是invisible && 曝光比例 >= 0.5) {
  记录当前坑位是visible状态
  记录出现时间
} else if (当前坑位是visible && 曝光比例 < 0.5) {
  记录当前坑位是invisible状态
  if (当前时间-出现时间 > 500ms) {
    调用曝光埋点接口
  }
}

点击坑位

点击坑位埋点没什么难点,很容易就可以想到下面的方案:

效果

经过多轮迭代和优化,目前线上Flutter页面的埋点准确率已经达到100%,有力地支持了业务的分析和判断。同时这套方案让业务同学在做开发时,对于页面进入/离开、曝光坑位可以做到无感知,即不用关心何时去触发,做到了简单易用和无侵入性。

展望

此外,针对页面进入/离开这个场景,由于闲鱼是基于Flutter Boost混合栈的方案,因此我们的解决方案还不够通用。不过未来随着闲鱼上的Flutter页面越来越多,我们后续也会去实现基于Flutter原生的方案。

在闲鱼做数据驱动业务是一件非常重要且有意义事,而埋点直接影响着数据采集,埋点的丢失和错误将会让我们在大海上航行时失去灯塔的指引。在这里大家都习惯着用数据来指导工作方向,试验->取数据分析->调整实验->再取数据分析->再调整实验。如此循环着,只为找到最适合用户的那一个设计。如果你认可我们的工作方法论,欢迎加入闲鱼!

おすすめ

転載: yq.aliyun.com/articles/705175