diff --git a/Docs/Integration.md b/Docs/Integration.md index 87589ea..2830dfb 100644 --- a/Docs/Integration.md +++ b/Docs/Integration.md @@ -112,7 +112,7 @@ value, and a persisted value wins over the manifest on later launches. | Manifest `meta-data` (`com.facebook.sdk.`) | Runtime API | Effect | | --- | --- | --- | | `AutoInitEnabled` | `SetAutoInitEnabled`, `IsAutoInitEnabled` | `false` keeps the SDK from fully initializing; the SDK does not process Graph API responses until then. | -| `AutoLogAppEventsEnabled` | `SetAutoLogAppEventsEnabled`, `IsAutoLogAppEventsEnabled` | Automatic install ping, app activation and, when Events Manager allows it, Google Play purchase and subscription events. Since 19.0.0 a local `false` wins over Events Manager. | +| `AutoLogAppEventsEnabled` | `SetAutoLogAppEventsEnabled`, `IsAutoLogAppEventsEnabled` | The SDK's automatic events: app activation and deactivation (`fb_mobile_activate_app`, `fb_mobile_deactivate_app`, even when `ActivateApp()` started tracking) and, when the App Dashboard allows it, Google Play purchase and subscription events. It does not cover the install ping, which only `ActivateApp()` sends. The effective value is the local value and the Events Manager value: since 19.0.0 a local `false` always wins, and disabling automatic SDK event logging in Events Manager overrides a local `true`. | | `AdvertiserIDCollectionEnabled` | `SetAdvertiserIdCollectionEnabled`, `IsAdvertiserIdCollectionEnabled` | Advertising ID collection. | | `AutoLogMetaDataEnabled` | `SetMetadataCollectionEnabled`, `IsMetadataCollectionEnabled` | SDK 19.0.0+: attaches the screen title and AppLink URL to events. `false` also discards what was collected. | | `AutoLogProductImprovementEnabled` | `SetAutoLogProductImprovementEnabled`, `IsAutoLogProductImprovementEnabled` | SDK 19.0.0+: control for product-improvement data. The 19.0.0 changelog says the SDK does not collect such data yet. | @@ -143,17 +143,34 @@ SDK (see the strictest setup below). { FacebookAppEvents.SetAutoInitEnabled(true); FacebookAppEvents.SetAdvertiserIdCollectionEnabled(true); - // Either let the SDK log automatically ... - // FacebookAppEvents.SetAutoLogAppEventsEnabled(true); - // ... or keep automatic logging off and log activation yourself. ActivateApp() - // sends the one-time install ping and starts activation tracking, which logs - // fb_mobile_activate_app from the next activity resume on. Call it after - // auto-init is enabled, or the SDK discards the ping response. - FacebookAppEvents.SetAutoLogAppEventsEnabled(false); + // App opens (fb_mobile_activate_app) are automatic events: they need + // automatic logging on. + FacebookAppEvents.SetAutoLogAppEventsEnabled(true); + // One-time install ping, and activity tracking. Call it after auto-init + // is enabled, or the SDK discards the ping response. FacebookAppEvents.ActivateApp(); } ``` + `ActivateApp()` alone does not measure app opens. It sends the install ping + and starts activity tracking, but facebook-core 19.0.0 logs the activation + and deactivation events through its automatic-event path, which drops them + while automatic logging is off. With `SetAutoLogAppEventsEnabled(false)`, + the app reports the install and nothing else. + + Automatic logging also turns on automatic Google Play purchase and + subscription logging. When a server already reports purchases (see + [Avoid double counting](#avoid-double-counting-with-server-side-events)), + set "Log In-App Purchases Automatically" and "Log In-App Subscriptions + Automatically" to "No" on the Android card of the Meta App Dashboard + (Settings > Basic) before you enable it. In Events Manager, leave the + dataset's automatic SDK event logging setting unspecified so the app + decides: disabling it there overrides a local `true` once the SDK cached + the app settings, and app opens stop. + + `SetAutoLogAppEventsEnabled` persists its value across launches, so the + withdrawal branch must set it back to `false` (step 3). + When consent is first granted from a dialog, the activity is already resumed, so that session's activation is only counted from the next resume. Do not log `fb_mobile_activate_app` yourself to make up for it: the SDK owns @@ -172,18 +189,17 @@ SDK (see the strictest setup below). ``` Withdrawal fully takes effect on the next process start. Until then the - SDK stays fully initialized: it keeps flushing queued events and, once - `ActivateApp()` or automatic logging started activity tracking, keeps - logging `fb_mobile_activate_app` and deactivation on every resume; none of - the switches above stops that. So: + SDK stays fully initialized and keeps flushing queued events. Activity + tracking keeps running too, but `SetAutoLogAppEventsEnabled(false)` stops + the activation, deactivation and automatic purchase events at once: the SDK + checks the flag for every automatic event. So: - gate your own `Log*` calls on the consent state, so manual events stop at once; - set `ExplicitOnly` and do not call `Flush()` until the process restarts, so nothing more is sent in this process; - - events already queued (including the activation events logged meanwhile) - stay in the SDK's disk queue, and a later fully initialized session (after - consent is granted again) sends them. + - events already queued stay in the SDK's disk queue, and a later fully + initialized session (after consent is granted again) sends them. The SDK cannot delete events it already sent; that goes through Meta's data deletion process. @@ -247,9 +263,12 @@ event ID shared by both sides, and such integrations do not coordinate one with the SDK. When a server already sends trial, subscription or purchase events: - do not log those events from the app as well; -- disable automatic purchase logging: keep `AutoLogAppEventsEnabled=false` and - call `ActivateApp()` (install and activation are still measured), and/or set - "Log In-App Events Automatically" to "No" in the Meta App Dashboard. +- disable automatic purchase logging on the Android card of the Meta App + Dashboard (Settings > Basic): "Log In-App Purchases Automatically" and "Log + In-App Subscriptions Automatically" on "No". Keep `AutoLogAppEventsEnabled` + on after consent if you measure app opens: they are automatic events too. + With `AutoLogAppEventsEnabled=false`, `ActivateApp()` only measures the + install. ### Identity diff --git a/samples/Kapusch.Facebook.Android.Sample/README.md b/samples/Kapusch.Facebook.Android.Sample/README.md index c9dc5b2..7d4af70 100644 --- a/samples/Kapusch.Facebook.Android.Sample/README.md +++ b/samples/Kapusch.Facebook.Android.Sample/README.md @@ -44,12 +44,15 @@ the untracked `strings.xml` only; never commit them. The manifest template sets every automatic collection switch to `false` (`AutoInitEnabled`, `AutoLogAppEventsEnabled`, `AdvertiserIDCollectionEnabled`, `AutoLogMetaDataEnabled`, `AutoLogProductImprovementEnabled`). The sample's -"Grant ads consent" button enables auto-init and advertiser ID collection, then -calls `ActivateApp()` with automatic logging still off (activation is logged -from the next resume on); "Withdraw ads consent" reverts them and sets the -flush behavior to `ExplicitOnly`, because the SDK keeps tracking activation -until the process restarts. Debug builds enable `SetDebugLoggingEnabled(true)`, so logged and -flushed events appear in `adb logcat`. Use Meta Events Manager > Test events to +"Grant ads consent" button enables auto-init, advertiser ID collection and +automatic logging, then calls `ActivateApp()` (install ping; activation is +logged from the next resume on, and only while automatic logging is on); +"Withdraw ads consent" reverts them and sets the flush behavior to +`ExplicitOnly`, because the SDK keeps flushing queued events until the process +restarts. Automatic logging also enables automatic purchase logging: turn it +off on the Android card of the Meta App Dashboard if you test purchases. Debug +builds enable `SetDebugLoggingEnabled(true)`, so logged and flushed events +appear in `adb logcat`. Use Meta Events Manager > Test events to confirm delivery. ### Access token attribution check diff --git a/samples/Kapusch.Facebook.Android.Sample/src/MainActivity.cs b/samples/Kapusch.Facebook.Android.Sample/src/MainActivity.cs index a5ffbd0..ccee8ca 100644 --- a/samples/Kapusch.Facebook.Android.Sample/src/MainActivity.cs +++ b/samples/Kapusch.Facebook.Android.Sample/src/MainActivity.cs @@ -86,11 +86,12 @@ private static void GrantConsent() FacebookAppEvents.SetFlushBehavior(FacebookAppEventsFlushBehavior.Auto); FacebookAppEvents.SetAutoInitEnabled(true); FacebookAppEvents.SetAdvertiserIdCollectionEnabled(true); - // Keep automatic logging off (no purchase auto-logging) and log activation explicitly. - // ActivateApp sends the one-time install ping and logs activation from the next activity - // resume on; this screen is already resumed, so the current session is not counted. A real + // App opens are automatic events, so they need automatic logging on. Turn automatic purchase + // logging off in the Meta App Dashboard when a server reports purchases. + FacebookAppEvents.SetAutoLogAppEventsEnabled(true); + // ActivateApp sends the one-time install ping; activations are logged from the next activity + // resume on. This screen is already resumed, so the current session is not counted. A real // app calls it on every launch with consent, before the first activity resumes. - FacebookAppEvents.SetAutoLogAppEventsEnabled(false); FacebookAppEvents.ActivateApp(); } @@ -101,8 +102,9 @@ private static void WithdrawConsent() FacebookAppEvents.SetAutoInitEnabled(false); FacebookAppEvents.ClearUserId(); FacebookAppEvents.ClearUserData(); - // The SDK stays fully initialized and keeps tracking activation until the process restarts. - // Stop sending for this process; a real app also stops calling the Log* methods. + // Automatic events stop at once, but the SDK stays fully initialized and keeps flushing queued + // events until the process restarts. Stop sending for this process; a real app also stops + // calling the Log* methods. FacebookAppEvents.SetFlushBehavior(FacebookAppEventsFlushBehavior.ExplicitOnly); } diff --git a/src/Kapusch.FacebookApisForAndroidComponents/Facebook/FacebookAppEvents.cs b/src/Kapusch.FacebookApisForAndroidComponents/Facebook/FacebookAppEvents.cs index 69942a7..4733211 100644 --- a/src/Kapusch.FacebookApisForAndroidComponents/Facebook/FacebookAppEvents.cs +++ b/src/Kapusch.FacebookApisForAndroidComponents/Facebook/FacebookAppEvents.cs @@ -19,10 +19,11 @@ namespace Kapusch.Facebook.Android; /// /// /// Turning switches off does not stop the SDK for the current process: it stays fully initialized, -/// keeps flushing queued events and, once or automatic logging started -/// activity tracking, keeps logging activation on every activity resume. Withdrawal fully applies -/// on the next process start. Until then, stop calling the Log* methods and set -/// without calling . +/// keeps flushing queued events and keeps activity tracking running. +/// with stops the automatic events +/// (activation, deactivation, purchases) at once. Withdrawal fully applies on the next process start. Until then, stop calling the +/// Log* methods and set without +/// calling . /// /// /// Every setter, the identity methods and the event methods throw @@ -129,11 +130,18 @@ public static void InitializeSdk( /// /// Sets the persisted automatic App Events logging flag. starts activity - /// tracking, which requires an initialized SDK. Automatic logging covers the install ping, app - /// activation and, when enabled in Events Manager, in-app purchases and subscriptions. - /// does not stop activity tracking already started in this process; it - /// applies from the next process start. + /// tracking, which requires an initialized SDK. Automatic logging covers the SDK's automatic + /// events: app activation and deactivation (also when started + /// tracking) and, when enabled on the Android card of the Meta App Dashboard, in-app purchases and + /// subscriptions. It does not send the install ping; does. + /// stops automatic events at once (the SDK checks the flag for each one) + /// but leaves activity tracking running until the process ends. /// + /// + /// The value persists across launches. The effective value () + /// is when either this value or the Events Manager setting cached by the SDK + /// is disabled. + /// public static void SetAutoLogAppEventsEnabled(bool enabled) => CallVoid("setAutoLogAppEventsEnabled", "(Z)V", new JValue(enabled)); @@ -198,16 +206,17 @@ public static void SetFlushBehavior(FacebookAppEventsFlushBehavior behavior) } /// - /// Sends the one-time install ping and starts activation tracking - /// (AppEventsLogger.activateApp): the SDK logs fb_mobile_activate_app and - /// deactivation from the next activity resume on. An activity already resumed when this runs is - /// not counted, so call it on every launch before the first activity resumes, for example from + /// Sends the one-time install ping and starts activity tracking + /// (AppEventsLogger.activateApp). App opens (fb_mobile_activate_app) and + /// deactivation are automatic events: the SDK logs them from the next activity resume on only + /// while is . With automatic + /// logging off, this measures the install only. An activity already resumed when this runs is not + /// counted, so call it on every launch before the first activity resumes, for example from /// Application.OnCreate or MainActivity.OnCreate. When it runs right after a consent - /// dialog, that session is only counted from the next resume. Use it when automatic logging is - /// disabled and the consumer still wants install and launch measurement. Call it once the SDK is - /// fully initialized ( or ); before - /// that the SDK discards the install ping response and only retries on a later activation. - /// Tracking cannot be stopped until the process ends. + /// dialog, that session is only counted from the next resume. Call it once the SDK is fully + /// initialized ( or ); before that the + /// SDK discards the install ping response and only retries on a later activation. Tracking cannot + /// be stopped until the process ends. /// public static void ActivateApp(Context? context = null) => CallVoid("activateApp", "(Landroid/content/Context;)V", new JValue(ResolveContext(context)));