|
| 1 | +# Add Analytics to the Notes App |
| 2 | + |
| 3 | +In the [previous section](./index.md) of this tutorial, you installed Android Studio, downloaded a sample note-taking app from GitHub, and then compiled and ran it in the Android Emulator. This tutorial assumes you have completed these steps. In this section, you extend the notes app to include application analytics. Application analytics enable you to gather demographic information about the application usage. |
| 4 | + |
| 5 | +You should be able to complete this section in 10-15 minutes. |
| 6 | + |
| 7 | +## Create an AWS Backend |
| 8 | + |
| 9 | +1. Open the project in Android Studio. |
| 10 | +2. Choose **View**, choose **Tool Windows**, and then choose **Terminal**. This opens a terminal prompt within Android Studio at the bottom of the window. |
| 11 | +3. In the terminal window, enter the following commands: |
| 12 | + |
| 13 | + ``` |
| 14 | + $ amplify init |
| 15 | + ``` |
| 16 | +
|
| 17 | + The CLI prompts you through the process of initializing your backend project. When prompted for the `Res` directory: |
| 18 | +
|
| 19 | + ``` |
| 20 | + ? Where is your Res directory: app/src/main/res |
| 21 | + ``` |
| 22 | +
|
| 23 | +4. Next, add the analytics service to your backend: |
| 24 | +
|
| 25 | + ``` |
| 26 | + $ amplify add analytics |
| 27 | + ``` |
| 28 | +
|
| 29 | + Again, the CLI prompts you through the process of initializing your backend project. |
| 30 | +5. Finally, deploy the resources you have provisioned: |
| 31 | +
|
| 32 | + ``` |
| 33 | + $ amplify push |
| 34 | + ``` |
| 35 | +
|
| 36 | +The `amplify init` command does the following within your project: |
| 37 | +
|
| 38 | +* Creates a basic backend definition in the `amplify` directory. |
| 39 | +* Creates an `awsconfiguration.json` file describing the backend in the `app/src/main/res/raw` resource directory. |
| 40 | +
|
| 41 | +The `amplify analytics add` command adds the appropriate entries into the backend definition file for deploying Amazon Pinpoint as a service for this project. The `amplify push` command deploys any new services that are defined and updates the `awsconfiguration.json` file so that the new services can be used within your app. |
| 42 | +
|
| 43 | +## Add Permissions to the AndroidManifest.xml |
| 44 | +
|
| 45 | +1. Open the project in Android Studio. |
| 46 | +2. On the left side of the project, choose **Project** to open the project browser. |
| 47 | +3. To find the app manifest, change the project browser view menu at the top to **Android**, and open the `app/manifests` folder. |
| 48 | +4. Add the `INTERNET`, `ACCESS_NETWORK_STATE`, and `ACCESS_WIFI_STATE` permissions to your project's `AndroidManifest.xml` file. |
| 49 | +
|
| 50 | + ```xml |
| 51 | + <?xml version="1.0" encoding="utf-8"?> |
| 52 | + <manifest xmlns:android="http://schemas.android.com/apk/res/android" |
| 53 | + package="com.amazonaws.mobile.samples.mynotes"> |
| 54 | +
|
| 55 | + <uses-permission android:name="android.permission.INTERNET"/> |
| 56 | + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> |
| 57 | + <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> |
| 58 | +
|
| 59 | + <application |
| 60 | + android:name=".NotesApp" |
| 61 | + android:allowBackup="true" |
| 62 | + android:icon="@mipmap/ic_launcher" |
| 63 | + android:label="@string/app_name" |
| 64 | + android:roundIcon="@mipmap/ic_launcher_round" |
| 65 | + android:supportsRtl="true" |
| 66 | + android:theme="@style/AppTheme"> |
| 67 | + </application> |
| 68 | + </manifest> |
| 69 | + ``` |
| 70 | +
|
| 71 | +## Add AWS SDK for Android Library |
| 72 | +
|
| 73 | +1. Edit the `app/build.gradle` file. Add the following lines to the `dependencies` section: |
| 74 | +
|
| 75 | + ```gradle |
| 76 | + dependencies { |
| 77 | + // Other dependencies will be here already |
| 78 | +
|
| 79 | + // AWS Mobile SDK for Android |
| 80 | + def aws_version = '2.6.27' |
| 81 | + implementation "com.amazonaws:aws-android-sdk-core:$aws_version" |
| 82 | + implementation "com.amazonaws:aws-android-sdk-auth-core:$aws_version@aar" |
| 83 | + implementation "com.amazonaws:aws-android-sdk-pinpoint:$aws_version" |
| 84 | + } |
| 85 | + ``` |
| 86 | +
|
| 87 | +2. Choose **Sync Now** on the upper-right corner to incorporate the dependencies you just declared. |
| 88 | +
|
| 89 | +## Create an AWSService.kt Class |
| 90 | +
|
| 91 | +In the sample, you need to provide a class to provide access to the configuration and identity provider objects. These objects are central to how Android applications locate and communicate with AWS resources. This object should be a singleton. In the sample, you use a central dependency class to ensure that the `AWSService` object is created one time only. |
| 92 | +
|
| 93 | +1. Expand `app/java` in the Android Studio project explorer. |
| 94 | +2. Right-click the `services` directory. |
| 95 | +3. Choose **New** > **Package**. |
| 96 | +4. For **Name**, enter `aws` and then choose **OK**. |
| 97 | +5. Right-click the `aws` directory. |
| 98 | +6. Choose **New** > **Java Class**. |
| 99 | +7. For **Name**, enter `AWSService` and then choose **OK**. |
| 100 | +
|
| 101 | +The following is the initial code in this class: |
| 102 | +
|
| 103 | +```java |
| 104 | +package com.amazonaws.mobile.samples.mynotes.services.aws; |
| 105 | +
|
| 106 | +import android.content.Context; |
| 107 | +
|
| 108 | +import com.amazonaws.mobile.auth.core.IdentityManager; |
| 109 | +import com.amazonaws.mobile.config.AWSConfiguration; |
| 110 | +
|
| 111 | +public class AWSService { |
| 112 | + private AWSConfiguration awsConfiguration; |
| 113 | + private IdentityManager identityManager; |
| 114 | +
|
| 115 | + public AWSService(Context context) { |
| 116 | + awsConfiguration = new AWSConfiguration(context); |
| 117 | + identityManager = new IdentityManager(context, awsConfiguration); |
| 118 | + IdentityManager.setDefaultIdentityManager(identityManager); |
| 119 | + } |
| 120 | +
|
| 121 | + public IdentityManager getIdentityManager() { |
| 122 | + return identityManager; |
| 123 | + } |
| 124 | +
|
| 125 | + public AWSConfiguration getConfiguration() { |
| 126 | + return awsConfiguration; |
| 127 | + } |
| 128 | +} |
| 129 | +``` |
| 130 | + |
| 131 | +## Create an AWSAnalyticsService.java Class |
| 132 | + |
| 133 | +In our sample, the analytics service is provided through a mock dependency injection service. The analytics service must be an object that implements the `AnalyticsService` interface. All other parts of the application will use the `AnalyticsService` that is defined in the `Injection` class. |
| 134 | + |
| 135 | +1. Right-click the `aws` directory. |
| 136 | +2. Choose **New** > **Java Class**. |
| 137 | +3. For **Name**, enter `AWSAnalyticsService` and then choose **OK**. |
| 138 | + |
| 139 | +The following is the initial code in this class: |
| 140 | + |
| 141 | +```java |
| 142 | +package com.amazonaws.mobile.samples.mynotes.services.aws; |
| 143 | + |
| 144 | +import android.content.Context; |
| 145 | + |
| 146 | +import com.amazonaws.auth.AWSCredentialsProvider; |
| 147 | +import com.amazonaws.mobile.samples.mynotes.services.AnalyticsService; |
| 148 | +import com.amazonaws.mobileconnectors.pinpoint.PinpointConfiguration; |
| 149 | +import com.amazonaws.mobileconnectors.pinpoint.PinpointManager; |
| 150 | +import com.amazonaws.mobileconnectors.pinpoint.analytics.AnalyticsEvent; |
| 151 | +import java.util.Map; |
| 152 | + |
| 153 | +public class AWSAnalyticsService implements AnalyticsService { |
| 154 | + private PinpointManager pinpointManager; |
| 155 | + |
| 156 | + public AWSAnalyticsService(Context context, AWSService awsService) { |
| 157 | + AWSCredentialsProvider cp = awsService.getIdentityManager().getCredentialsProvider(); |
| 158 | + PinpointConfiguration config = new PinpointConfiguration(context, cp, awsService.getConfiguration()); |
| 159 | + pinpointManager = new PinpointManager(config); |
| 160 | + |
| 161 | + // Automatically record a startSession event |
| 162 | + startSession(); |
| 163 | + } |
| 164 | + |
| 165 | + @Override |
| 166 | + public void startSession() { |
| 167 | + pinpointManager.getSessionClient().startSession(); |
| 168 | + pinpointManager.getAnalyticsClient().submitEvents(); |
| 169 | + } |
| 170 | + |
| 171 | + @Override |
| 172 | + public void stopSession() { |
| 173 | + pinpointManager.getSessionClient().stopSession(); |
| 174 | + pinpointManager.getAnalyticsClient().submitEvents(); |
| 175 | + } |
| 176 | + |
| 177 | + @Override |
| 178 | + public void recordEvent(String eventName, Map<String, String> attributes, Map<String, Double> metrics) { |
| 179 | + final AnalyticsEvent event = pinpointManager.getAnalyticsClient().createEvent(eventName); |
| 180 | + if (attributes != null) { |
| 181 | + for (Map.Entry<String,String> entry : attributes.entrySet()) { |
| 182 | + event.addAttribute(entry.getKey(), entry.getValue()); |
| 183 | + } |
| 184 | + } |
| 185 | + if (metrics != null) { |
| 186 | + for (Map.Entry<String,Double> entry : metrics.entrySet()) { |
| 187 | + event.addMetric(entry.getKey(), entry.getValue()); |
| 188 | + } |
| 189 | + } |
| 190 | + pinpointManager.getAnalyticsClient().recordEvent(event); |
| 191 | + pinpointManager.getAnalyticsClient().submitEvents(); |
| 192 | + } |
| 193 | +} |
| 194 | +``` |
| 195 | + |
| 196 | +## Register the AWSAnalyticsService with the Injection Service |
| 197 | + |
| 198 | +Similar to the `AWSService` class, the `AWSAnalyticsService` class should be instantiated as a singleton object. You use the `Injection` service to do this. Open the `Injection` class, and replace the `initialize()` method with the following code: |
| 199 | + |
| 200 | +```java |
| 201 | +private static AWSService awsService = null; |
| 202 | + |
| 203 | +public static synchronized void initialize(Context context) { |
| 204 | + if (awsService == null) { |
| 205 | + awsService = new AWSService(context); |
| 206 | + } |
| 207 | + |
| 208 | + if (analyticsService == null) { |
| 209 | + analyticsService = new AWSAnalyticsService(context, awsService); |
| 210 | + } |
| 211 | + |
| 212 | + if (dataService == null) { |
| 213 | + dataService = new MockDataService(); |
| 214 | + } |
| 215 | + |
| 216 | + if (notesRepository == null) { |
| 217 | + notesRepository = new NotesRepository(dataService); |
| 218 | + } |
| 219 | +} |
| 220 | +``` |
| 221 | + |
| 222 | +You should also add the `AWSService` and `AWSAnalyticsService` classes to the list of imports for the class. You can easily do this using **Alt+Enter** in the editor. |
| 223 | + |
| 224 | +> **Tip** |
| 225 | +> |
| 226 | +> You can set up Auto Import to automatically import classes that you need. On Windows or Linux, you can find Auto Import under **File** > **Settings**. On a Mac, you can find it under **Android Studio** > **Preferences**. The Auto Import setting is under **Editor** > **General** > **Auto Import** > **Java**. Change **Insert imports on paste** to **All** and select the **Add unambiguous imports on the fly** option. |
| 227 | +
|
| 228 | +## Run the Project and Validate Results |
| 229 | + |
| 230 | +Run the application in the emulator using **Run** > **Run 'app'**. Add and delete some notes to generate some traffic that will appear in the Amazon Pinpoint console. |
| 231 | + |
| 232 | +To view the demographics and session events, run the following command: |
| 233 | + |
| 234 | +```bash |
| 235 | +$ amplify console analytics |
| 236 | +``` |
| 237 | + |
| 238 | +It can take up to 5 minutes for the first data to be shown in the graphs. You should see an increase in several graphs: |
| 239 | + |
| 240 | + |
| 241 | + |
| 242 | +Choose **Demographics** to view the demographics information. |
| 243 | + |
| 244 | + |
| 245 | + |
| 246 | +If you see data in each page, you have successfully added analytics to your app. Should you release your app on the App Store, you can return here to see more details about your users. |
| 247 | + |
| 248 | +Next Steps |
| 249 | +---------- |
| 250 | + |
| 251 | +* Continue by adding [Authentication](./auth.md). |
| 252 | +* Learn more about [Amazon Pinpoint](https://aws.amazon.com/pinpoint/). |
0 commit comments