Android アプリで AWS pinpoint を使って Analytics 情報を収集する 〜アプリコーディング編

[Backend 準備編](https://qiita.com/Idenon/items/8761b2d1e3155f5b7955)の続き。前回の内容が終わっていること前提です。
手順の記述がメイン、説明は端折り気味。

## 環境・言語
Android Studio 3.3.2
Kotlin 1.3.21

## 1. Backend アクセスのためのライブラリとか許可準備
app/gradle の dependencies に以下を implementation。

```groovy:app/gradle
dependencies {
  implementation 'com.amazonaws:aws-android-sdk-pinpoint:2.13.+'
  implementation ('com.amazonaws:aws-android-sdk-mobile-client:2.13.+@aar') { transitive = true }
}
```

マニフェストに以下を記述。

```xml:AndroidManifest.xml
 <uses-permission android:name="android.permission.INTERNET"/>
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
```

## ２． セッションの開始
Analytics 情報の取得や送信のために、キャプチャーセッションを開始します。
タイミングについて詳しくは公式ドキュメントを見てほしいですが、ここではアクティビティの onCreate() で開始します。
また、onDestroy() でセッションを停止します。

```kotlin:MainActivity.kt
import android.content.Context
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.amazonaws.mobileconnectors.pinpoint.PinpointManager
import com.amazonaws.mobile.client.AWSMobileClient
import com.amazonaws.mobile.client.Callback
import com.amazonaws.mobileconnectors.pinpoint.PinpointConfiguration
import com.amazonaws.mobile.client.UserStateDetails
import com.amazonaws.mobile.config.AWSConfiguration

class MainActivity : AppCompatActivity() {

    lateinit var pinpointManager: PinpointManager

    fun getPinpointManager(applicationContext: Context): PinpointManager {
        if (!this::pinpointManager.isInitialized) {
            // Initialize the AWS Mobile Client
            val awsConfig = AWSConfiguration(applicationContext)
            AWSMobileClient.getInstance()
                .initialize(applicationContext, awsConfig, object : Callback<UserStateDetails> {
                    override fun onResult(userStateDetails: UserStateDetails) {
                        Log.i("INIT", userStateDetails.userState.toString())
                    }

                    override fun onError(e: Exception) {
                        Log.e("INIT", "Initialization error.", e)
                    }
                })

            val pinpointConfig = PinpointConfiguration(
                applicationContext,
                AWSMobileClient.getInstance(),
                awsConfig
            )

            pinpointManager = PinpointManager(pinpointConfig)
        }

        return pinpointManager
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val pinpointManager = getPinpointManager(applicationContext)
        pinpointManager.sessionClient.startSession()
    }

    override fun onDestroy() {
        super.onDestroy()

        pinpointManager.sessionClient.stopSession()
        pinpointManager.analyticsClient.submitEvents()
    }
}
```

これで Analytics のセッションが開始されます。
AWS pinpoint のダッシュボードから設定したプロジェクトのページに入ると、Analytics 情報を確認できるようになっています。


## 3. Custom Event を収集する
カスタムのイベントを収集したい場合は以下のようなメソッドを作り、好きなタイミングで呼び出せばいいです。

```kotlin
    private fun button1Event(){
        val event: AnalyticsEvent? =
            pinpointManager.analyticsClient.createEvent("Button1 Click")
                .withAttribute("Button1Attribute", "Button1AttributeValue")
                .withMetric("Button1Metric", Math.random())

        pinpointManager.analyticsClient?.recordEvent(event)
        pinpointManager.analyticsClient?.submitEvents()
    }
```

createEvent の中でイベント名とかメトリック名とかアトリビュート名とか新しく作ってます。
（これはボタンを押した時に呼び出すようにしたのでそういう名前にしました）

recordEvent でイベントの記録をして、submitEvents で AWS pinpoint へ送信しているものと思います。
今回は submitEvents をここで呼んでいますが、通信タイミングの調整がしたい場合は別の場所へ移動させれば良いかと思います。


# あとがき
初めてアプリに AWS サービスを組み込みましたが、思ったよりうまくいったので調子に乗って資料化しました。
Java のコード例は公式ドキュメントに乗ってますが Kotlin のはあんまりないので、そのへん参考になれば幸いです。

# 参考文献
Amplify Android SDK - Analytics
https://aws-amplify.github.io/docs/android/analytics


# 04/25 追記
ご指摘を頂き、MainActivity.kt のコードを修正しました。

* クラスメンバ pinpointManager を Non-Nullable にする
* getPinpointManager メソッドの最初で pinpointManager が初期化済みかどうかを判断する（`this::pinpointManager.isInitialized`）
* 初期化されていない場合にメソッドの中の内容を実行する

こうすることにより、大量の ? を消すことができました。（Nullable じゃなくなったから）
また以前のコードでは、pinpointManager が初期化済み（PinpointManager 取得済み）の時に getPinpointManager を再度呼ぶとクラッシュする問題がありましたが、それが解決されています。

ご指摘ありがとうございました。