57

In my android application, I have an Activity that has 3 or 4 fragments that can be attached in sequence based on some user or server events.

I would like to track all these fragments as screens in firebase.

So ideally, if possible, is there an API i can invoke in the onCreate of the fragments, and tell firebase that user is currently in fragment1, fragment2 or fragment3?

UmarZaii
  • 1,355
  • 1
  • 17
  • 26
Zhen Liu
  • 7,550
  • 14
  • 53
  • 96

4 Answers4

87

UPDATE

Since the setCurrentScreen is deprecated, you can use logEvent method

Bundle bundle = new Bundle();
bundle.putString(FirebaseAnalytics.Param.SCREEN_NAME, fragment.getClass().getSimpleName());
bundle.putString(FirebaseAnalytics.Param.SCREEN_CLASS, fragment.getClass().getSimpleName());
mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.SCREEN_VIEW, bundle);

I've used the following adb commands to check if all is working fine.

adb shell setprop log.tag.FA VERBOSE
adb shell setprop log.tag.FA-SVC VERBOSE
adb logcat -v time -s FA FA-SVC

Once you do that you'll see screen_view events in the logcat. Like this one:

10-15 13:14:13.744 V/FA-SVC (20323): Logging event: origin=app,name=screen_view(_vs),params=Bundle[{ga_event_origin(_o)=app, engagement_time_msec(_et)=31600, ga_previous_class(_pc)=ContentsFragment, ga_previous_id(_pi)=8077407744361472421, ga_previous_screen(_pn)=ContentsFragment, ga_screen_class(_sc)=TestFragment, ga_screen_id(_si)=8077407744361472423, ga_screen(_sn)=TestFragment}]

Previous answer

There is a special method to set a current screen - setCurrentScreen

I used it as follows

mFirebaseAnalytics.setCurrentScreen(this, fragment.getClass().getSimpleName(), fragment.getClass().getSimpleName());

Once the method is called, the following message appears in the LogCat

Logging event (FE): screen_view(_vs), Bundle[{firebase_event_origin(_o)=auto, firebase_previous_class(_pc)=HomeFragment, firebase_previous_id(_pi)=4121566113087629222, firebase_previous_screen(_pn)=HomeFragment, firebase_screen_class(_sc)=StatisticsFragment, firebase_screen_id(_si)=4121566113087629223, firebase_screen(_sn)=StatisticsFragment}]

The following event appears on auto activity tracking:

Logging event (FE): screen_view(_vs), Bundle[{firebase_event_origin(_o)=auto, firebase_previous_class(_pc)=StatisticsFragment, firebase_previous_id(_pi)=4121566113087629223, firebase_previous_screen(_pn)=StatisticsFragment, firebase_screen_class(_sc)=LoginActivity, firebase_screen_id(_si)=4121566113087629224}]

As you see, they are almost the same, so setCurrentScreen is working.

I'm able to see those classes in Firebase Console only on the next day. It is normal for Firebase - it takes time to process such amounts of data.

Firebase Console

Artem Mostyaev
  • 3,874
  • 10
  • 53
  • 60
  • 3
    Where do you think the best place is to call this method? In `onStart`, `onResume`, or another method? (in a fragment) – Thomas Vos Jan 03 '18 at 19:16
  • 6
    `onResume` is the best option, I think. As it is called when you're returning to the fragment from another one. – Artem Mostyaev Jan 04 '18 at 14:48
  • 1
    you can track it during 60seconds: https://firebase.google.com/docs/analytics/debugview https://support.google.com/firebase/answer/7201382?hl=en&utm_id=ad&authuser=0 – yozhik Jan 22 '18 at 14:16
  • Must be called on UI thread: https://stackoverflow.com/a/48117692/1177083 – 4ndro1d Oct 30 '18 at 13:41
  • @ArtemMostyaev what about tracking the activity the fragment is placed in? Are you tracking even that? If yes, activity's screenview will be followed by the fragment's, right? – Charan Dec 11 '18 at 11:06
  • @Charan Activities are tracked automatically, the order of this events depends when you call `setCurrentScreen` in activity lifecycle. – Artem Mostyaev Dec 12 '18 at 09:32
  • 2
    `setCurrentScreen` is deprecated :( – Kartik Garasia Aug 27 '20 at 18:23
  • how they track time? I mean if I log only for one fragment, how they know when I leave that fragment if I don't log other screen events? – Pavel Poley Aug 11 '22 at 11:07
  • I suppose only when you send the next logEvent with a screen. – Artem Mostyaev Aug 11 '22 at 16:28
13

Adding a some more insight here to Artem Mostyaev answer. GA/Firebase panel was reflecting the class name in DEV version but not on PROD version.The main culprit here is

fragment.getClass().getSimpleName()

which obfuscate the fragment name in prod. So GA/Firebase was showing classname to be like (a,b,ah, etc)

getSimpleName() is also dangerous to use in other situation.

More literature : https://medium.com/@elye.project/the-danger-of-using-class-getsimplename-as-tag-for-fragment-5cdf3a35bfe2

Progaurd rules

-keepnames class com.somepackage.yourclass 
Gufran Khurshid
  • 888
  • 2
  • 9
  • 28
  • 1
    Or you can use this proguard rule for all fragments ```-keepnames class * extends androidx.fragment.app.Fragment``` – mindw0rk Jun 17 '21 at 22:49
13

Since setCurrentScreen is deprecated you can use firebaseAnalytics.logEvent(FirebaseAnalytics.Event.SCREEN_VIEW, bundle) instead.

there is a blog post here that explains more about tracking screens manually.

here is an example:

private fun setCurrentScreen(screenName: String) = firebaseAnalytics?.run {
    val bundle = Bundle()
    bundle.putString(FirebaseAnalytics.Param.SCREEN_NAME, screenName)
    bundle.putString(FirebaseAnalytics.Param.SCREEN_CLASS, this@BaseFragment.javaClass.simpleName)
    logEvent(FirebaseAnalytics.Event.SCREEN_VIEW, bundle)
}

In addition, if you want to track screens automatically, you can call this function in one of your BaseFragment lifecycle methods like onResume. just keep in mind that some of the fragments may not have to change the current screen, like the ones which are being created in a ViewPager, so I have declared an open val which you can override in order to change the default behavior.

here is the code in BaseFragment:

protected open val trackScreenView: Boolean = true

override fun onResume() {
    super.onResume()

    if (trackScreenView) setCurrentScreen(this.javaClass.simpleName)
}

and you can disable it by overriding it in your target Fragment:

override val trackScreenView: Boolean = false

By the way, if you are using NavigationUI Component, currently there is no automatic solution for tracking screens, and it only track the single activity you have, so you can prevent firebase automatic screen reporting by putting this meta-data in your app manifest:

<application
    android:name=".App"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme">
    
    <!-- .... -->
    
    <meta-data
        android:name="google_analytics_automatic_screen_reporting_enabled"
        android:value="false" />
</application>
Mosius
  • 1,602
  • 23
  • 32
9

For projects using NavigationUI, you can use a listener NavController.OnDestinationChangedListener

Inside onCreate()

override fun onCreate() {
      super.onCreate()
      .
      .
      .
      .
      navController = Navigation.findNavController(context!!, R.id.nav_host_fragment)
      navController?.addOnDestinationChangedListener(listener)
}

Of the 3 listener function parameters,

  • controller is useful to obtain classname
  • destination is useful to obtain layout xml name string of destination as found inside nav_host_fragment by the attribute android:label
private val listener = NavController.OnDestinationChangedListener { controller, destination, arguments ->
      
      val bundle = Bundle()
      val currentFragmentClassName = (controller.currentDestination as FragmentNavigator.Destination).className
      bundle.putString(FirebaseAnalytics.Param.SCREEN_NAME, destination.label.toString())
      bundle.putString(FirebaseAnalytics.Param.SCREEN_CLASS, currentFragmentClassName)
      FirebaseAnalytics.getInstance(requireContext()).logEvent(FirebaseAnalytics.Event.SCREEN_VIEW, bundle)
      
}

Don't forget cleanup

override fun onDestroy() {
      super.onDestroy()
      navController?.removeOnDestinationChangedListener(listener)
}
Rahul Kahale
  • 519
  • 6
  • 19