diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 7ba0d6a4..7f3d977d 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,73 +2,78 @@ ## Our Pledge -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -nationality, personal appearance, race, religion, or sexual identity and -orientation. +We as members, contributors, and leaders pledge to make participation in our project and community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards -Examples of behavior that contributes to creating a positive environment -include: +Examples of behavior that contribute to a positive environment for our project and community include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +* Focusing on what is best, not just for us as individuals but for the overall community -Examples of unacceptable behavior by participants include: +Examples of unacceptable behavior include: -* The use of sexualized language or imagery and unwelcome sexual attention or -advances -* Trolling, insulting/derogatory comments, and personal or political attacks +* The use of sexualized language or imagery, and sexual attention or advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting +* Publishing others’ private information, such as a physical or email address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. +Project maintainers are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any instances of unacceptable behavior. -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. +This Code of Conduct applies when an individual is representing the project or its community both within project spaces and in public spaces. Examples of representing a project or community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at Grp-opensourceoffice@adobe.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by first contacting the project team. Oversight of Adobe projects is handled by the Adobe Open Source Office, which has final say in any violations and enforcement of this Code of Conduct and can be reached at Grp-opensourceoffice@adobe.com. All complaints will be reviewed and investigated promptly and fairly. + +The project team must respect the privacy and security of the reporter of any incident. + +Project maintainers who do not follow or enforce the Code of Conduct may face temporary or permanent repercussions as determined by other members of the project's leadership or the Adobe Open Source Office. + +## Enforcement Guidelines + +Project maintainers will follow these Community Impact Guidelines in determining the consequences for any action they deem to be in violation of this Code of Conduct: + +**1. Correction** + +Community Impact: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +Consequence: A private, written warning from project maintainers describing the violation and why the behavior was unacceptable. A public apology may be requested from the violator before any further involvement in the project by violator. + +**2. Warning** + +Community Impact: A relatively minor violation through a single incident or series of actions. + +Consequence: A written warning from project maintainers that includes stated consequences for continued unacceptable behavior. Violator must refrain from interacting with the people involved for a specified period of time as determined by the project maintainers, including, but not limited to, unsolicited interaction with those enforcing the Code of Conduct through channels such as community spaces and social media. Continued violations may lead to a temporary or permanent ban. + +**3. Temporary Ban** + +Community Impact: A more serious violation of community standards, including sustained unacceptable behavior. + +Consequence: A temporary ban from any interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Failure to comply with the temporary ban may lead to a permanent ban. + +**4. Permanent Ban** + +Community Impact: Demonstrating a consistent pattern of violation of community standards or an egregious violation of community standards, including, but not limited to, sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +Consequence: A permanent ban from any interaction with the community. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at [https://contributor-covenant.org/version/1/4][version] +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, +available at [https://contributor-covenant.org/version/2/1][version] [homepage]: https://contributor-covenant.org -[version]: https://contributor-covenant.org/version/1/4/ +[version]: https://contributor-covenant.org/version/2/1 \ No newline at end of file diff --git a/COPYRIGHT b/COPYRIGHT index 8aa33c0c..b67d6c5e 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,4 +1,4 @@ -© Copyright 2015-2021 Adobe. All rights reserved. +© Copyright 2015-2023 Adobe. All rights reserved. Adobe holds the copyright for all the files found in this repository. diff --git a/Documentation/README.md b/Documentation/README.md index 5967d96f..e46f8815 100644 --- a/Documentation/README.md +++ b/Documentation/README.md @@ -1,53 +1,8 @@ -# Advertising identifier - -## Configuration -To enable advertising identifier features in the sample app, follow these steps: -1. Update the value for key `gms_ads_app_id` located in the `secrets.xml` at [aepsdk-edgeidentity-android/code/app/src/main/res/values](../code/app/src/main/res/values/secrets.xml) with a valid Google AdMob app ID. - - See Google's [quick start reference](https://developers.google.com/admob/android/quick-start) on how to get your AdMob app ID. See step 3 of the [Configure your app](https://developers.google.com/admob/android/quick-start#import_the_mobile_ads_sdk) section for a free public test app ID from Google. - - Any real key values in the `secrets.xml` file should **not** be committed to the repository. -2. By default, the ad ID features are commented out in the sample app. To enable these features, uncomment the implemention code using [find and replace all](https://www.jetbrains.com/help/idea/finding-and-replacing-text-in-project.html#replace_search_string_in_project) to replace all instances of: -```java -/* Ad ID implementation -``` -with: -```java -//* Ad ID implementation -``` -Each code block has a pair of block comments wrapped around it to enable this behavior: -```java -/* Ad ID implementation (pt. 1/4) - -/* Ad ID implementation (pt. 1/4) */ -``` - -After replacement it will become: -```java -//* Ad ID implementation (pt. 1/4) - -//* Ad ID implementation (pt. 1/4) */ -``` - -For convenience, these are the default find and replace shortcuts in Android Studio: -[Default shortcuts for find and replace](./assets/find-and-replace-shortcuts.png) - -The shortcut should open a window that looks like the following: -[Example of find and replace](./assets/find-and-replace-all-example.png) -There should be 5 pairs of special comment blocks (10 total matches) across two files: -`app/build.gradle`, `CustomIdentityFragment.kt`, and `SharedViewModel.kt` - -3. With the implementation code and gradle files uncommented with new dependencies, sync the project with the Gradle file changes using: File -> Sync Project with Gradle Files - -[Example of find and replace](./assets/sync-project-gradle-example.png) - -The app should now be properly configured to use advertising identifier features. - -To **disable** these features, follow these steps: -1. [Find and replace](https://www.jetbrains.com/help/idea/finding-and-replacing-text-in-project.html#replace_search_string_in_project) all instances of: -```java -//* Ad ID implementation -``` -with: -```java -/* Ad ID implementation -``` -2. Sync Project with Gradle files using: File -> Sync Project with Gradle Files \ No newline at end of file +# Edge Identity extension documentation + +## Contents +- [Getting started](getting-started.md) +- [API reference](api-reference.md) +- [Getting started with the test app](getting-started-test-app.md) +- [Troubleshooting guide](troubleshooting-guide.md) +- [Frequently asked questions](frequently-asked-questions.md) \ No newline at end of file diff --git a/Documentation/api-reference.md b/Documentation/api-reference.md index 218a5dc7..e6fb2224 100644 --- a/Documentation/api-reference.md +++ b/Documentation/api-reference.md @@ -134,8 +134,11 @@ Identity.getUrlVariables(new AdobeCallback() { Registers the Identity for Edge Network extension with the Mobile Core extension. +> **Warning** +> Deprecated as of 2.0.0. Use the [MobileCore.registerExtensions API](https://github.com/adobe/aepsdk-core-android) instead. + > **Note** -> If your use-case covers both Edge Network and Adobe Experience Cloud Solutions extensions, you need to register Identity for Edge Network and Identity for Experience Cloud Identity Service from Mobile Core extensions. For more details, see the [frequently asked questions](https://aep-sdks.gitbook.io/docs/foundation-extensions/identity-for-edge-network/identity-faq#q-i-am-using-aep-edge-and-adobe-solutions-extensions-which-identity-extension-should-i-install-and-register). +> If your use-case covers both Edge Network and Adobe Experience Cloud Solutions extensions, you need to register Identity for Edge Network and Identity for Experience Cloud Identity Service from Mobile Core extensions. For more details, see the [frequently asked questions](frequently-asked-questions.md). #### Java @@ -192,12 +195,12 @@ Some example use cases for this API are: * A last-resort reset for when an ECID should no longer be used. This API is not recommended for: -* Resetting a user's consent and privacy settings; see [Privacy and GDPR](https://aep-sdks.gitbook.io/docs/resources/privacy-and-gdpr). +* Resetting a user's consent and privacy settings; see [Privacy and GDPR](https://developer.adobe.com/client-sdks/documentation/privacy-and-gdpr). * Removing existing custom identifiers; use the [`removeIdentity`](#removeidentity) API instead. -* Removing a previously synced advertising identifier after the advertising tracking settings were changed by the user; use the [`setAdvertisingIdentifier`](https://aep-sdks.gitbook.io/docs/foundation-extensions/mobile-core/identity/identity-api-reference#setadvertisingidentifier) API instead. +* Removing a previously synced advertising identifier after the advertising tracking settings were changed by the user; use the [`setAdvertisingIdentifier`](#setadvertisingidentifier) API instead. > **Warning** ->The Identity for Edge Network extension does not read the Mobile SDK's privacy status, and therefore setting the SDK's privacy status to opt-out will not automatically clear the identities from the Identity for Edge Network extension. See [`MobileCore.resetIdentities`](https://aep-sdks.gitbook.io/docs/foundation-extensions/mobile-core/mobile-core-api-reference#resetidentities) for more details. +>The Identity for Edge Network extension does not read the Mobile SDK's privacy status, and therefore setting the SDK's privacy status to opt-out will not automatically clear the identities from the Identity for Edge Network extension. See [`MobileCore.resetIdentities`](https://github.com/adobe/aepsdk-core-android/blob/main/Documentation/MobileCore/api-reference.md) for more details. ------ @@ -208,7 +211,7 @@ When this API is called with a valid advertising identifier, the Identity for Ed The GAID is preserved between app upgrades, is saved and restored during the standard application backup process, and is removed at uninstall. > **Warning** -> In order to enable collection of the user's current advertising tracking authorization selection for the provided advertising identifier, you need to install and register the [AEPEdgeConsent](https://aep-sdks.gitbook.io/docs/foundation-extensions/consent-for-edge-network) extension and update the [AEPEdge](https://aep-sdks.gitbook.io/docs/foundation-extensions/experience-platform-extension) dependency to minimum 1.3.2. +> In order to enable collection of the user's current advertising tracking authorization selection for the provided advertising identifier, you need to install and register the [Consent](https://github.com/adobe/aepsdk-edgeconsent-android) extension and update the [Edge](https://github.com/adobe/aepsdk-edge-android) dependency to minimum 1.3.2. > **Note** > These examples require Google Play Services to be configured in your mobile application, and use the Google Mobile Ads Lite SDK. For instructions on how to import the SDK and configure your `ApplicationManifest.xml` file, see [Google Mobile Ads Lite SDK setup](https://developers.google.com/admob/android/lite-sdk). @@ -377,7 +380,7 @@ Defines a map containing a set of end user identities, keyed on either namespace The format of the IdentityMap class is defined by the [XDM Identity Map Schema](https://github.com/adobe/xdm/blob/master/docs/reference/mixins/shared/identitymap.schema.md). -For more information, please read an overview of the [AEP Identity Service](https://experienceleague.adobe.com/docs/experience-platform/identity/home.html). +For more information, please read an overview of the [Adobe Experience Platform Identity Service](https://experienceleague.adobe.com/docs/experience-platform/identity/home.html). ```text "identityMap" : { @@ -463,7 +466,7 @@ boolean primary = item.isPrimary(); ### AuthenticatedState -Defines the state an [Identity Item](api-reference.md#identityitem) is authenticated for. +Defines the state an [Identity Item](#identityitem) is authenticated for. The possible authenticated states are: diff --git a/Documentation/frequently-asked-questions.md b/Documentation/frequently-asked-questions.md new file mode 100644 index 00000000..c39706bb --- /dev/null +++ b/Documentation/frequently-asked-questions.md @@ -0,0 +1,121 @@ +## Frequently asked questions + +### Q: I am using AEP Edge and Adobe Solutions extensions, which Identity Extension should I install and register? + +A: Both + +When using both Adobe Experience Platform Edge and Adobe Solutions extensions, both Identity for Edge Network and Identity for Experience Cloud ID Service extensions can be registered with the Mobile SDK at the same time. + +**Note** +The following instructions are for configuring an application using both Edge Network and Adobe Solutions mobile extensions. If an application will include only Adobe Experience Platform Edge extensions, follow the instructions here. + +Download and import the Identity and Identity for Edge Network extensions +#### Java + +1. Add the Mobile Core and Edge extensions to your project using the app's Gradle file. + + ```java + implementation 'com.adobe.marketing.mobile:core:2.+' + implementation 'com.adobe.marketing.mobile:identity:2.+' + implementation 'com.adobe.marketing.mobile:edge:2.+' + implementation 'com.adobe.marketing.mobile:edgeidentity:2.+' + ``` +> **Warning** +> Using dynamic dependency versions is not recommended for production apps. Refer to this [page](https://github.com/adobe/aepsdk-core-android/blob/main/Documentation/MobileCore/gradle-dependencies.md) for managing gradle dependencies. + +2. Import the Mobile Core and Edge extensions in your application class. + + ```java + import com.adobe.marketing.mobile.*; + ``` + +Register the Identity and Identity for Edge Network extensions with Mobile Core + +### Q: Will an existing Experience Cloud ID (ECID) migrate to the Identity for Edge Network extension? + +A: Yes. + +If the application previously installed the Identity for Experience Cloud ID Service extension and upgrades to the Identity for Edge Network extension, the existing ECID value is migrated to the Identity for Edge Network extension on first launch of the application. + +Note, however, if the Mobile SDK's privacy status was set to `optedOut` at the time the application is upgraded, the Identity for Experience Cloud ID Service extension will not have an ECID, as it was cleared. In this case, the Identity for Edge Network extension will generate a new ECID. + +### Q: What is the Experience Cloud ID (ECID) used by the SDK when using both AEP Edge extensions and Adobe Solutions extensions? + +A: The Identity for Edge Network extension and the Identity for Experience Cloud ID Service extension each manage their own ECID. However, the two ECIDs are synced as part of the XDM IdentityMap. + +At first launch of the application after upgrading to the Identity for Edge Network extension, the existing ECID from the Identity for Experience Cloud ID Service extension is migrated to the Identity for Edge Network extension. In this case both extensions will have the same ECID value. + +The [resetIdentities](https://github.com/adobe/aepsdk-core-android/blob/main/Documentation/MobileCore/api-reference.md) API regenerates a new ECID used by the Identity for Edge Network extension. This API call does not change the ECID used by the Identity for Experience Cloud ID Service extension. After calling this API, the ECID used by each identity extension will be different. + +Changing the privacy status to optedOut will clear the ECID value used by the Identity for Experience Cloud ID Service extension. Changing the privacy status back to optedIn will generate a new ECID used by the Identity for Experience Cloud ID Service extension. Privacy status changes do not change the ECID used by the Identity for Edge Network extension. Changing the privacy status will cause the ECID used by each identity extension to be different. + +When each identity extension has a different ECID, the Identity for Edge Network extension will include the Identity for Experience Cloud ID Service ECID in its [IdentityMap](api-reference.md), and so the Adobe Experience Platform Identity Service will link the the two ECIDs in the customer's Identity Graph. + +The following example shows an IdentityMap containing the ECIDs from both Identity for Edge Network extension and Identity for Experience Cloud ID Service extension. The ECID from the Identity for Edge Network extension is always listed first in the list of ECIDs. + +```json + "identityMap" : { + "ECID" : [ + { + "id" : "73586628797489658169123381027155647197", + "authenticatedState" : "ambiguous", + "primary" : false + }, + { + "id" : "81117527655405132265917409409236407340", + "authenticatedState" : "ambiguous", + "primary" : false + } + ] + } +``` +### Q: I set privacy status to opted out, why do I see an ECID value when calling Identity.getExperienceCloudId()? + +A: The Identity for Edge Network extension does not change its ECID based on privacy status changes. + +**Note** +The Identity for Edge Network extension and the Identity for Experience Cloud ID Service extension each manage their own ECID value and are generated independently of each other. + +The Identity for Edge Network extension does not clear its stored identities or regenerate the ECID due to privacy status changes. Instead, use the [MobileCore.resetIdentities](https://github.com/adobe/aepsdk-core-android/blob/main/Documentation/MobileCore/api-reference.md) API. Note this API does not clear the ECID but instead generates a new ECID. + +Each identity extension has its own API to retrieve their respective ECIDs as well. Use [Identity.getExperienceCloudId](api-reference.md) to get the Identity for Edge Network extension's ECID, and [Identity.getExperienceCloudId](https://github.com/adobe/aepsdk-core-android/blob/main/Documentation/Identity/api-reference.md) to get the Identity for Experience Cloud ID Service extension's ECID. + +### Q: How can I get all the identifiers used by the SDK when using both AEP Edge extensions and Adobe Solutions extensions? + +A: Use both `getSdkIdentities` and `getIdentities`. +To get the identifiers used by the Adobe Solutions extensions, call [getSdkIdentities](https://github.com/adobe/aepsdk-core-android/blob/main/Documentation/MobileCore/api-reference.md). +To get the identifiers used by the AEP Edge extensions, call [getIdentities](api-reference.md). + +### Q: How can I clear all the identifiers from the SDK when using both AEP Edge extensions and Adobe Solutions extensions? + +A: Set privacy status to `optedOut` and call `resetIdentities`. + +To clear the identifiers used by the Adobe Solutions extensions, call [setPrivacyStatus](https://github.com/adobe/aepsdk-core-android/blob/main/Documentation/MobileCore/api-reference.md) and set the privacy status to optedOut. + +To clear the identifiers used by the AEP Edge extensions, call [resetIdentities](https://github.com/adobe/aepsdk-core-android/blob/main/Documentation/MobileCore/api-reference.md) + +### Q: What steps are needed to generate a new Experience Cloud ID (ECID) for a user when using both AEP Edge extensions and Adobe Solutions extensions? + +A: Both identity extensions' ECID must be regenerated in sequence to avoid linking the old and new ECIDs in Adobe Experience Platform. + +When using Real-time Customer Profile and Identity Service, the ECIDs from both identity extensions are linked together in the customer's Identity Graph. Care must be taken when regenerating new ECIDs such that the old and new ECIDs are not linked within the same Identity Graph. + +Perform the following API calls to regenerate the ECIDs in sequence: +1. Set [privacy status](https://github.com/adobe/aepsdk-core-android/blob/main/Documentation/MobileCore/api-reference.md) to `optedOut` to clear the ECID from the AEP Identity direct service extension. +2. Call [resetIdentities](https://github.com/adobe/aepsdk-core-android/blob/main/Documentation/MobileCore/api-reference.md) to regenerate a new ECID in the Identity for Edge Network extension. +3. Call [getExperienceCloudId](api-reference.md) on the Identity for Edge Network extension. This ensures the new ECID is generated before continuing. +4. Set privacy status `to optedIn` to generate a new ECID in the AEP Identity direct service extension. + +After completing the above steps, each identity extension will have its own, different, ECID. The new ECIDs will get linked under a new Identity Graph for the customer. + +```java +MobileCore.setPrivacyStatus(MobilePrivacyStatus.OPT_OUT); +MobileCore.resetIdentities(); +com.adobe.marketing.mobile.edge.identity.Identity.getExperienceCloudId(new AdobeCallback() { + @Override + public void call(String s) { + // ignore + } +}); +MobileCore.setPrivacyStatus(MobilePrivacyStatus.OPT_IN); +``` \ No newline at end of file diff --git a/Documentation/getting-started-test-app.md b/Documentation/getting-started-test-app.md index 3dde45fb..befe36de 100644 --- a/Documentation/getting-started-test-app.md +++ b/Documentation/getting-started-test-app.md @@ -1,6 +1,82 @@ # Getting started with the test app -## Testing tips for Android advertising identifier +## Data Collection mobile property prerequisites + +The test app needs to be configured with the following edge extensions before it can be used: +- [Mobile Core](https://github.com/adobe/aepsdk-core-android) (installed by default) +- [Edge Network](https://github.com/adobe/aepsdk-edge-android) +- [Edge Identity](https://github.com/adobe/aepsdk-edgeidentity-android) +- [Edge Consent](https://github.com/adobe/aepsdk-edgeconsent-android) (recommended when using the setAdvertisingIdentifier API) + +1. In the test app, set your `ENVIRONMENT_FILE_ID` in `EdgeIdentityApplication.kt`. Refer to [getting started](getting-started.md) for how to get the ENVIRONMENT_FILE_ID. +2. Select the `app` runnable with the desired emulator and run the program. + +## Validation with Assurance + +Configure a new Assurance session by setting the Base URL to `testapp://main` and launch Assurance in the demo app by running the following command in your terminal: + +```bash +$ adb shell am start -W -a android.intent.action.VIEW -d "testapp://main?adb_validation_sessionid=ADD_YOUR_SESSION_ID_HERE" com.adobe.marketing.edge.identity.app +``` + +Note: replace `ADD_YOUR_SESSION_ID_HERE` with your Assurance session identifier. + +Once the connection is established and the events list starts getting populated, you can filter the events for this extension by typing `Edge Identity` in the `Search Events` search box. + +## Testing with advertising identifier + +To enable advertising identifier features in the test app, follow these steps: +1. Update the value for key `gms_ads_app_id` located in the `secrets.xml` at [aepsdk-edgeidentity-android/code/app/src/main/res/values](../code/app/src/main/res/values/secrets.xml) with a valid Google AdMob app ID. + - See Google's [quick start reference](https://developers.google.com/admob/android/quick-start) on how to get your AdMob app ID. See step 3 of the [Configure your app](https://developers.google.com/admob/android/quick-start#import_the_mobile_ads_sdk) section for a free public test app ID from Google. + - Any real key values in the `secrets.xml` file should **not** be committed to the repository. +2. By default, the ad ID features are commented out in the sample app. To enable these features, uncomment the implemention code using [find and replace all](https://www.jetbrains.com/help/idea/finding-and-replacing-text-in-project.html#replace_search_string_in_project) to replace all instances of: +```java +/* Ad ID implementation +``` +with: +```java +//* Ad ID implementation +``` +Each code block has a pair of block comments wrapped around it to enable this behavior: +```java +/* Ad ID implementation (pt. 1/4) + +/* Ad ID implementation (pt. 1/4) */ +``` + +After replacement it will become: +```java +//* Ad ID implementation (pt. 1/4) + +//* Ad ID implementation (pt. 1/4) */ +``` + +For convenience, these are the default find and replace shortcuts in Android Studio: +[Default shortcuts for find and replace](./assets/find-and-replace-shortcuts.png) + +The shortcut should open a window that looks like the following: +[Example of find and replace](./assets/find-and-replace-all-example.png) +There should be 5 pairs of special comment blocks (10 total matches) across two files: +`app/build.gradle`, `CustomIdentityFragment.kt`, and `SharedViewModel.kt` + +3. With the implementation code and gradle files uncommented with new dependencies, sync the project with the Gradle file changes using: File -> Sync Project with Gradle Files + +[Example of find and replace](./assets/sync-project-gradle-example.png) + +The app should now be properly configured to use advertising identifier features. + +To **disable** these features, follow these steps: +1. [Find and replace](https://www.jetbrains.com/help/idea/finding-and-replacing-text-in-project.html#replace_search_string_in_project) all instances of: +```java +//* Ad ID implementation +``` +with: +```java +/* Ad ID implementation +``` +2. Sync Project with Gradle files using: File -> Sync Project with Gradle Files + +### Testing tips for Android advertising identifier See Google's [Advertising ID help article](https://support.google.com/googleplay/android-developer/answer/6048248?hl=en) for the latest requirements to access ad ID through `AdvertisingIdClient` APIs. Developers using ad ID should get the value from the API each time it is used, as permissions for ad tracking and/or the value of the ID itself may be changed at any time. @@ -31,14 +107,15 @@ In other Android environments, the ad ID tracking authorization is controlled us [New ad ID settings page - opt-in state](./assets/new_adid_setting_optin.png) [New ad ID settings page - opt-out state](./assets/new_adid_setting_optout.png) -## Android Ads SDKs -## Google Mobile Ads Lite SDK +#### Android Ads SDKs + +##### Google Mobile Ads Lite SDK The [Google Mobile Ads Lite SDK](https://developers.google.com/admob/android/lite-sdk) is a way to use ads APIs without including the full size [Google Mobile Ads SDK](https://developers.google.com/admob/android/quick-start). See API reference for [`AdvertisingIdClient`](https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient) and [`AdvertisingIdClient.Info`](https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info); the latter provides the APIs for getting the ad ID value and tracking authorization status. The Google AdMob SDK requires an application ID specified in the `AndroidManifest.xml` when the SDK is included in the build, otherwise the app will crash. However, for just ad ID testing purposes, the SDK doesn't have to be initialized. See Google's [quick start guide](https://developers.google.com/admob/android/quick-start#import_the_mobile_ads_sdk) for a detailed implementation guide (and a free sample app ID provided by Google for testing purposes in step 3). -#### Implementation example +##### Implementation example Using a getter to return the ad ID value. Key points to note: - Use of a background coroutine scope from the call site. - Checking the ad tracking authorization status to return the appropriate ad ID value. @@ -95,7 +172,7 @@ Required normal permissions to use ad ID (Android 13 and above): ``` For more specifics on the use of this permission in the context of Android version requirements and permission merging through SDKs, see the [AdvertisingIdClient.Info documentation](https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info). -## AndroidX Ads SDK +##### AndroidX Ads SDK Overview: https://developer.android.com/jetpack/androidx/releases/ads See the overview for official releases; the latest version is still in alpha and may not be fully supported. `AdvertisingIdClient` API reference: https://developer.android.com/reference/androidx/ads/identifier/AdvertisingIdClient diff --git a/Documentation/getting-started.md b/Documentation/getting-started.md index c3aace0f..e1107504 100644 --- a/Documentation/getting-started.md +++ b/Documentation/getting-started.md @@ -1,60 +1,90 @@ -## Getting started +## Adobe Experience Platform Edge Identity Mobile Extension -The Adobe Experience Platform Identity for Edge Network extension has the following peer dependency, which must be installed prior to installing the identity extension: -- [Mobile Core](https://aep-sdks.gitbook.io/docs/foundation-extensions/mobile-core) +The Adobe Experience Platform Identity for Edge Network mobile extension enables identity management from your mobile app when using the Adobe Experience Platform Mobile SDK and the Edge Network extension. -## Add the AEP Identity extension to your app +## Configure the Identity extension in Data Collection UI +1. Log into [Adobe Experience Platform Data Collection](https://experience.adobe.com/data-collection). +2. From **Tags**, locate or search for your Tag mobile property. +3. In your mobile property, select **Extensions** tab. +4. On the **Catalog** tab, locate or search for the **Identity** extension, and select **Install**. +5. There are no configuration settings for **Identity**. +6. Follow the publishing process to update SDK configuration. -### Download and import the Identity extension +## Add the Identity extension to your app -> :information_source: The following instructions are for configuring an application using Adobe Experience Platform Edge mobile extensions. If an application will include both Edge Network and Adobe Solution extensions, both the Identity for Edge Network and Identity for Experience Cloud ID Service extensions are required. Find more details in the [Frequently Asked Questions](https://aep-sdks.gitbook.io/docs/foundation-extensions/identity-for-edge-network/identity-faq) page. +The Adobe Experience Platform Identity for Edge Network extension depends on the following extensions: +- [Mobile Core](https://github.com/adobe/aepsdk-core-android) +- [Edge Network](https://github.com/adobe/aepsdk-edge-android) (required for handling requests to Adobe Edge Network) -### Java +### Download and import the Identity extension -1. Add the Mobile Core and Edge extensions to your project using the app's Gradle file. +> **Note** The following instructions are for configuring an application using Adobe Experience Platform Edge mobile extensions. If an application will include both Edge Network and Adobe Solution extensions, both the Identity for Edge Network and Identity for Experience Cloud ID Service extensions are required. Find more details in the [Frequently Asked Questions](frequently-asked-questions.md) page. - ```java - implementation 'com.adobe.marketing.mobile:core:1.+' - implementation 'com.adobe.marketing.mobile:edge:1.+' - implementation 'com.adobe.marketing.mobile:edgeidentity:1.+' +1. Add the Mobile Core, Edge, and Edge Identity extensions to your project using the app's Gradle file: + +```java +implementation 'com.adobe.marketing.mobile:core:2.+' +implementation 'com.adobe.marketing.mobile:edge:2.+' +implementation 'com.adobe.marketing.mobile:edgeidentity:2.+' ``` +> **Warning** +> Using dynamic dependency versions is not recommended for production apps. Refer to this [page](https://github.com/adobe/aepsdk-core-android/blob/main/Documentation/MobileCore/gradle-dependencies.md) for managing gradle dependencies. -2. Import the Mobile Core and Edge extensions in your Application class. +2. Import the libraries: +#### Java +```java +import com.adobe.marketing.mobile.MobileCore; +import com.adobe.marketing.mobile.Edge; +import com.adobe.marketing.mobile.edge.identity.Identity; +``` +#### Kotlin +```kotlin +import com.adobe.marketing.mobile.MobileCore +import com.adobe.marketing.mobile.Edge +import com.adobe.marketing.mobile.edge.identity.Identity +``` - ```java - import com.adobe.marketing.mobile.MobileCore; - import com.adobe.marketing.mobile.Edge; - import com.adobe.marketing.mobile.edge.identity.Identity; - ``` -3. Register the Identity for Edge Extension with MobileCore: +### Register the Identity for Edge Extension with MobileCore -### Java +#### Java ```java public class MobileApp extends Application { + // Set up the preferred Environment File ID from your mobile property configured in Data Collection UI + private final String ENVIRONMENT_FILE_ID = ""; @Override public void onCreate() { super.onCreate(); MobileCore.setApplication(this); - try { - Edge.registerExtension(); - Identity.registerExtension(); - // register other extensions - MobileCore.start(new AdobeCallback () { - @Override - public void call(Object o) { - MobileCore.configureWithAppID("yourAppId"); - } - }); - - } catch (Exception e) { - ... - } - + MobileCore.configureWithAppID(ENVIRONMENT_FILE_ID); + // Register Adobe Experience Platform SDK extensions + MobileCore.registerExtensions( + Arrays.asList(Edge.EXTENSION, Identity.EXTENSION), + o -> Log.debug("MobileApp", "MobileApp", "Adobe Experience Platform Mobile SDK initialized.") + ); } } ``` +#### Kotlin + +```kotlin +class MobileApp : Application() { + // Set up the preferred Environment File ID from your mobile property configured in Data Collection UI + private var ENVIRONMENT_FILE_ID: String = "" + override fun onCreate() { + super.onCreate() + MobileCore.setApplication(this) + MobileCore.configureWithAppID(ENVIRONMENT_FILE_ID) + // Register Adobe Experience Platform SDK extensions + MobileCore.registerExtensions( + listOf(Edge.EXTENSION, Identity.EXTENSION) + ) { + Log.debug("MobileApp", "MobileApp", "Adobe Experience Platform Mobile SDK initialized.") + } + } +} +``` \ No newline at end of file diff --git a/Documentation/troubleshooting-guide.md b/Documentation/troubleshooting-guide.md new file mode 100644 index 00000000..d928adf9 --- /dev/null +++ b/Documentation/troubleshooting-guide.md @@ -0,0 +1,29 @@ +## Troubleshooting Guide + +### Development on M1 Macs + +M1 Macs may run into errors during the build process, specifically finding the npm installation directory. + +``` +Execution failed for task ':spotlessInternalRegisterDependencies'. + +Can't automatically determine npm executable and none was specifically supplied! + +Spotless tries to find your npm executable automatically. It looks for npm in the following places: +- An executable referenced by the java system property 'npm.exec' - if such a system property exists. +- The environment variable 'NVM_BIN' - if such an environment variable exists. +- The environment variable 'NVM_SYMLINK' - if such an environment variable exists. +- The environment variable 'NODE_PATH' - if such an environment variable exists. +- In your 'PATH' environment variable + +If autodiscovery fails for your system, try to set one of the environment variables correctly or +try setting the system property 'npm.exec' in the build process to override autodiscovery. +``` + +To address this: +- Update Android Studio to the latest version (minimum version Bumblebee Patch 1 should address this issue) +- Update the Android Gradle Plugin to the latest version (7.x.x as of this writing) + +If that does not address the issue, try installing node using the installer and not through homebrew: https://nodejs.org/en/download/ + +Please make sure that these build configuration changes are kept local; any build process dependencies (ex: Gradle version, packages) that are updated in this process should **not** be included in any PRs that are not specifically for updating the project's build configuration. \ No newline at end of file diff --git a/LICENSE b/LICENSE index 161d7ff9..c911c8d8 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright 2021 Adobe +Copyright 2023 Adobe Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 2f5f7753..2d00cd29 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,14 @@ # Adobe Experience Platform Edge Identity Mobile Extension - +[![Maven Central](https://img.shields.io/maven-central/v/com.adobe.marketing.mobile/edgeidentity.svg?logo=android&logoColor=white&label=edgeidentity)](https://mvnrepository.com/artifact/com.adobe.marketing.mobile/edgeidentity) ## About this project -The Adobe Experience Platform Edge Identity is a mobile extension for the [Adobe Experience Platform SDK](https://github.com/Adobe-Marketing-Cloud/acp-sdks) and requires the `MobileCore` extension. This extension enables handling of user identity data from a mobile app when using the AEP Mobile SDK and the Edge Network extension. +The Adobe Experience Platform Identity for Edge Network mobile extension enables identity management from your mobile app when using the [Adobe Experience Platform Mobile SDK](https://developer.adobe.com/client-sdks/documentation) and the Edge Network extension. ### Installation -Integrate the Edge Identity extension into your app by including the following in your gradle file's `dependencies`: - -```gradle -implementation 'com.adobe.marketing.mobile:edgeidentity:1.+' -implementation 'com.adobe.marketing.mobile:edge:1.+' -implementation 'com.adobe.marketing.mobile:core:1.+' -implementation 'com.adobe.marketing.mobile:edgeconsent:1.+' // Recommended when using the setAdvertisingIdentifier API -``` +Integrate the Identity for Edge Network mobile extension into your app by following the [getting started guide](Documentation/getting-started.md). ### Development @@ -23,62 +16,15 @@ implementation 'com.adobe.marketing.mobile:edgeconsent:1.+' // Recommended when To open and run the project, open the `code/settings.gradle` file in Android Studio. -**Data Collection mobile property prerequisites** - -The test app needs to be configured with the following edge extensions before it can be used: -- Mobile Core (installed by default) -- [Edge](https://aep-sdks.gitbook.io/docs/foundation-extensions/experience-platform-extension) -- [Edge Identity](https://aep-sdks.gitbook.io/docs/foundation-extensions/identity-for-edge-network) -- [Edge Consent](https://aep-sdks.gitbook.io/docs/foundation-extensions/consent-for-edge-network) (recommended when using the setAdvertisingIdentifier API) - -**Run demo application** - -1. In the test app, set your `ENVIRONMENT_FILE_ID` in `EdgeIdentityApplication.kt`. -2. Select the `app` runnable with the desired emulator and run the program. - -> **Note** -> To enable GAID related advertising identifier features, follow the [documentation](Documentation/README.md#advertising-identifier) for the required setup steps. - -**View the platform events with Assurance** - -Configure a new Assurance session by setting the Base URL to `testapp://main` and launch Assurance in the demo app by running the following command in your terminal: - -```bash -$ adb shell am start -W -a android.intent.action.VIEW -d "testapp://main?adb_validation_sessionid=ADD_YOUR_SESSION_ID_HERE" com.adobe.marketing.mobile.testapp -``` - -Note: replace ADD_YOUR_SESSION_ID_HERE with your Assurance session identifier. - -Once the connection is established and the events list starts getting populated, you can filter the events for this extension by typing `Edge Identity` in the `Search Events` search box. - -**Development on M1 Macs** -M1 Macs may run into errors during the build process, specifically finding the npm installation directory. - -``` -Execution failed for task ':spotlessInternalRegisterDependencies'. - -Can't automatically determine npm executable and none was specifically supplied! - -Spotless tries to find your npm executable automatically. It looks for npm in the following places: -- An executable referenced by the java system property 'npm.exec' - if such a system property exists. -- The environment variable 'NVM_BIN' - if such an environment variable exists. -- The environment variable 'NVM_SYMLINK' - if such an environment variable exists. -- The environment variable 'NODE_PATH' - if such an environment variable exists. -- In your 'PATH' environment variable - -If autodiscovery fails for your system, try to set one of the environment variables correctly or -try setting the system property 'npm.exec' in the build process to override autodiscovery. -``` +**Run the test app** -To address this: -- Update Android Studio to the latest version (minimum version Bumblebee Patch 1 should address this issue) -- Update the Android Gradle Plugin to the latest version (7.x.x as of this writing) +To configure and run the test app for this project, follow the [getting started guide for the test app](Documentation/getting-started-test-app.md). -If that does not address the issue, try installing node using the installer and not through homebrew: https://nodejs.org/en/download/ +**Development on M1 Macs** -Please make sure that these build configuration changes are kept local; any build process dependencies (ex: Gradle version, packages) that are updated in this process should **not** be included in any PRs that are not specifically for updating the project's build configuration. +If you are seeing any build failures when running the project for the first time on your M1 machine, check out the [troubleshooting guides](Documentation/troubleshooting-guide.md). -### Code Format +#### Code Format This project uses the code formatting tools [Spotless](https://github.com/diffplug/spotless/tree/main/plugin-gradle) with [Prettier](https://prettier.io/) and [ktlint](https://github.com/pinterest/ktlint). Formatting is applied when the project is built from Gradle and is checked when changes are submitted to the CI build system. @@ -93,7 +39,11 @@ make init | Project | Description | | ------------------------------------------------------------ | ------------------------------------------------------------ | -| [AEP SDK Sample App for Android](https://github.com/adobe/aepsdk-sample-app-android) | Contains Android sample app for the AEP SDK. | +| [Core extensions](https://github.com/adobe/aepsdk-core-android) | The Mobile Core represents the foundation of the Adobe Experience Platform mobile SDK. | +| [Edge Network extension](https://github.com/adobe/aepsdk-edge-android) | The Edge Network extension allows you to send data to the Adobe Edge Network from a mobile application. | +| [Consent for Edge Network extension](https://github.com/adobe/aepsdk-edgeconsent-android) | The Consent extension enables consent preferences collection from your mobile app when using the AEP SDK and the Edge Network extension. | +| [Assurance extension](https://github.com/adobe/aepsdk-assurance-android) | The Assurance extension enables validation workflows for your SDK implementation. | +| [Adobe Experience Platform sample app for Android](https://github.com/adobe/aepsdk-sample-app-android) | Contains a fully implemented Android sample app using the Experience Platform SDKs. | ## Documentation diff --git a/code/app/src/main/AndroidManifest.xml b/code/app/src/main/AndroidManifest.xml index a11edc9a..3a7d481a 100644 --- a/code/app/src/main/AndroidManifest.xml +++ b/code/app/src/main/AndroidManifest.xml @@ -12,15 +12,27 @@ android:networkSecurityConfig="@xml/network_security_config" android:theme="@style/AppTheme"> - + + + + + + ` + + + + + (R.id.btn_get_gaid).setOnClickListener { - Log.d(LOG_TAG, "For complete instructions on how to enable ad ID features, please see ./Documentation/README.md#advertising-identifier") + Log.d(LOG_TAG, "For complete instructions on how to enable ad ID features, please see ./Documentation/advertising-identifier.md") } /* Ad ID implementation (pt. 5/5) diff --git a/code/edgeidentity/src/main/java/com/adobe/marketing/mobile/edge/identity/IdentityMap.java b/code/edgeidentity/src/main/java/com/adobe/marketing/mobile/edge/identity/IdentityMap.java index 710bbc31..2a5b8c9b 100644 --- a/code/edgeidentity/src/main/java/com/adobe/marketing/mobile/edge/identity/IdentityMap.java +++ b/code/edgeidentity/src/main/java/com/adobe/marketing/mobile/edge/identity/IdentityMap.java @@ -15,6 +15,7 @@ import com.adobe.marketing.mobile.services.Log; import com.adobe.marketing.mobile.util.DataReader; +import com.adobe.marketing.mobile.util.MapUtils; import com.adobe.marketing.mobile.util.StringUtils; import java.util.ArrayList; import java.util.HashMap; @@ -265,7 +266,7 @@ Map asXDMMap(final boolean allowEmpty) { * @return {@code Map} XDM format representation of IdentityMap */ static IdentityMap fromXDMMap(final Map map) { - if (Utils.isNullOrEmpty(map)) { + if (MapUtils.isNullOrEmpty(map)) { return null; } diff --git a/code/edgeidentity/src/main/java/com/adobe/marketing/mobile/edge/identity/IdentityState.java b/code/edgeidentity/src/main/java/com/adobe/marketing/mobile/edge/identity/IdentityState.java index 2cc44e91..eeec0c41 100644 --- a/code/edgeidentity/src/main/java/com/adobe/marketing/mobile/edge/identity/IdentityState.java +++ b/code/edgeidentity/src/main/java/com/adobe/marketing/mobile/edge/identity/IdentityState.java @@ -24,6 +24,7 @@ import com.adobe.marketing.mobile.services.Log; import com.adobe.marketing.mobile.services.ServiceProvider; import com.adobe.marketing.mobile.util.DataReader; +import com.adobe.marketing.mobile.util.MapUtils; import java.util.HashMap; import java.util.Map; @@ -294,7 +295,7 @@ private boolean isIdentityDirectRegistered(final Map eventHubSha null ); - return !Utils.isNullOrEmpty(identityDirectInfo); + return !MapUtils.isNullOrEmpty(identityDirectInfo); } /** diff --git a/code/edgeidentity/src/main/java/com/adobe/marketing/mobile/edge/identity/Utils.java b/code/edgeidentity/src/main/java/com/adobe/marketing/mobile/edge/identity/Utils.java index ebdcfc95..c3d075c9 100644 --- a/code/edgeidentity/src/main/java/com/adobe/marketing/mobile/edge/identity/Utils.java +++ b/code/edgeidentity/src/main/java/com/adobe/marketing/mobile/edge/identity/Utils.java @@ -12,22 +12,11 @@ package com.adobe.marketing.mobile.edge.identity; import java.util.List; -import java.util.Map; class Utils { private Utils() {} - /** - * Checks if the {@code Map} provided is null or empty. - * - * @param map the {@code Map} to verify - * @return true if the {@code Map} provided is null or empty; false otherwise - */ - static boolean isNullOrEmpty(final Map map) { - return map == null || map.isEmpty(); - } - /** * Checks if the {@code List} provided is null or empty. * diff --git a/code/edgeidentity/src/test/java/com/adobe/marketing/mobile/edge/identity/UtilsTests.java b/code/edgeidentity/src/test/java/com/adobe/marketing/mobile/edge/identity/UtilsTests.java index 3a5072b4..eb060e62 100644 --- a/code/edgeidentity/src/test/java/com/adobe/marketing/mobile/edge/identity/UtilsTests.java +++ b/code/edgeidentity/src/test/java/com/adobe/marketing/mobile/edge/identity/UtilsTests.java @@ -17,27 +17,11 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Map; import org.junit.Test; @SuppressWarnings("unchecked") public class UtilsTests { - @Test - public void test_isNullOrEmpty_nullMap() { - assertTrue(Utils.isNullOrEmpty((Map) null)); - } - - @Test - public void test_isNullOrEmpty_emptyMap() { - assertTrue(Utils.isNullOrEmpty(Collections.EMPTY_MAP)); - } - - @Test - public void test_isNullOrEmpty_nonEmptyNonNullMap() { - assertFalse(Utils.isNullOrEmpty(Collections.singletonMap("someKey", "someValue"))); - } - @Test public void test_isNullOrEmpty_nullList() { assertTrue(Utils.isNullOrEmpty((List) null));