Privacy: Introduction

The Privacy module provides you convenient tools and resources to streamline the process of getting compliant with user privacy directive and regulations such as the General Data Privacy Regulation (GDPR). Here're some highlights of this modules:

  • App Tracking Transparency

    • Starting from version 2.16.0, Easy Mobile supports App Tracking Transparency API (ATT) that is available on iOS starting with its version 14. Android support will be added once they provide a similar API in the future.
  • Comprehensive, flexible consent management system

    • Multi-level, prioritized consent system for flexible management of various consent-requirable services in your app
    • Consent is automatically stored to be persistent across app sessions
    • Consent is automatically applied/communicated to relevant services in runtime
  • Multi-purpose built-in native consent dialog

    • Easy to use dialog that can be used as the common interface for collecting user consent for all relevant services (to avoid annoying the user with multiple popups asking consent for various things)
    • The dialog content and layout can be flexibly adapted to your consent management needs
    • The dialog can be created from script or by using the built-in graphical composer
    • Native look makes sure the dialog can visually fit into apps of any graphic style
  • Location detection tool

    • Built-in API to check whether the current device is in the European Economic Area (EEA) region, which is regulated by the GDPR

App Tracking Transparency

Since iOS 14, Apple requires developers to ask for user consent before accessing privacy data that enables the tracking of users across apps, most notably the IDFA. Apple accordingly provides the App Tracking Transparency framework which contains APIs that facilitate the process, mostly allowing developers to show a popup as shown below to ask for user consent before they can access the IDFA. Easy Mobile helps expose these native APIs as equivalent C# APIs which you can use in Unity environment.

More info about Apple's App Tracking Transparency https://developer.apple.com/app-store/user-privacy-and-data-use/

A consent can take one of 3 values: Unknown, Granted or Revoke.

State Description
Unknown The default state of consent, which means the user neither accepts nor denies the requested use of their data.
Granted The user allows permission to the requested use of their data
Revoked The user denies (or revokes a previously granted) permission to the requested use of their data

A consent is considered "defined" if it has a state other than Unknown.

The primary design target of the consent system is flexibility, that it allows setting a global consent or granular consent for individual modules or services. Different consent-levels have different priorities such that the higher prioritized consent overrides the lower one. In other words, more specific consent is prioritized over less-specific one. The table below summarizes the types of consent provided by Easy Mobile.

Type Level Priority Description
Vendor/Provider Consent Lowest (most specific) Highest Consent given to a specific vendor of a certain service, e.g. AdMob's consent
Module Consent Medium Medium Consent given to a certain module, e.g. Advertising module's consent
Global Consent Highest (least specific) Lowest The common consent given to the whole app

Whenever a service seeks for an applicable consent, it searches from the lowest level to the highest level and get the defined consent with highest priority. The following pseudo-code illustrates the process:

if there’s a defined vendor-consent
    Use vendor-consent
else if there’s a defined module-consent
    Use module-consent
else if there’s a define global-consent
    Use global-consent
else
    Fallback to service's default-behaviour (the “pre-GDPR” behaviour)

ConsentManager Class

Each consent type is managed by a corresponding consent manager. Specifically,

  • The vendor consent is managed by the client of the corresponding vendor, e.g. AdMob's consent is managed by the Advertising.AdMobClient object
  • The module consent is managed by the corresponding consent manager of that module, e.g. the Advertising module's consent is managed by the AdvertisingConsentManager.
  • The global consent is managed by the GlobalConsentManager.

Each of these manager extends the ConsentManager class, which is an abstract class that implements the IConsentRequirable interface. It provides an API for following tasks:

  • Querying the current state of the managed consent
  • Granting or revoking consent
  • Observing consent changes using event

The ConsentManager stores the specified consent state in PlayerPrefs so that it persists across app launches.

You can create classes extending the ConsentManager class to manage consent for other services in your app that are not governed by Easy Mobile.

Specified consent (Granted or Revoked) will be automatically communicated (applied) to corresponding services during their initialization, which most of the time is done automatically during the initialization of Easy Mobile (see Using Easy Mobile > Initializing), unless you turned off the auto initialization feature of these services in the Settings interface. If the consent is changed after the corresponding service has been initialized, that change will be applied in the next initialization. In such case you should inform the user accordingly.

Details on how consent is applied for each individual service can be found in the chapter on GDPR of the corresponding module. Currently, two modules being affected are the Advertising and Notifications module.

Collecting user consent may sound trivial, but if not done right could negatively affect the user experience. A typical app could incorporate multiple consent-requirable services such as ads, analytics and remote notifications. Each service may provide its own interface to collect user consent, e.g. AdMob provides the Consent SDK and the MoPub SDK offers a built-in dialog for the same purpose. However, it may not be ideal to use these vendor-specific interfaces because it means the user would be presented with multiple dialogs asking consent for different things, which would not be a great experience, to say the least.

To solve this problem, Easy Mobile provides a multi-purpose consent dialog that can serve as a common interface for collecting user consent for all relevant services in your app. The dialog is built from native UI elements to give it a mobile-native look that easily fits into your app regardless of its graphic style.

The following image depicts how the consent dialog looks on Android and iOS (left to right).A consent dialog consists of following parts:

  • Title bar: on top of the dialog is a title bar containing:
    • Title (1): the title for your dialog
    • Dismiss button (2): optional button that allows the user to cancel the dialog without updating the consent, when this button is clicked the dialog closes and raises its Dismissed event.
  • Main content: the body of the dialog is comprised of the following element:
    • Texts (3)(5): you can use common HTML tags such as <b>, <i> to style the text, as well as using the <a> tag to include hyperlinks, which is useful for providing links to privacy policies.
    • Toggles (4): you can optionally include toggles in your dialog asking the user to provide granular consent for different services. Toggles can be turned off by default, making them a good means for users to provide explicit consent (they have to turn them on explicitly). Each toggle consists of a title, a switch and a description text, which is collapsible. Similar to the body text, you can use common HTML tags such as <b>, <i> and <a> in this description text. Also, you can, for example, make a toggle on by default and make it unclickable for a service that is vital for the operation of your app to indicate the user that consent for such service is required for continued use of the app.
    • Buttons (6): whenever a button in the dialog is clicked, the dialog closes and raises its Completed event with the ID of the clicked button and the current values of the toggles if any.
  • You can construct consent dialogs directly in script or by using the built-in consent dialog composer (see Settings).
  • You can flexibly interleave text, toggles and buttons in the body of your consent dialog to achieve the desired layout.
  • You can have zero or more toggles, but the dialog should always have at least one button otherwise the Completed event will never fire and the dialog results (clicked button ID, toggle values) won't be returned.

One of the requirement of the GDPR is the the request for consent must be intelligible, so it may be desirable to localize the consent dialog into multiple languages. Easy Mobile's consent dialog was designed with that in mind. All elements of the consent dialog can be accessed and altered at runtime, making it easy to localize them. A typical approach would be using known string-patterns as placeholders for the texts in the dialog (e.g title, body texts, toggle description, button label) and replace them with appropriate localized texts in runtime before showing the dialog.

You may want to use a dedicated localization asset, which can be easily found on the Unity Asset Store, for the purpose of managing and selecting correct translation for the placeholder texts.

EEA Region Checking

Since the GDPR applies specifically to the EEA region, it may be desirable to have different behaviors for your app between EEA and non-EEA regions, especially on privacy-sensitive tasks. To serve that purpose, Easy Mobile provides a built-in validator to detect whether the current device is in EEA region or not. The tool employs several different methods for the test which are summarized in the table below.

Method Description
Google Service Validating using the service provided by Google at https://adservice.google.com/getconfig/pubvendors, requires an internet conection
Telephony Validating using the country code obtained from the device's mobile carrier information (SIM card information), no connection required but won't work without a SIM card
Timezone Validating using the device's timezone setting. No connection required; note that this setting can be changed by the user
Locale Validating using the device's locale setting. No connection required; note that this setting can be changed by the user

The EEA region validator returns one of the following results: InEEA, NotInEEA or Unknown. It allows you to use all available validating methods or a subset of them in a predefined order of priorities. If a higher prioritized method fails, the validator will use the next method until an explicit result (either an InEEA or NotInEEA value) is determined. In the rare case that all methods fail, the result will be returned as Unknown. For example scripts on using the EEA validator see the Scripting chapter.

The codes of those countries currently included in the EEA region are stored in the EEACountries enum.

public enum EEACountries
{
    None = 0,
    AT, BE, BG, HR, CY, CZ, DK, EE, FI, FR, DE, GR, HU, IE, IT, LV, LT, LU, MT, NL, PL, PT, RO, SK, SI, ES, SE, GB, // 28 member states.
    GF, PF, TF, // French territories French Guiana, Polynesia, Southern Territories.
    EL, UK,  // Alternative EU names for GR and GB.
    IS, LI, NO, // Not EU but in EAA.
    CH, // Not in EU or EAA but in single market.
    AL, BA, MK, XK, ME, RS, TR // Candidate countries.
}

It's up to you to decide how your app should react to the GDPR, including whether user consent should be collected for those services in the app that may be subject to the regulation. The following proposed workflow can be optionally employed in the case you decide to collect user consent and configure relevant service with that consent.

SgLib Games offer tools and information as a resource to assist you in getting compliant with the GDPR, but we don't offer legal advice. We recommend you contact your legal counsel to find out how GDPR affects you.

When building a consent aware app using Easy Mobile, following considerations can be made:

  • Since the consent is applied during service initialization, it's advisable to collect user consent and forward it to relevant modules or services before initializing the Easy Mobile runtime.
  • A consent dialog should be presented the first time the app launches to collect user consent for all relevant services; this dialog should not be dismissible, as we want the user to specify explicit consent once before the normal operation runs.
  • The consent dialog should be accessible again (e.g. via a menu button) so that the user can change their consent; this dialog should reflect the current consent states for each individual services and should be dismissible, so the user can leave it without updating their consent in case the dialog was opened unintentionally. If the user does change their consent, they should be informed that the changes will take place during the next app launch (the next initialization).
  • It may be advisable to only collect and apply consent for devices in the EEA region, while having a "pre-GDPR" behavior in other region (not setting any consent, as what's normally done before the GDPR came out).
  • It may be desirable to use a localization tool to localize the consent dialog to languages in the EEA region.

Since it's common to have multiple consent-requirable services in your app, some of those may be governed by Easy Mobile while others may be not, we recommend having a custom "app consent" class that represents the collection of all consent given to each individual service in the app. This class should have several functionalities:

  • Represents the collection of consent given to various services, specifically advertising, analytics and notifications as in the example script
  • Forwards the collected consent to corresponding services using appropriate API provided by Easy Mobile (and other relevant 3rd party SDKs if any)
  • Allows saving and retrieving the collected consent to and from PlayerPrefs in form of a JSON string (thus it is attributed as Serializable) so that we can restore the consent values and reflect them on the consent dialog when it is shown again

For the purpose of explaining this proposed workflow, we reuse the DemoAppConsent class found in our Privacy demo scene as an example of the aforementioned class.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

namespace EasyMobile.Demo
{
    /// <summary>
    /// This class represents a collection of individual consents for
    /// all 3rd-party services that require consent in our app.
    /// This class can be used to manage consent for any
    /// 3rd-party service, not just those managed by Easy Mobile.
    /// Note that this class is serializable so we can serialize it
    /// to a JSON string and store in PlayerPrefs.
    /// </summary>
    [Serializable]
    public class DemoAppConsent
    {
        public const string DemoStorageKey = "EM_Demo_AppConsent";

        #region 3rd-party Services Consent

        // The consent for the whole Advertising module.
        // (we could have had different consents for individual ad networks, but for
        // the sake of simplicity in this demo, we'll ask the user a single consent
        // for the whole module and use it for all ad networks).
        public ConsentStatus advertisingConsent = ConsentStatus.Unknown;

        // The consent for the whole Notifications module.
        // Note that data consent is only applicable to push notifications,
        // local notifications don't require any consent.
        public ConsentStatus notificationConsent = ConsentStatus.Unknown;

        // Since this demo app also has In-App Purchase, which forces the use of
        // Unity Analytics, we could have had to ask a consent for that too. However,
        // according to Unity it's sufficient to provide the user with an URL
        // so they can opt-out on Unity website. So we will include that URL in our
        // consent dialog and not need to ask and store any explicit consent locally.

        // Here you can add consent variables for other 3rd party services if needed,
        // including those not managed by Easy Mobile...

        #endregion

        /// <summary>
        /// To JSON string.
        /// </summary>
        /// <returns>A <see cref="System.String"/> that represents the current <see cref="EasyMobile.Demo.AppConsent"/>.</returns>
        public override string ToString()
        {
            return JsonUtility.ToJson(this);
        }

        /// <summary>
        /// Converts this object to JSON and stores in PlayerPrefs with the provided key.
        /// </summary>
        /// <param name="key">Key.</param>
        public void Save(string key)
        {
            PlayerPrefs.SetString(key, ToString());
        }

        /// <summary>
        /// Forwards the consent to relevant modules of EM.
        /// </summary>
        /// <param name="consent">Consent.</param>
        /// <remarks>
        /// In a real-world app, you'd want to write similar method
        /// to forward the obtained consent not only to relevant EM modules
        /// and services, but also to other relevant 3rd-party SDKs in your app.
        public static void ApplyDemoAppConsent(DemoAppConsent consent)
        {
            // Forward the consent to the Advertising module.
            if (consent.advertisingConsent == ConsentStatus.Granted)
                Advertising.GrantDataPrivacyConsent();
            else if (consent.advertisingConsent == ConsentStatus.Revoked)
                Advertising.RevokeDataPrivacyConsent();

            // Forward the consent to the Notifications module.
            if (consent.notificationConsent == ConsentStatus.Granted)
                Notifications.GrantDataPrivacyConsent();
            else if (consent.notificationConsent == ConsentStatus.Revoked)
                Notifications.RevokeDataPrivacyConsent();

            // Here you can forward the consent to other relevant 3rd-party services if needed...

        }

        /// <summary>
        /// Saves the give app consent to PlayerPrefs as JSON using the demo storage key.
        /// </summary>
        /// <param name="consent">Consent.</param>
        public static void SaveDemoAppConsent(DemoAppConsent consent)
        {
            if (consent != null)
                consent.Save(DemoStorageKey);
        }

        /// <summary>
        /// Loads the demo app consent from PlayerPrefs, returns null if nothing stored previously.
        /// </summary>
        /// <returns>The demo app consent.</returns>
        public static DemoAppConsent LoadDemoAppConsent()
        {
            string json = PlayerPrefs.GetString(DemoStorageKey, null);

            if (!string.IsNullOrEmpty(json))
                return JsonUtility.FromJson<DemoAppConsent>(json);
            else
                return null;
        }
    }
}

The following pseudo-code illustrates the process that should be done at every app launch to collect and forward consent (if needed) and then initialize Easy Mobile in a consent-aware app.

if NOT in EEA region                             // not affected by GDPR
{
    Initialize Easy Mobile                       // no consent needed, go ahead with initialization
}
else                                             // is in EEA region, affected by GDPR
{
    if NOT first app launch                      // consent should be given already in the 1st launch
    {
        Initialize Easy Mobile                   // go ahead with initialization
    }
    else                                         // this is first app launch, should ask for consent
    {
        Get the default consent dialog           // or create a new one
        Localize the consent dialog              // if needed, preferably using a localization tool
        Show non-dismissible consent dialog      // user can not skip it
        Construct new "app consent" object       // consent collected, construct the object off it
        Forward consent to relevant services     // using the "app consent" object
        Save consent values                      // using the "app consent" object
        Initialize Easy Mobile                   // everything is set, can now start working!
    }
}

As mentioned previously, apart from collecting consent at the first app launch we also need to provide a way for the user to access the consent dialog again to update their consent if needed. The simplest way is having a menu button that can open the consent dialog at the user discretion. This dialog should reflect the current consent status and is dismissible. The following pseudo-code illustrate the process to handle such consent dialog opening button.

if button clicked
{
    Get the default consent dialog               // or create a new one
    Localize the consent dialog                  // if needed, preferably using a localization tool

    if having a stored consent                   // check using the "app consent" class
    {
        Retrieve the stored consent              // using the "app consent" class
        Update dialog with stored consent        // reflect the current consent status
    }

    Show dismissible consent dialog              // user can skip it if opened unintentionally

    if consent is updated                        // dialog is close & consent has changed
    {
        Construct new "app consent" object       // consent collected, construct the object off it
        Forward consent to relevant services     // using the "app consent" object
        Save consent values                      // using the "app consent" object
        Show alert                               // inform user changes will be applied since next app launch
    }
}

Please see folder Assets/EasyMobile/Demo/Scripts/PrivacyDemo for example scripts on this subject.

results matching ""

    No results matching ""