huawei_analytics 6.12.0+302 copy "huawei_analytics: ^6.12.0+302" to clipboard
huawei_analytics: ^6.12.0+302 copied to clipboard

Huawei Analytics Kit plugin for Flutter. Analytics Kit offers you a range of preset analytics models so you can gain a deeper insight into your users, products, and content.

example/lib/main.dart

/*
    Copyright 2020-2026. Huawei Technologies Co., Ltd. All rights reserved.

    Licensed under the Apache License, Version 2.0 (the "License")
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        https://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

// =============================================================================
// Huawei HMS Analytics Flutter demo.
// =============================================================================
//
// This file hosts a small, self contained demonstration application for the
// Huawei HMS Analytics Flutter plugin. The application presents a vertically
// scrollable list of buttons where every button triggers exactly one method of
// the [HMSAnalytics] API and reports the outcome of that call inside a simple,
// dismissible dialog.
//
// The demo is intentionally kept flat so that each analytics capability can be
// inspected in isolation. The catalogue below groups the demonstrated methods
// into a handful of thematic areas:
//
//   Logging configuration
//   ---------------------------------------------------------------------------
//     * Enable Log ............... turns on the verbose SDK debug log.
//     * Enable Log With Level .... turns on the debug log at a chosen level.
//
//   User identification
//   ---------------------------------------------------------------------------
//     * Set User Id .............. associates the session with a user id.
//     * Set User Profile ......... stores a single key/value user attribute.
//     * Set Push Token ........... supplies a push token to the SDK.
//     * Delete User Profile ...... removes a single user attribute.
//     * Delete UserId ............ removes the previously stored user id.
//     * Get User Profiles ........ reads back the stored user attributes.
//
//   Session configuration
//   ---------------------------------------------------------------------------
//     * Set Min Activity Sessions  configures the minimum activity sessions.
//     * Set Sessions Duration .... configures the session timeout duration.
//
//   Event reporting
//   ---------------------------------------------------------------------------
//     * Send Custom Event ........ reports a fully custom, typed event.
//     * Send Predefined Event .... reports a predefined SUBMITSCORE event.
//     * Add Default Event Params . registers parameters attached to events.
//
//   Data and privacy management
//   ---------------------------------------------------------------------------
//     * Clear Cached Data ........ clears any locally cached analytics data.
//     * Set Analytics Enabled .... toggles analytics collection on or off.
//     * Set Restriction Enabled .. toggles the collection restriction flag.
//     * Is Restriction Enabled ... reads back the collection restriction flag.
//     * Set Collect Ads Id ....... toggles collection of the advertising id.
//     * Set Property Collection .. toggles collection of a named property.
//
//   Reporting policy
//   ---------------------------------------------------------------------------
//     * Set Report Policies ...... configures the scheduled reporting policy.
//     * Get Report Policy Thresh . reads back the scheduled policy threshold.
//
//   Page tracking
//   ---------------------------------------------------------------------------
//     * Page Start ............... signals the beginning of a page view.
//     * Page End ................. signals the end of a page view.
//
//   Miscellaneous getters and setters
//   ---------------------------------------------------------------------------
//     * Get AAID ................. reads back the anonymous application id.
//     * Set Channel .............. configures the distribution channel.
//     * Set Custom Referrer ...... configures a custom install referrer.
//     * Get Data Upload Site Info  reads back the data upload site details.
//
// None of the helpers in this file change the behaviour of the analytics SDK.
// They only describe how the menu is laid out and how each API call is invoked.
// The demonstrated argument values are placeholders that are safe to send while
// exploring the API and should be replaced with real values in a production
// integration.
// =============================================================================

import 'package:flutter/material.dart';
import 'package:huawei_analytics/huawei_analytics.dart';

/// The entry point of the application.
///
/// This function is intentionally kept as small as possible: it only starts the
/// Flutter framework with a [MaterialApp] whose home is the [MyHomePage] widget.
///
/// Keeping [main] free of any additional logic makes it obvious – at a glance –
/// that the application does nothing more than render the demo home page. Any
/// asynchronous initialisation that the demo requires is performed later, from
/// within the state object of [MyHomePage], rather than here.
void main() {
  runApp(
    const MaterialApp(
      home: MyHomePage(),
    ),
  );
}

/// Collection of constant values that are used throughout the analytics demo.
///
/// Keeping those values in a single, dedicated location makes it easier to see
/// – at a glance – which captions, colors and argument values are being used.
/// The values are intentionally identical to the ones that were previously
/// written inline throughout the widget tree and the API calls.
///
/// The class is deliberately made non instantiable by declaring a single,
/// private constructor. All of the members are `static const`, which means the
/// class acts purely as a namespace for the configuration of the demo.
///
/// The constants are loosely grouped into three categories:
///
///   * presentation constants, such as [appTitle], [appBarColor] and the
///     various button colors, which control how the demo looks, and
///   * dialog constants, such as [dialogTitle] and [dialogCloseText], which
///     control the appearance of the shared result dialog, and
///   * argument constants, such as [userId], [channel] and [scheduledTime],
///     which are forwarded, unchanged, to the analytics SDK.
class _AnalyticsDemoConstants {
  /// Private constructor that prevents this namespace class from being
  /// instantiated. The class only ever exposes `static const` members.
  const _AnalyticsDemoConstants._();

  /// The title displayed in the application bar of the demo.
  ///
  /// Note that the title deliberately preserves the double space between the
  /// words "Flutter" and "Demo" that was present in the original example. The
  /// spacing is kept verbatim so that the rendered demo is byte-for-byte the
  /// same as the original.
  static const String appTitle = 'Huawei HMS Analytics Flutter  Demo';

  /// The background color of the application bar of the demo.
  static const Color appBarColor = Colors.blue;

  /// The background color used behind every button.
  ///
  /// This is the color of the [Container] that wraps each [ElevatedButton] and
  /// provides the thin white gutter around the buttons.
  static const Color buttonBackground = Colors.white;

  /// The fill color used for the [ElevatedButton] itself.
  static const Color buttonFillColor = Colors.grey;

  /// The color used for the caption text of every button.
  static const Color buttonTextColor = Colors.white;

  /// The uniform padding applied around every button.
  ///
  /// A three logical pixel inset is applied on every side, which produces the
  /// small, even gutter that separates the buttons from one another.
  static const EdgeInsets buttonPadding = EdgeInsets.fromLTRB(3, 3, 3, 3);

  /// The title displayed at the top of the result dialog.
  static const String dialogTitle = 'Result';

  /// The caption of the button that dismisses the result dialog.
  static const String dialogCloseText = 'Close';

  /// The log level requested by the "enable log with level" example.
  ///
  /// Possible options are DEBUG, INFO, WARN and ERROR. The example uses INFO,
  /// which reports informational messages and anything more severe.
  static const String logLevel = 'INFO';

  /// The user id supplied to the "set user id" example.
  ///
  /// In a real integration this would be a stable identifier for the signed in
  /// user rather than a hard coded placeholder.
  static const String userId = 'userId';

  /// The key supplied to the "set user profile" example.
  static const String userProfileKey = 'key';

  /// The value supplied to the "set user profile" example.
  static const String userProfileValue = 'value';

  /// The placeholder push token supplied to the "set push token" example.
  ///
  /// The angle brackets make it obvious that the value is a placeholder that is
  /// expected to be replaced with a genuine push token.
  static const String pushToken = '<your_token>';

  /// The number of activity sessions supplied to the corresponding example.
  static const int minActivitySessions = 1000;

  /// The session duration, in milliseconds, supplied to the example.
  static const int sessionDuration = 1000;

  /// The name of the custom event reported by the "send custom event" example.
  static const String customEventName = 'my_custom_event';

  /// The predefined score value reported by the "send predefined event" call.
  static const int predefinedScore = 12;

  /// The scheduled reporting time, in seconds, supplied to the example.
  static const int scheduledTime = 90;

  /// The page name supplied to the page start and page end examples.
  static const String pageName = 'pageName';

  /// The page class override supplied to the page start example.
  static const String pageClassOverride = 'pageClassOverride';

  /// The key deleted by the "delete user profile" example.
  static const String deletedProfileKey = 'key';

  /// The default event parameter key supplied to the example.
  static const String defaultEventParamKey = 'param';

  /// The default event parameter value supplied to the example.
  static const String defaultEventParamValue = 'value';

  /// The channel name supplied to the "set channel" example.
  static const String channel = 'AppGallery';

  /// The property name supplied to the "set property collection" example.
  static const String propertyCollectionName = 'userAgent';

  /// The custom referrer supplied to the "set custom referrer" example.
  static const String customReferrer = 'CustomReferrer';
}

/// A simple, reusable button used throughout the analytics demo.
///
/// Every button displays a bold [title] and, when tapped, invokes the callback
/// supplied through the constructor. The callback is stored as a plain
/// [Function] so that both synchronous and asynchronous handlers can be used
/// interchangeably. In practice every handler in this demo is asynchronous, but
/// the loose typing keeps the button trivially reusable.
///
/// The button intentionally does not concern itself with the outcome of the
/// callback. Each handler is responsible for reporting its own result, which it
/// does through the shared [_MyHomePageState._showDialog] helper.
class MyBtn extends StatelessWidget {
  /// The caption displayed on the button.
  final String title;

  /// The callback invoked when the button is pressed.
  ///
  /// The field is private to the widget; it is only ever read from within
  /// [build]. It is stored as a [Function] so that the call sites can pass a
  /// tear-off of an asynchronous handler without any additional ceremony.
  final Function _onPress;

  /// Creates a new [MyBtn] with the provided [title] and press callback.
  ///
  /// The [_onPress] callback is positional so that the call sites stay concise.
  /// The [key] argument is forwarded, unchanged, to the [StatelessWidget]
  /// super constructor.
  const MyBtn(
    this.title,
    this._onPress, {
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: _AnalyticsDemoConstants.buttonPadding,
      color: _AnalyticsDemoConstants.buttonBackground,
      child: ElevatedButton(
        style: ElevatedButton.styleFrom(
          backgroundColor: _AnalyticsDemoConstants.buttonFillColor,
        ),
        child: Text(
          title,
          style: const TextStyle(
            fontWeight: FontWeight.bold,
            color: _AnalyticsDemoConstants.buttonTextColor,
          ),
        ),
        onPressed: () async {
          _onPress();
        },
      ),
    );
  }
}

/// An immutable description of a single analytics demo action.
///
/// Each action bundles together the caption that should be displayed on the
/// corresponding [MyBtn] together with the callback that should be invoked when
/// the button is pressed. Modelling the actions as data keeps the widget tree
/// in [_MyHomePageState.build] short and makes it trivial to add, remove or
/// reorder the demonstrated analytics capabilities.
///
/// The class is intentionally minimal: it carries no behaviour of its own and
/// exists purely to pair a [label] with its [onPressed] callback.
class _AnalyticsAction {
  /// Creates a description of a single analytics demo action.
  ///
  /// Both the [label] and the [onPressed] callback are positional so that the
  /// list of actions in [_MyHomePageState._analyticsActions] reads as a compact
  /// table of caption/handler pairs.
  const _AnalyticsAction(
    this.label,
    this.onPressed,
  );

  /// The caption displayed on the button that triggers this action.
  final String label;

  /// The callback invoked when the button that triggers this action is pressed.
  final Function onPressed;
}

/// The home page of the analytics demo application.
///
/// The widget itself does not hold any mutable state. All of the mutable state
/// – namely the [HMSAnalytics] instance – lives inside the associated
/// [State] object, [_MyHomePageState].
class MyHomePage extends StatefulWidget {
  /// Creates the [MyHomePage] widget.
  ///
  /// The [key] argument is forwarded, unchanged, to the [StatefulWidget]
  /// super constructor.
  const MyHomePage({
    Key? key,
  }) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

/// The [State] implementation that backs the [MyHomePage] widget.
///
/// This object owns the [HMSAnalytics] instance and exposes one handler method
/// for every analytics capability demonstrated by the example. Each handler
/// follows the same three step shape:
///
///   1. it invokes a single method of the [HMSAnalytics] API,
///   2. it awaits the asynchronous result of that call, and
///   3. it reports the outcome to the user through [_showDialog].
///
/// Because every handler shares this shape, the demo stays extremely uniform,
/// which in turn makes it easy to locate and study any individual capability.
class _MyHomePageState extends State<MyHomePage> {
  /// The title displayed in the application bar of the demo.
  ///
  /// The value is read from [_AnalyticsDemoConstants.appTitle] so that all of
  /// the presentation strings live in a single, well known location.
  final String _appTitle = _AnalyticsDemoConstants.appTitle;

  /// The analytics instance used by every handler in this state object.
  ///
  /// The instance is marked as `late` because it is obtained asynchronously in
  /// [_init], which is triggered from [initState]. Every handler assumes that
  /// the instance has been initialised by the time the user is able to tap a
  /// button, which in practice is always the case because the initialisation
  /// completes almost immediately after the first frame.
  late HMSAnalytics hmsAnalytics;

  @override
  void initState() {
    // Obtain the analytics instance before deferring to the super class so that
    // the asynchronous initialisation is started as early as possible.
    _init();
    super.initState();
  }

  /// Asynchronously obtains the shared [HMSAnalytics] instance.
  ///
  /// The instance is stored in [hmsAnalytics] and is used by every handler in
  /// this state object. The method returns `void` rather than `Future<void>`
  /// because it is invoked in a fire-and-forget fashion from [initState]; there
  /// is no caller that awaits its completion.
  void _init() async {
    hmsAnalytics = await HMSAnalytics.getInstance();
  }

  /// Displays [content] inside a simple, dismissible result dialog.
  ///
  /// The dialog is used by every handler to report the outcome of the analytics
  /// call that it performed. The content is wrapped in a [SingleChildScrollView]
  /// so that long results – such as the map returned by the user profiles
  /// getter – remain fully readable even when they do not fit on a single
  /// screen. The dialog exposes a single "Close" action that pops it off the
  /// navigator.
  void _showDialog(String content) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: const Text(_AnalyticsDemoConstants.dialogTitle),
          content: SingleChildScrollView(
            child: Text(content),
          ),
          actions: <Widget>[
            TextButton(
              child: const Text(_AnalyticsDemoConstants.dialogCloseText),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ],
        );
      },
    );
  }

  /// Enables the analytics debug log and reports the outcome.
  ///
  /// The Huawei Analytics SDK keeps an internal debug log that is disabled by
  /// default in order to avoid leaking diagnostic information in production
  /// builds. Enabling it makes the SDK emit verbose diagnostic messages to the
  /// platform log, which can be extremely helpful while integrating or
  /// debugging the analytics pipeline.
  ///
  /// This handler simply forwards to [HMSAnalytics.enableLog] and, once the
  /// asynchronous call has completed, surfaces a confirmation to the user by
  /// means of the shared [_showDialog] helper.
  ///
  /// See also:
  ///
  ///   * [_onEnableLogWithLevel], which enables the log at a specific level.
  Future<void> _onEnableLog() async {
    await hmsAnalytics.enableLog();
    _showDialog('enableLog success');
  }

  /// Enables the analytics debug log at a specific level and reports the result.
  ///
  /// This is the more granular counterpart of [_onEnableLog]. Instead of simply
  /// turning the log on, it also selects the minimum severity of the messages
  /// that should be emitted. The requested level is
  /// [_AnalyticsDemoConstants.logLevel]. The possible options are DEBUG, INFO,
  /// WARN and ERROR, listed here from least to most severe.
  ///
  /// This handler forwards to [HMSAnalytics.enableLogWithLevel] and then reports
  /// a confirmation through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_onEnableLog], which enables the log at the default level.
  Future<void> _onEnableLogWithLevel() async {
    // Possible options DEBUG, INFO, WARN, ERROR
    await hmsAnalytics.enableLogWithLevel(_AnalyticsDemoConstants.logLevel);
    _showDialog('enableLogWithLevel success');
  }

  /// Associates the current user with a user id and reports the outcome.
  ///
  /// The user id is a stable identifier that ties the collected analytics data
  /// to a specific user. In this demo the placeholder value
  /// [_AnalyticsDemoConstants.userId] is used; a real integration would supply
  /// the identifier of the signed in user instead.
  ///
  /// This handler forwards to [HMSAnalytics.setUserId] and then reports a
  /// confirmation through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_deleteUserId], which removes the previously stored user id.
  Future<void> _setUserId() async {
    await hmsAnalytics.setUserId(_AnalyticsDemoConstants.userId);
    _showDialog('setUserId success');
  }

  /// Stores a single key/value user profile entry and reports the outcome.
  ///
  /// User profile entries describe attributes of the current user, such as
  /// their subscription tier or their preferred language. This demo stores a
  /// single placeholder entry using [_AnalyticsDemoConstants.userProfileKey] and
  /// [_AnalyticsDemoConstants.userProfileValue].
  ///
  /// This handler forwards to [HMSAnalytics.setUserProfile] and then reports a
  /// confirmation through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_getUserProfiles], which reads the stored profile entries back.
  ///   * [_deleteUserProfile], which removes a single profile entry.
  Future<void> _setUserProfile() async {
    await hmsAnalytics.setUserProfile(
      _AnalyticsDemoConstants.userProfileKey,
      _AnalyticsDemoConstants.userProfileValue,
    );
    _showDialog('setUserProfile success');
  }

  /// Supplies a push token to the analytics SDK and reports the outcome.
  ///
  /// Associating a push token with the analytics session allows the collected
  /// data to be correlated with push messaging campaigns. The demo uses the
  /// obvious placeholder [_AnalyticsDemoConstants.pushToken].
  ///
  /// This handler forwards to [HMSAnalytics.setPushToken] and then reports a
  /// confirmation through [_showDialog].
  Future<void> _setPushToken() async {
    await hmsAnalytics.setPushToken(_AnalyticsDemoConstants.pushToken);
    _showDialog('setPushToken success');
  }

  /// Configures the minimum number of activity sessions and reports the result.
  ///
  /// This setting controls how the SDK groups foreground activity into distinct
  /// sessions. The demo uses [_AnalyticsDemoConstants.minActivitySessions].
  ///
  /// This handler forwards to [HMSAnalytics.setMinActivitySessions] and then
  /// reports a confirmation through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_setSessionDuration], the related session timeout setting.
  Future<void> _setMinActivitySessions() async {
    await hmsAnalytics.setMinActivitySessions(
      _AnalyticsDemoConstants.minActivitySessions,
    );
    _showDialog('setMinActivitySessions success');
  }

  /// Configures the session duration and reports the outcome.
  ///
  /// The session duration is the period of inactivity, in milliseconds, after
  /// which the SDK considers the current session to have ended. The demo uses
  /// [_AnalyticsDemoConstants.sessionDuration].
  ///
  /// This handler forwards to [HMSAnalytics.setSessionDuration] and then reports
  /// a confirmation through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_setMinActivitySessions], the related activity session setting.
  Future<void> _setSessionDuration() async {
    await hmsAnalytics.setSessionDuration(
      _AnalyticsDemoConstants.sessionDuration,
    );
    _showDialog('setSessionDuration success');
  }

  /// Builds the payload reported by the custom event example.
  ///
  /// The payload demonstrates the different value types that can be attached to
  /// a custom event, including strings, integers, longs, doubles, booleans, a
  /// list of strings and a nested bundle. The structure and values are
  /// intentionally identical to the ones used in the original example.
  ///
  /// The commented out `list_of_integers` entry documents an important
  /// constraint of the SDK: only a single list may be attached to any given
  /// event, so the list of strings and the (disabled) list of integers cannot
  /// both be present at the same time.
  Map<String, dynamic> _buildCustomEventPayload() {
    return <String, dynamic>{
      'string_value': 'analytics',
      'integer_value': '42',
      'long_value': 4294967298,
      'double_value': 4.2,
      'boolean_value': true,
      // "list_of_integers": <int>[1, 2, 3, 4, 5, 6, 10], // You can only send one list at a time.
      'list_of_strings': <String>['Huawei', 'Analytics'],
      'inner_bundle_example': <String, dynamic>{
        'string_val': 'hms',
        'int_val': 23,
      },
    };
  }

  /// Reports a fully custom analytics event and shows the outcome.
  ///
  /// A custom event is an event whose name and parameters are chosen freely by
  /// the application, as opposed to the predefined events whose names come from
  /// [HAEventType]. The event name is
  /// [_AnalyticsDemoConstants.customEventName] and the payload is created by
  /// [_buildCustomEventPayload].
  ///
  /// This handler forwards to [HMSAnalytics.onEvent] and then reports a
  /// confirmation through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_onPredefinedEvent], which reports a predefined event instead.
  Future<void> _onCustomEvent() async {
    String name = _AnalyticsDemoConstants.customEventName;

    Map<String, dynamic> customEvent = _buildCustomEventPayload();

    await hmsAnalytics.onEvent(name, customEvent);
    _showDialog('onEvent success');
  }

  /// Reports a predefined analytics event and shows the outcome.
  ///
  /// Predefined events use well known names and parameter keys that the SDK
  /// understands out of the box, which allows them to power richer, built in
  /// reports. This example uses the predefined [HAEventType.SUBMITSCORE] type
  /// together with a single [HAParamType.SCORE] parameter whose value is
  /// [_AnalyticsDemoConstants.predefinedScore].
  ///
  /// This handler forwards to [HMSAnalytics.onEvent] and then reports a
  /// confirmation through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_onCustomEvent], which reports a fully custom event instead.
  Future<void> _onPredefinedEvent() async {
    String name = HAEventType.SUBMITSCORE;
    dynamic value = <String, dynamic>{
      HAParamType.SCORE: _AnalyticsDemoConstants.predefinedScore,
    };

    await hmsAnalytics.onEvent(name, value);
    _showDialog('onEvent success');
  }

  /// Clears any locally cached analytics data and reports the outcome.
  ///
  /// This removes data that the SDK has buffered locally but not yet uploaded.
  /// It is primarily useful during testing, when a clean slate is desired.
  ///
  /// This handler forwards to [HMSAnalytics.clearCachedData] and then reports a
  /// confirmation through [_showDialog].
  Future<void> _clearCachedData() async {
    await hmsAnalytics.clearCachedData();
    _showDialog('clearCachedData success');
  }

  /// Enables analytics collection and reports the outcome.
  ///
  /// This is the master switch that controls whether the SDK collects and
  /// reports any analytics at all. The demo enables collection by passing
  /// `true`.
  ///
  /// This handler forwards to [HMSAnalytics.setAnalyticsEnabled] and then
  /// reports a confirmation through [_showDialog].
  Future<void> _setAnalyticsEnabled() async {
    await hmsAnalytics.setAnalyticsEnabled(true);
    _showDialog('setAnalyticsEnabled success');
  }

  /// Reads back the anonymous application id and reports it.
  ///
  /// The anonymous application id, or AAID, is a per-installation identifier
  /// that the SDK uses to distinguish devices without relying on any personally
  /// identifiable information. The retrieved value – which may be `null` – is
  /// displayed in the result dialog.
  ///
  /// This handler forwards to [HMSAnalytics.getAAID] and then reports the value
  /// through [_showDialog].
  Future<void> _getAAID() async {
    String? aaid = await hmsAnalytics.getAAID();
    _showDialog('AAID : $aaid');
  }

  /// Reads back the stored user profiles and reports them.
  ///
  /// The returned map contains the user profile entries that were previously
  /// stored, for example through [_setUserProfile]. The boolean argument
  /// requests the predefined profiles in addition to the custom ones. The
  /// resulting map is rendered in the result dialog.
  ///
  /// This handler forwards to [HMSAnalytics.getUserProfiles] and then reports
  /// the value through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_setUserProfile], which stores a profile entry.
  Future<void> _getUserProfiles() async {
    Map<String, dynamic> profiles = await hmsAnalytics.getUserProfiles(true);
    _showDialog('User Profiles : $profiles');
  }

  /// Signals the start of a page view and reports the outcome.
  ///
  /// Page tracking allows the SDK to measure how long the user spends on each
  /// logical screen of the application. The demo uses
  /// [_AnalyticsDemoConstants.pageName] together with
  /// [_AnalyticsDemoConstants.pageClassOverride].
  ///
  /// This handler forwards to [HMSAnalytics.pageStart] and then reports a
  /// confirmation through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_pageEnd], which signals the end of the same page view.
  Future<void> _pageStart() async {
    await hmsAnalytics.pageStart(
      _AnalyticsDemoConstants.pageName,
      _AnalyticsDemoConstants.pageClassOverride,
    );
    _showDialog('pageStart success');
  }

  /// Signals the end of a page view and reports the outcome.
  ///
  /// This is the counterpart of [_pageStart] and closes the page view that was
  /// opened for [_AnalyticsDemoConstants.pageName].
  ///
  /// This handler forwards to [HMSAnalytics.pageEnd] and then reports a
  /// confirmation through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_pageStart], which signals the beginning of the same page view.
  Future<void> _pageEnd() async {
    await hmsAnalytics.pageEnd(_AnalyticsDemoConstants.pageName);
    _showDialog('pageEnd success');
  }

  /// Configures the reporting policy and reports the outcome.
  ///
  /// The reporting policy controls when the SDK uploads the collected data. The
  /// demo configures the scheduled time policy so that data is uploaded every
  /// [_AnalyticsDemoConstants.scheduledTime] seconds.
  ///
  /// This handler forwards to [HMSAnalytics.setReportPolicies] and then reports
  /// a confirmation through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_getReportPolicyThreshold], which reads the configured threshold back.
  Future<void> _setReportPolicies() async {
    await hmsAnalytics.setReportPolicies(
      scheduledTime: _AnalyticsDemoConstants.scheduledTime,
    );
    _showDialog('setReportPolicies success');
  }

  /// Reads back the threshold of the scheduled time reporting policy.
  ///
  /// The threshold – which may be `null` if the policy is not configured – is
  /// requested for [ReportPolicyType.ON_SCHEDULED_TIME_POLICY] and is displayed
  /// in the result dialog.
  ///
  /// This handler forwards to [HMSAnalytics.getReportPolicyThreshold] and then
  /// reports the value through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_setReportPolicies], which configures the policy in the first place.
  Future<void> _getReportPolicyThreshold() async {
    int? type = await hmsAnalytics.getReportPolicyThreshold(
      ReportPolicyType.ON_SCHEDULED_TIME_POLICY,
    );
    _showDialog('getReportPolicyThreshold $type');
  }

  /// Reads back whether collection restrictions are currently enabled.
  ///
  /// When restrictions are enabled the SDK limits the data that it collects in
  /// order to comply with stricter privacy requirements. The retrieved boolean
  /// is displayed in the result dialog.
  ///
  /// This handler forwards to [HMSAnalytics.isRestrictionEnabled] and then
  /// reports the value through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_setRestrictionEnabled], which toggles the restriction flag.
  Future<void> _isRestrictionEnabled() async {
    bool enabled = await hmsAnalytics.isRestrictionEnabled();
    _showDialog('isRestrictionEnabled $enabled');
  }

  /// Enables collection restrictions and reports the outcome.
  ///
  /// This is the setter counterpart of [_isRestrictionEnabled]. The demo turns
  /// restrictions on by passing `true`.
  ///
  /// This handler forwards to [HMSAnalytics.setRestrictionEnabled] and then
  /// reports a confirmation through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_isRestrictionEnabled], which reads the restriction flag back.
  Future<void> _setRestrictionEnabled() async {
    await hmsAnalytics.setRestrictionEnabled(true);
    _showDialog('setRestrictionEnabled success');
  }

  /// Deletes a single user profile entry and reports the outcome.
  ///
  /// The entry identified by [_AnalyticsDemoConstants.deletedProfileKey] is
  /// removed from the stored user profile.
  ///
  /// This handler forwards to [HMSAnalytics.deleteUserProfile] and then reports
  /// a confirmation through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_setUserProfile], which stores a profile entry.
  Future<void> _deleteUserProfile() async {
    await hmsAnalytics.deleteUserProfile(
      _AnalyticsDemoConstants.deletedProfileKey,
    );
    _showDialog('deleteUserProfile success');
  }

  /// Deletes the stored user id and reports the outcome.
  ///
  /// This clears the association that was previously established through
  /// [_setUserId], for example when the user signs out.
  ///
  /// This handler forwards to [HMSAnalytics.deleteUserId] and then reports a
  /// confirmation through [_showDialog].
  ///
  /// See also:
  ///
  ///   * [_setUserId], which establishes the user id association.
  Future<void> _deleteUserId() async {
    await hmsAnalytics.deleteUserId();
    _showDialog('deleteUserId success');
  }

  /// Enables collection of the advertising id and reports the outcome.
  ///
  /// The advertising id, or OAID, allows the collected analytics to be
  /// correlated with advertising campaigns. The demo enables its collection by
  /// passing `true`.
  ///
  /// This handler forwards to [HMSAnalytics.setCollectAdsIdEnabled] and then
  /// reports a confirmation through [_showDialog].
  Future<void> _setCollectAdsIdEnabled() async {
    await hmsAnalytics.setCollectAdsIdEnabled(true);
    _showDialog('setCollectAdsIdEnabled success');
  }

  /// Builds the default event parameters used by the corresponding example.
  ///
  /// The parameters are attached to every subsequently reported event. The
  /// values are intentionally identical to the ones used in the original
  /// example and are drawn from [_AnalyticsDemoConstants].
  Map<String, Object> _buildDefaultEventParams() {
    return <String, Object>{
      _AnalyticsDemoConstants.defaultEventParamKey:
          _AnalyticsDemoConstants.defaultEventParamValue,
    };
  }

  /// Registers a set of default event parameters and reports the outcome.
  ///
  /// Default event parameters are automatically merged into every event that is
  /// reported afterwards, which avoids having to repeat common parameters at
  /// every call site. The parameters are built by [_buildDefaultEventParams].
  ///
  /// This handler forwards to [HMSAnalytics.addDefaultEventParams] and then
  /// reports a confirmation through [_showDialog].
  Future<void> _addDefaultEventParams() async {
    await hmsAnalytics.addDefaultEventParams(
      _buildDefaultEventParams(),
    );
    _showDialog('addDefaultEventParams success');
  }

  /// Configures the distribution channel and reports the outcome.
  ///
  /// The channel identifies where the application was installed from. The demo
  /// uses [_AnalyticsDemoConstants.channel].
  ///
  /// This handler forwards to [HMSAnalytics.setChannel] and then reports a
  /// confirmation through [_showDialog].
  Future<void> _setChannel() async {
    await hmsAnalytics.setChannel(_AnalyticsDemoConstants.channel);
    _showDialog('setChannel success');
  }

  /// Enables collection of a specific property and reports the outcome.
  ///
  /// This toggles whether the named property
  /// [_AnalyticsDemoConstants.propertyCollectionName] is collected. The demo
  /// enables its collection by passing `true`.
  ///
  /// This handler forwards to [HMSAnalytics.setPropertyCollection] and then
  /// reports a confirmation through [_showDialog].
  Future<void> _setPropertyCollection() async {
    await hmsAnalytics.setPropertyCollection(
      _AnalyticsDemoConstants.propertyCollectionName,
      true,
    );
    _showDialog('setPropertyCollection success');
  }

  /// Configures a custom referrer and reports the outcome.
  ///
  /// The custom referrer supplements the automatically detected install
  /// referrer with an application supplied value. The demo uses
  /// [_AnalyticsDemoConstants.customReferrer].
  ///
  /// This handler forwards to [HMSAnalytics.setCustomReferrer] and then reports
  /// a confirmation through [_showDialog].
  Future<void> _setCustomReferrer() async {
    await hmsAnalytics.setCustomReferrer(
      _AnalyticsDemoConstants.customReferrer,
    );
    _showDialog('setCustomReferrer success');
  }

  /// Reads back information about the data upload site and reports it.
  ///
  /// The data upload site describes the geographic location of the servers that
  /// the collected data is uploaded to. The retrieved value – which may be
  /// `null` – is displayed in the result dialog.
  ///
  /// This handler forwards to [HMSAnalytics.getDataUploadSiteInfo] and then
  /// reports the value through [_showDialog].
  Future<void> _getDataUploadSiteInfo() async {
    String? dataUploadSiteInfo = await hmsAnalytics.getDataUploadSiteInfo();
    _showDialog('DataUploadSiteInfo : $dataUploadSiteInfo');
  }

  /// Builds the ordered list of analytics demo actions.
  ///
  /// The list is intentionally described as data so that the widget tree in
  /// [build] can be generated from it. The order of the actions matches the
  /// order in which the buttons were previously declared inline, so that the
  /// rendered menu is byte-for-byte identical to the original example.
  List<_AnalyticsAction> _analyticsActions() {
    return <_AnalyticsAction>[
      _AnalyticsAction('Enable Log', _onEnableLog),
      _AnalyticsAction('Enable Log With Level', _onEnableLogWithLevel),
      _AnalyticsAction('Set User Id', _setUserId),
      _AnalyticsAction('Set User Profile', _setUserProfile),
      _AnalyticsAction('Set Push Token', _setPushToken),
      _AnalyticsAction('Set Min Activity Sessions', _setMinActivitySessions),
      _AnalyticsAction('Set Sessions Duration', _setSessionDuration),
      _AnalyticsAction('Send Custom Event', _onCustomEvent),
      _AnalyticsAction('Send Predefined Event', _onPredefinedEvent),
      _AnalyticsAction('Clear Cached Data', _clearCachedData),
      _AnalyticsAction('Delete User Profile', _deleteUserProfile),
      _AnalyticsAction('Delete UserId', _deleteUserId),
      _AnalyticsAction('Set Analytics Enabled', _setAnalyticsEnabled),
      _AnalyticsAction('Get AAID', _getAAID),
      _AnalyticsAction('Get User Profiles', _getUserProfiles),
      _AnalyticsAction('Page Start', _pageStart),
      _AnalyticsAction('Page End', _pageEnd),
      _AnalyticsAction('Set Report Policies', _setReportPolicies),
      _AnalyticsAction(
          'Get Report Policy Threshold', _getReportPolicyThreshold),
      _AnalyticsAction('Set Restriction Enabled', _setRestrictionEnabled),
      _AnalyticsAction('Is Restriction Enabled', _isRestrictionEnabled),
      _AnalyticsAction('Set Collect Ads Id Enabled', _setCollectAdsIdEnabled),
      _AnalyticsAction('Add Default Event Params', _addDefaultEventParams),
      _AnalyticsAction('Set Channel', _setChannel),
      _AnalyticsAction('Set Property Collection', _setPropertyCollection),
      _AnalyticsAction('Set Custom Referrer', _setCustomReferrer),
      _AnalyticsAction('Get Data Upload Site Info', _getDataUploadSiteInfo),
    ];
  }

  /// Builds the list of buttons – one for each of the analytics demo actions.
  ///
  /// The buttons are generated from the data returned by [_analyticsActions] so
  /// that the widget tree stays in lock-step with the declared actions. Each
  /// action is mapped to a [MyBtn] that displays its label and invokes its
  /// callback when tapped.
  List<Widget> _buildActionButtons() {
    return _analyticsActions().map<Widget>((_AnalyticsAction action) {
      return MyBtn(action.label, action.onPressed);
    }).toList();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(_appTitle),
        backgroundColor: _AnalyticsDemoConstants.appBarColor,
      ),
      body: SingleChildScrollView(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: _buildActionButtons(),
        ),
      ),
    );
  }
}

// =============================================================================
// Appendix: action reference.
// =============================================================================
//
// The following appendix documents, in a single place, every action that is
// wired up in this demo. For each action it lists the handler that implements
// it, the underlying [HMSAnalytics] method that the handler calls, the
// arguments that are forwarded to that method, the exact text that is shown in
// the result dialog once the call has completed, and the thematic category that
// the action belongs to.
//
// The appendix is purely informational. It exists so that the behaviour of the
// demo can be understood without having to cross-reference the widget tree, the
// list of actions and the individual handler methods. Nothing in this appendix
// is executed; it is a block of documentation comments only.
//
// -----------------------------------------------------------------------------
// Action: Enable Log
// -----------------------------------------------------------------------------
// Handler ......... _onEnableLog
// SDK method ...... HMSAnalytics.enableLog()
// Arguments ....... none
// Result dialog ... "enableLog success"
// Category ........ Logging configuration
//
// Turns on the verbose SDK debug log. The log is disabled by default so that
// diagnostic details are not emitted in production builds. Enabling it is
// typically the first step when troubleshooting an analytics integration, as
// it surfaces the SDK's internal activity in the platform log.
//
// -----------------------------------------------------------------------------
// Action: Enable Log With Level
// -----------------------------------------------------------------------------
// Handler ......... _onEnableLogWithLevel
// SDK method ...... HMSAnalytics.enableLogWithLevel(level)
// Arguments ....... level -> _AnalyticsDemoConstants.logLevel ('INFO')
// Result dialog ... "enableLogWithLevel success"
// Category ........ Logging configuration
//
// The granular counterpart of Enable Log. In addition to turning the log on it
// selects the minimum severity of the messages that are emitted. The available
// levels, from least to most severe, are DEBUG, INFO, WARN and ERROR.
//
// -----------------------------------------------------------------------------
// Action: Set User Id
// -----------------------------------------------------------------------------
// Handler ......... _setUserId
// SDK method ...... HMSAnalytics.setUserId(id)
// Arguments ....... id -> _AnalyticsDemoConstants.userId ('userId')
// Result dialog ... "setUserId success"
// Category ........ User identification
//
// Associates the analytics session with a stable identifier for the signed in
// user. The placeholder value is expected to be replaced with a real user id in
// a production integration.
//
// -----------------------------------------------------------------------------
// Action: Set User Profile
// -----------------------------------------------------------------------------
// Handler ......... _setUserProfile
// SDK method ...... HMSAnalytics.setUserProfile(key, value)
// Arguments ....... key -> 'key', value -> 'value'
// Result dialog ... "setUserProfile success"
// Category ........ User identification
//
// Stores a single key/value attribute of the current user. Profile entries are
// later reported back verbatim by the Get User Profiles action.
//
// -----------------------------------------------------------------------------
// Action: Set Push Token
// -----------------------------------------------------------------------------
// Handler ......... _setPushToken
// SDK method ...... HMSAnalytics.setPushToken(token)
// Arguments ....... token -> _AnalyticsDemoConstants.pushToken ('<your_token>')
// Result dialog ... "setPushToken success"
// Category ........ User identification
//
// Associates a push token with the analytics session so that the collected data
// can be correlated with push messaging campaigns.
//
// -----------------------------------------------------------------------------
// Action: Set Min Activity Sessions
// -----------------------------------------------------------------------------
// Handler ......... _setMinActivitySessions
// SDK method ...... HMSAnalytics.setMinActivitySessions(interval)
// Arguments ....... interval -> 1000 (milliseconds)
// Result dialog ... "setMinActivitySessions success"
// Category ........ Session configuration
//
// Configures how foreground activity is grouped into distinct sessions. Works
// hand in hand with the session duration setting below.
//
// -----------------------------------------------------------------------------
// Action: Set Sessions Duration
// -----------------------------------------------------------------------------
// Handler ......... _setSessionDuration
// SDK method ...... HMSAnalytics.setSessionDuration(duration)
// Arguments ....... duration -> 1000 (milliseconds)
// Result dialog ... "setSessionDuration success"
// Category ........ Session configuration
//
// Sets the period of inactivity after which the current session is considered
// to have ended and a new one begins.
//
// -----------------------------------------------------------------------------
// Action: Send Custom Event
// -----------------------------------------------------------------------------
// Handler ......... _onCustomEvent
// SDK method ...... HMSAnalytics.onEvent(name, payload)
// Arguments ....... name -> 'my_custom_event', payload -> mixed-type map
// Result dialog ... "onEvent success"
// Category ........ Event reporting
//
// Reports an event whose name and parameters are chosen freely by the app. The
// payload demonstrates strings, integers, longs, doubles, booleans, a list of
// strings and a nested bundle. Only a single list may be attached per event.
//
// -----------------------------------------------------------------------------
// Action: Send Predefined Event
// -----------------------------------------------------------------------------
// Handler ......... _onPredefinedEvent
// SDK method ...... HMSAnalytics.onEvent(name, value)
// Arguments ....... name -> HAEventType.SUBMITSCORE, value -> {SCORE: 12}
// Result dialog ... "onEvent success"
// Category ........ Event reporting
//
// Reports an event using a predefined name and parameter key. Predefined events
// power the richer built-in reports offered by the analytics console.
//
// -----------------------------------------------------------------------------
// Action: Clear Cached Data
// -----------------------------------------------------------------------------
// Handler ......... _clearCachedData
// SDK method ...... HMSAnalytics.clearCachedData()
// Arguments ....... none
// Result dialog ... "clearCachedData success"
// Category ........ Data and privacy management
//
// Removes data that the SDK has buffered locally but not yet uploaded. Most
// useful during testing when a clean slate is desired.
//
// -----------------------------------------------------------------------------
// Action: Delete User Profile
// -----------------------------------------------------------------------------
// Handler ......... _deleteUserProfile
// SDK method ...... HMSAnalytics.deleteUserProfile(key)
// Arguments ....... key -> _AnalyticsDemoConstants.deletedProfileKey ('key')
// Result dialog ... "deleteUserProfile success"
// Category ........ User identification
//
// Removes a single previously stored user profile entry, identified by its key.
//
// -----------------------------------------------------------------------------
// Action: Delete UserId
// -----------------------------------------------------------------------------
// Handler ......... _deleteUserId
// SDK method ...... HMSAnalytics.deleteUserId()
// Arguments ....... none
// Result dialog ... "deleteUserId success"
// Category ........ User identification
//
// Clears the user id association, for example when the user signs out.
//
// -----------------------------------------------------------------------------
// Action: Set Analytics Enabled
// -----------------------------------------------------------------------------
// Handler ......... _setAnalyticsEnabled
// SDK method ...... HMSAnalytics.setAnalyticsEnabled(enabled)
// Arguments ....... enabled -> true
// Result dialog ... "setAnalyticsEnabled success"
// Category ........ Data and privacy management
//
// The master switch that controls whether the SDK collects and reports any
// analytics at all.
//
// -----------------------------------------------------------------------------
// Action: Get AAID
// -----------------------------------------------------------------------------
// Handler ......... _getAAID
// SDK method ...... HMSAnalytics.getAAID()
// Arguments ....... none
// Result dialog ... "AAID : $aaid"
// Category ........ Getters
//
// Reads back the anonymous application id, a per-installation identifier that
// distinguishes devices without relying on personally identifiable information.
//
// -----------------------------------------------------------------------------
// Action: Get User Profiles
// -----------------------------------------------------------------------------
// Handler ......... _getUserProfiles
// SDK method ...... HMSAnalytics.getUserProfiles(predefined)
// Arguments ....... predefined -> true
// Result dialog ... "User Profiles : $profiles"
// Category ........ Getters
//
// Reads back the stored user profile entries. Passing true additionally returns
// the predefined profiles alongside the custom ones.
//
// -----------------------------------------------------------------------------
// Action: Page Start
// -----------------------------------------------------------------------------
// Handler ......... _pageStart
// SDK method ...... HMSAnalytics.pageStart(pageName, pageClassOverride)
// Arguments ....... pageName -> 'pageName', override -> 'pageClassOverride'
// Result dialog ... "pageStart success"
// Category ........ Page tracking
//
// Signals the beginning of a page view so that the SDK can measure how long the
// user spends on the corresponding screen.
//
// -----------------------------------------------------------------------------
// Action: Page End
// -----------------------------------------------------------------------------
// Handler ......... _pageEnd
// SDK method ...... HMSAnalytics.pageEnd(pageName)
// Arguments ....... pageName -> 'pageName'
// Result dialog ... "pageEnd success"
// Category ........ Page tracking
//
// Closes the page view that was previously opened by the Page Start action.
//
// -----------------------------------------------------------------------------
// Action: Set Report Policies
// -----------------------------------------------------------------------------
// Handler ......... _setReportPolicies
// SDK method ...... HMSAnalytics.setReportPolicies(scheduledTime: seconds)
// Arguments ....... scheduledTime -> 90 (seconds)
// Result dialog ... "setReportPolicies success"
// Category ........ Reporting policy
//
// Configures the scheduled time policy so that the collected data is uploaded
// at a fixed interval.
//
// -----------------------------------------------------------------------------
// Action: Get Report Policy Threshold
// -----------------------------------------------------------------------------
// Handler ......... _getReportPolicyThreshold
// SDK method ...... HMSAnalytics.getReportPolicyThreshold(policyType)
// Arguments ....... policyType -> ReportPolicyType.ON_SCHEDULED_TIME_POLICY
// Result dialog ... "getReportPolicyThreshold $type"
// Category ........ Reporting policy
//
// Reads back the threshold configured for the scheduled time reporting policy.
// The value may be null when the policy has not been configured.
//
// -----------------------------------------------------------------------------
// Action: Set Restriction Enabled
// -----------------------------------------------------------------------------
// Handler ......... _setRestrictionEnabled
// SDK method ...... HMSAnalytics.setRestrictionEnabled(enabled)
// Arguments ....... enabled -> true
// Result dialog ... "setRestrictionEnabled success"
// Category ........ Data and privacy management
//
// Turns on the collection restriction flag, limiting the data collected in
// order to comply with stricter privacy requirements.
//
// -----------------------------------------------------------------------------
// Action: Is Restriction Enabled
// -----------------------------------------------------------------------------
// Handler ......... _isRestrictionEnabled
// SDK method ...... HMSAnalytics.isRestrictionEnabled()
// Arguments ....... none
// Result dialog ... "isRestrictionEnabled $enabled"
// Category ........ Data and privacy management
//
// Reads back the current value of the collection restriction flag.
//
// -----------------------------------------------------------------------------
// Action: Set Collect Ads Id Enabled
// -----------------------------------------------------------------------------
// Handler ......... _setCollectAdsIdEnabled
// SDK method ...... HMSAnalytics.setCollectAdsIdEnabled(enabled)
// Arguments ....... enabled -> true
// Result dialog ... "setCollectAdsIdEnabled success"
// Category ........ Data and privacy management
//
// Toggles collection of the advertising id (OAID), which allows analytics to be
// correlated with advertising campaigns.
//
// -----------------------------------------------------------------------------
// Action: Add Default Event Params
// -----------------------------------------------------------------------------
// Handler ......... _addDefaultEventParams
// SDK method ...... HMSAnalytics.addDefaultEventParams(params)
// Arguments ....... params -> {'param': 'value'}
// Result dialog ... "addDefaultEventParams success"
// Category ........ Event reporting
//
// Registers parameters that are automatically merged into every event reported
// afterwards, avoiding repetition at each call site.
//
// -----------------------------------------------------------------------------
// Action: Set Channel
// -----------------------------------------------------------------------------
// Handler ......... _setChannel
// SDK method ...... HMSAnalytics.setChannel(channel)
// Arguments ....... channel -> _AnalyticsDemoConstants.channel ('AppGallery')
// Result dialog ... "setChannel success"
// Category ........ Miscellaneous
//
// Records the distribution channel that the application was installed from.
//
// -----------------------------------------------------------------------------
// Action: Set Property Collection
// -----------------------------------------------------------------------------
// Handler ......... _setPropertyCollection
// SDK method ...... HMSAnalytics.setPropertyCollection(property, enabled)
// Arguments ....... property -> 'userAgent', enabled -> true
// Result dialog ... "setPropertyCollection success"
// Category ........ Data and privacy management
//
// Toggles whether a specific named property is collected by the SDK.
//
// -----------------------------------------------------------------------------
// Action: Set Custom Referrer
// -----------------------------------------------------------------------------
// Handler ......... _setCustomReferrer
// SDK method ...... HMSAnalytics.setCustomReferrer(referrer)
// Arguments ....... referrer -> 'CustomReferrer'
// Result dialog ... "setCustomReferrer success"
// Category ........ Miscellaneous
//
// Supplements the automatically detected install referrer with an application
// supplied value.
//
// -----------------------------------------------------------------------------
// Action: Get Data Upload Site Info
// -----------------------------------------------------------------------------
// Handler ......... _getDataUploadSiteInfo
// SDK method ...... HMSAnalytics.getDataUploadSiteInfo()
// Arguments ....... none
// Result dialog ... "DataUploadSiteInfo : $dataUploadSiteInfo"
// Category ........ Getters
//
// Reads back information about the geographic location of the servers that the
// collected data is uploaded to. The value may be null.
//
// =============================================================================
// End of appendix.
// =============================================================================
//
// =============================================================================
// Appendix: integration notes.
// =============================================================================
//
// The notes below complement the action reference above with practical, high
// level guidance about integrating the Huawei HMS Analytics plugin. As with the
// action reference, this section is documentation only and is never executed.
//
// -----------------------------------------------------------------------------
// 1. Obtaining the analytics instance.
// -----------------------------------------------------------------------------
// The [HMSAnalytics] instance is obtained asynchronously through the static
// factory [HMSAnalytics.getInstance]. In this demo the call is made from the
// [_MyHomePageState._init] method, which itself is invoked from [initState].
// Because the instance is required by every handler, it is stored in a `late`
// field and is assumed to be ready by the time the user is able to interact
// with any of the buttons.
//
// In a production application it can be worthwhile to guard the handlers so
// that they no-op until the instance has finished initialising, in order to
// avoid a late-initialisation error in the unlikely event that a button is
// tapped before the factory has completed.
//
// -----------------------------------------------------------------------------
// 2. Reporting outcomes to the user.
// -----------------------------------------------------------------------------
// Every handler reports its outcome through the shared [_showDialog] helper.
// The helper renders a simple [AlertDialog] whose body is wrapped in a
// [SingleChildScrollView] so that long results remain readable. The dialog is
// intentionally minimal because the goal of the demo is to exercise the API,
// not to present a polished user experience.
//
// The messages that the handlers pass to the dialog fall into two groups:
// confirmation messages, such as "enableLog success", which report that a
// fire-and-forget call has completed, and value messages, such as
// "AAID : $aaid", which additionally surface a value that was read back from
// the SDK.
//
// -----------------------------------------------------------------------------
// 3. Constant driven configuration.
// -----------------------------------------------------------------------------
// Every literal that the demo forwards to the SDK, as well as every literal
// that controls the appearance of the menu, is declared as a `static const`
// member of [_AnalyticsDemoConstants]. Centralising the literals in this way
// makes the demo easy to audit: a single glance at the constants class reveals
// exactly which values are being sent to the analytics backend.
//
// The constants are deliberately kept identical to the values that the original
// example used inline, so that migrating from the inline form to the constant
// driven form does not change the behaviour of the demo in any way.
//
// -----------------------------------------------------------------------------
// 4. Data driven menu construction.
// -----------------------------------------------------------------------------
// The list of buttons is not written out by hand. Instead, the demo describes
// each entry as an [_AnalyticsAction] – a caption paired with a handler – and
// then maps the resulting list to a list of [MyBtn] widgets in
// [_MyHomePageState._buildActionButtons]. This keeps the [build] method short
// and guarantees that the order of the rendered buttons matches the declared
// order of the actions.
//
// Adding a new capability to the demo therefore involves three small, local
// steps: write a handler method, document it, and add a single
// [_AnalyticsAction] entry to the list returned by
// [_MyHomePageState._analyticsActions].
//
// -----------------------------------------------------------------------------
// 5. Threading and asynchrony.
// -----------------------------------------------------------------------------
// Every call into the [HMSAnalytics] API is asynchronous and returns a
// [Future]. The handlers await those futures so that the confirmation dialog is
// only shown once the underlying call has actually completed. The [MyBtn]
// widget deliberately types its callback loosely, as a [Function], so that the
// asynchronous handlers can be passed as tear-offs without any additional
// wrapping.
//
// -----------------------------------------------------------------------------
// 6. Privacy considerations.
// -----------------------------------------------------------------------------
// Several of the demonstrated actions concern user privacy directly, including
// the restriction flag, the advertising id collection flag and the per-property
// collection flag. When integrating analytics into a real application these
// settings should be wired up to the user's consent choices rather than being
// hard coded to the values that the demo uses.
//
// The user identification actions likewise deserve careful handling: the user
// id and the user profile entries should reflect real, consented data, and the
// corresponding delete actions should be invoked when the user withdraws their
// consent or signs out.
//
// =============================================================================
// End of integration notes.
// =============================================================================
//
// =============================================================================
// Appendix: glossary.
// =============================================================================
//
// A short glossary of the terms and identifiers that recur throughout this
// demo. This section is documentation only and is never executed.
//
// AAID
//   The anonymous application id. A per-installation identifier used by the
//   SDK to distinguish devices without relying on personally identifiable
//   information. Read back by the Get AAID action.
//
// Channel
//   The distribution channel that the application was installed from, such as
//   an app store or a direct download. Configured by the Set Channel action.
//
// Custom event
//   An event whose name and parameters are chosen freely by the application,
//   as opposed to a predefined event. Reported by the Send Custom Event action.
//
// Default event parameters
//   Parameters that are automatically merged into every event reported after
//   they have been registered. Registered by the Add Default Event Params
//   action.
//
// OAID
//   The advertising id. An identifier that allows analytics to be correlated
//   with advertising campaigns. Its collection is toggled by the Set Collect
//   Ads Id Enabled action.
//
// Page view
//   A logical screen of the application whose duration is measured between a
//   Page Start and the matching Page End action.
//
// Predefined event
//   An event that uses a well known name and parameter keys understood by the
//   SDK out of the box, such as SUBMITSCORE. Reported by the Send Predefined
//   Event action.
//
// Reporting policy
//   The rule that determines when the SDK uploads the collected data. The
//   scheduled time policy uploads data at a fixed interval and is configured by
//   the Set Report Policies action.
//
// Restriction
//   A flag that, when enabled, limits the data collected by the SDK in order
//   to satisfy stricter privacy requirements. Toggled by the Set Restriction
//   Enabled action and read back by the Is Restriction Enabled action.
//
// Session
//   A contiguous period of user activity. Its grouping and timeout are
//   controlled by the Set Min Activity Sessions and Set Sessions Duration
//   actions respectively.
//
// User id
//   A stable identifier for the signed in user. Established by the Set User Id
//   action and cleared by the Delete UserId action.
//
// User profile
//   A collection of key/value attributes describing the current user. Written
//   by the Set User Profile action, read by the Get User Profiles action and
//   individually removed by the Delete User Profile action.
//
// =============================================================================
// End of glossary.
// =============================================================================
//
// =============================================================================
// Appendix: quick start checklist.
// =============================================================================
//
// A condensed checklist for running and reading this demo. This section is
// documentation only and is never executed.
//
//   [ ] Ensure the Huawei Mobile Services core is available on the device or
//       emulator that the demo is run on.
//   [ ] Launch the application; the home page renders the scrollable list of
//       action buttons described in the action reference appendix above.
//   [ ] Tap Enable Log first so that the SDK's diagnostic output becomes
//       visible in the platform log while exploring the other actions.
//   [ ] Tap any other action to invoke the corresponding API method; the
//       result dialog confirms completion or surfaces the value read back.
//   [ ] Consult the action reference appendix to map each button to its
//       handler, its underlying SDK method and its result message.
//   [ ] Consult the integration notes appendix for guidance on wiring the
//       demonstrated capabilities into a production application.
//
// =============================================================================
// End of quick start checklist.
// =============================================================================
22
likes
130
points
22
downloads

Documentation

API reference

Publisher

verified publisherdeveloper.huawei.com

Weekly Downloads

Huawei Analytics Kit plugin for Flutter. Analytics Kit offers you a range of preset analytics models so you can gain a deeper insight into your users, products, and content.

Homepage
Repository (GitHub)
View/report issues

License

Apache-2.0 (license)

Dependencies

flutter

More

Packages that depend on huawei_analytics

Packages that implement huawei_analytics