Tracking User Activities via React Navigation in React Native

09 Januari 2023 - Abdul Fattah Ikhsan

Bagikan:

NOTE 18 MARET 2023:

Daftar Isi:

Masalah

Ketika Kita buat aplikasi mobile dan mulai kompleks dengan banyaknya tampilan atau halaman. Maka, Kita perlu tahu halaman apa sih yang sering dikunjungi oleh pengguna aplikasi kita. Dari situ kita bisa jadikan data statistik yang bisa diolah kedepannya nanti selain trafik unduhan. Jika Kita terbiasa di web analytic tools pasti tau kita bisa lihat pengunjung di web Kita mengunjungi halaman apa saja, misalnya lewat google search console. Nah gimana dengan aplikasi mobile. Ok, Stay tuned!

Solusi

Kita perlu buat secara manual namun tidak sepenuhnya manual, hanya perlu buat mekanisme tracking via render props dari react navigation. Selanjutnya, kita simpan ke backend kita sendiri atau menggunakan analytic tool semisal appcenter analytics atau firebase analytics. Ada 2 render props react-navigation yang kita gunakan untuk implementasi ini, yaitu onReady dan onStateChange . Ok, lanjut ke implementasi.

Implementasi

Note: kita akan menggunakan react-navigation v6 dan appcenter-analytics v4 dan obviously menggunakan TypeScript 👍.

Pertama, Kita buat semacam helper module khusus untuk navigation di aplikasi. katakanlah NavigationHelper.ts .

import {
  createNavigationContainerRef,
  InitialState,
  NavigationState,
  PartialState,
  Route,
} from '@react-navigation/native';

export const navigationRef = createNavigationContainerRef();

type MaybeActiveRoute = (Omit<Route<string>, 'key'> & {key?: string; state?: InitialState}) | undefined;
// Gets the current screen from navigation state
export const getActiveRoute = (
  state: NavigationState | PartialState<NavigationState> | undefined,
): MaybeActiveRoute => {
  // @ts-ignore
  const route: MaybeActiveRoute = state?.routes[state?.index];

  if (route?.state) {
    // Dive into nested navigators
    return getActiveRoute(route.state);
  }

  return route;
};
export const getActiveRouteName = (state: NavigationState | undefined) => getActiveRoute(state)?.name;
export const getActiveRouteParams = (state: NavigationState | undefined) => getActiveRoute(state)?.params;
export const getPreviousRoute = (state: NavigationState | undefined) => getActiveRoute(state)?.state?.history;
export function omitDeep(props: {[key: string]: any}, keys: string[]) {
  if (!props) {
    return props;
  }
  let obj = {};
  for (let [key, val] of Object.entries(props)) {
    obj[key] = val;
    if (keys.includes(key)) {
      delete obj[key];
    } else if (typeof val === 'object' && val !== null && !Array.isArray(val)) {
      obj[key] = omitDeep(val, keys);
    }
  }
  return obj;
}

Kode khusus tracking terdiri dari 4 function:

  1. getActiveRoute , mencari route state react navigation secara recursive, function ini adalah main logic dari function lainnya.
  2. getActiveRouteName , mengambil spesifik nama route state.
  3. getActiveRouteParams , mengambil spesifik params route state.
  4. getPreviousRoute , mengambil spesifik routes sebelumnya dalam bentuk list atau array.

Selanjutnya, Kita buat file Router.tsx sebagai root navigation kita dan kita implementasikan kode diatas disini.

import {NavigationContainer} from '@react-navigation/native';
import Analytics from 'appcenter-analytics';
import {getActiveRouteName, getActiveRouteParams, navigationRef, omitDeep} from './NavigationHelper';

const omittedKeys = ['password', 'phoneNumber'];

export default function Router() {
  const routeNameRef = React.useRef<string | undefined>('');
  const routeParamRef = React.useRef<{[key: string]: any} | undefined>({});
  const onReady = () => {
    if (navigationRef.isReady()) {
      let navState = navigationRef.getRootState();
      routeNameRef.current = getActiveRouteName(navState);
      routeParamRef.current = getActiveRouteParams(navState);
      // other codes if you like
    }
  };

  return (
    <NavigationContainer
        ref={navigationRef}
        onReady={onReady}
        onStateChange={(navState) => {
          const previousRouteName = routeNameRef.current;
          const previousRouteParams = routeParamRef.current;
          const currentRouteName = getActiveRouteName(navState);
          const currentRouteParams = getActiveRouteParams(navState);
          if (previousRouteName !== currentRouteName) {
            // if (!__DEV__) { // uncomment this when you only need tracking in release build
              Analytics.trackEvent('Navigation Change', {
                screen: currentRouteName ?? 'Root',
                params: currentRouteParams ? JSON.stringify(omitDeep(currentRouteParams, omittedKeys)) : '',
              });
            }
          // } // uncomment this when you only need tracking in release build
          routeNameRef.current = currentRouteName;
          routeParamRef.current = currentRouteParams;
        }}
      >
        <Navigator />
      </NavigationContainer>
  );
}

Note: <Navigator /> disini adalah Component yang mengimplementasi Stack Navigator dan tidak perlu saya tulis disini.

Mari kita fokus di bagian onReady dan onStateChange , onReady hanya jalan sekali saat pertama kali NavigationContainer mounted. Kita lakukan inisiasi route yang aktif pertama. Selanjutnya, onStateChange akan jalan setiap kali pengguna pindah-pindah halaman atau screens, disini ada pengecekan jika route sebelumnya tidak sama dengan route yang baru saja dicek maka dipastikan itu route yang baru. Kemudian Kita simpan ke Appcenter Analytics sekaligus data params. Terakhir, pastikan untuk properti data params yang kita masukkan tidak ada data yang sensitif seperti password atau phone number.

Penutup

Saya mau menambahkan sebelum saya tutup, bahwa di iOS itu strict untuk masalah analytics dan tracking maka Kita perlu implementasi app tracking transparency. Untungnya, sudah ada yang buat pustakanya yaitu react-native-tracking-transparency . Cek sendiri di google atau di ChatGPT 🔍.

Saya rasa cukup, terima kasih atas kesediannya untuk membaca tulisan Saya. Semoga bermanfaat dan apabila bermanfaat, jangan lupa untuk share ke teman-teman developer yang lain. jika ada feedback atau mau kolaborasi jadi guest author di lanjutkoding.com bisa langsung kontak saya di https://t.me/ikhsaan

#react-native
© 2021 - 2023 lanjutkoding.com