# \[Android]プッシュ通知を受信する

プッシュ通知を受信したい場合は、リモート通知機能を利用することで実現可能です。

リモート通知機能は、KARTE SDKの導入及び`notifications` モジュールを導入することで利用可能です。

* 参考：[SDKを導入する](/android-sdk/setup-android-sdk.md)

なお KARTE ではプッシュ通知の送信に、Firebase Cloud Messaging（以下FCM）を利用しています。\
そのためFCM経由でプッシュ通知を送信するために各種設定を行う必要があります。

また受信側アプリケーションでも FCM SDK の導入が必要となります。

## 導入手順

### 1. FCM SDK を導入する

1. SDKを導入する\
   導入に関しては、下記ドキュメントをご覧ください。\
   [Set up a Firebase Cloud Messaging client app on Android](https://firebase.google.com/docs/cloud-messaging/android/client)
2. Notification Composer で通知のテストを行う\
   Firebase の Notification Composer から通知メッセージを送信し、メッセージが受信できるか確認してください。\
   [Send a notification message](https://firebase.google.com/docs/cloud-messaging/android/first-message#send_a_test_notification_message)

### 2. サービスアカウントの設定を行う

KARTEからFCMに対して通知の送信リクエストを行うために、KARTE側にサービスアカウントの設定を行う必要があります。\
[サービスアカウントを設定する](/app-send-notification/app-setup-service-account.md)

### 3. KARTE SDK を導入する

アプリの `build.gradle (app)` を任意のエディタで開き、`dependencies` ブロックに `notifications` モジュールを追加します。

{% code title="build.gradle" overflow="wrap" %}

```groovy
dependencies {
  implementation 'io.karte.android:notifications:2.+'
}
```

{% endcode %}

## 実装手順

### 1. FCMトークンを送信する

KARTE からプッシュ通知を送信するためには、FCMトークンが必要となります。\
そのためアプリケーションからKARTEにFCMトークンを送信する処理を実装します。

`FirebaseMessagingService` クラスを継承したクラスを作成し、`onNewToken()` メソッド内にトークンの送信処理を実装します。\
※SDKの[enabledFCMTokenResend](https://plaidev.github.io/karte-sdk-docs/android/notifications/latest/notifications/io.karte.android.notifications/-notifications-config/index.html) が有効な場合にはSDKの初期化時にもハンドリングされます。iOSではSDKの初期化時にハンドリングされる挙動のため、挙動を揃えるために[enabledFCMTokenResend](https://plaidev.github.io/karte-sdk-docs/android/notifications/latest/notifications/io.karte.android.notifications/-notifications-config/index.html)の有効化を推奨します

{% tabs %}
{% tab title="Kotlin" %}
{% code title="MyFirebaseMessagingService.kt" overflow="wrap" %}

```kotlin
import com.google.firebase.messaging.FirebaseMessagingService
import io.karte.android.KarteApp
import io.karte.android.notifications.registerFCMToken

class MyFirebaseMessagingService : FirebaseMessagingService() {
  override fun onNewToken(token: String) {
    super.onNewToken(token)
    KarteApp.registerFCMToken(token)

    // Notificationsクラスのメソッドを直接呼ぶことも可能です。
    // Notifications.registerFCMToken(token)
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code title="MyFirebaseMessagingService.java" overflow="wrap" %}

```java
import com.google.firebase.messaging.FirebaseMessagingService;
import io.karte.android.notifications.Notifications;

public class MyFirebaseMessagingService extends FirebaseMessagingService {
  @Override
  public void onNewToken(String token) {
    super.onNewToken(token)
    Notifications.registerFCMToken(token)
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**古い Firebase Cloud Messaging SDK を利用している場合**

v17.1.0 未満の Firebase Cloud Messaging SDK を利用してる場合は、代わりに `FirebaseInstanceIdService` を使い `onTokenRefresh()` で `trackFcmToken()` を呼び出してください。
{% endhint %}

また、KARTE SDK では FCM トークンを最新に保つために、アプリ起動時に自動で送信します。

[\[参考\]FCM登録トークンや、アプリPUSH通知許可設定がKARTEに送信されるタイミング](https://support.karte.io/post/38slBGumICBZdaURAESXvU#1-0)

### 2. 通知の表示処理を実装する

#### 受信したメッセージのハンドリング

※プッシュ通知のタップ時に、任意の画面に遷移させる等の処理をさせたい場合には必須の実装です。

受信した通知を通知ドロワーに表示するために、`FirebaseMessagingService` クラスを継承したクラスの `onMessageReceived()` メソッド内に、下記の実装を行う必要があります。\
またこの実装をすることで通知タップ時に自動でイベントが発生するようになります。\
※Messageからの送信の場合は`mass_push_click` 、それ以外での送信の場合は`message_click`が発生します。

{% tabs %}
{% tab title="Kotlin" %}
{% code title="MyFirebaseMessagingService.kt" overflow="wrap" %}

```kotlin
class MyFirebaseMessagingService : FirebaseMessagingService() {
  override fun onMessageReceived(remoteMessage: RemoteMessage) {
    // handled の値が `true` の場合は KARTE を起点に送信されたプッシュ通知
    // `false` の場合は KARTE 以外を起点に送信されたプッシュ通知
    val handled = MessageHandler.handleMessage(this, remoteMessage)
      if (!handled) {
      // KARTE以外のシステムを起点に送信されたプッシュ通知の場合の処理を書く
    }
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code title="MyFirebaseMessagingService.java" overflow="wrap" %}

```java
public class MyFirebaseMessagingService extends FirebaseMessagingService {
  @Override
  public void onMessageReceived(RemoteMessage remoteMessage) {
    // handled の値が `true` の場合は KARTE を起点に送信されたプッシュ通知
    // `false` の場合は KARTE 以外を起点に送信されたプッシュ通知
    boolean handled = MessageHandler.handleMessage(this, remoteMessage);
    if (!handled) {
      // KARTE以外のシステムを起点に送信されたプッシュ通知の場合の処理を書く
    }
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**通知タップ時のデフォルトの遷移先について**

通知メッセージにディープリンクの指定がされていないもしくは不正なディープリンクが指定されていた場合は、デフォルトでアプリのTOP画面に遷移します。

デフォルトの遷移先を変更したい場合は、 `MessageHandler.handleMessage()` の第3引数に `Intent` 指定することで変更することが可能です。
{% endhint %}

{% hint style="warning" %}
**Android 11以降における通知タップ時の外部アプリ起動について**

`targetSdkVersion 30`以上のアプリの場合、Android 11以降の端末ではmanifestでの宣言無しには外部アプリのActivity情報を取得できないため、通知タップ時に直接外部アプリを起動できず、デフォルトの遷移を行うケースがあります。

* [Package visibility filtering on Android | Android Developers](https://developer.android.com/training/package-visibility)

[notifications: 2.8.0](/android-sdk/release-notes-android-sdk.md#notifications-280)以降では、デフォルトで`http/https`のスキーマに関して起動できるよう、manifestに宣言を追加しています。\
notifications: 2.8.0未満を使用する場合や、`http/https`以外のスキーマの外部アプリを起動したい場合は、`AndroidManifest.xml`に`queries`タグを宣言するか、一度アプリを起動してから外部アプリを起動する必要があります。
{% endhint %}

またKARTEの管理画面上で設定した通知メッセージのurl等の値は、[extractKarteAttributes](https://plaidev.github.io/karte-sdk-docs/android/notifications/latest/notifications/io.karte.android.notifications/-message-handler/-companion/extract-karte-attributes.html)を介して参照可能です。\
その他の変数の取得については[デフォルト変数とペイロード値の対応関係について](https://app.developers.karte.io/android-sdk/pages/fgFWdQwuFelO4w0Maife#デフォルト変数とペイロード値の対応関係について)をご確認ください。

別途通知の表示をカスタマイズする場合は、[通知の表示をカスタマイズする](/android-sdk-appendix/appendix-customize-notification-android-sdk.md)を御覧ください。

#### 通知アイコン・アイコンカラーの設定

通知のアイコン・ラージアイコン・カスタムカラーを設定するには、`AndroidManifest.xml` の `application` タグ内に下記を追加します。

{% code title="AndroidManifest.xml" overflow="wrap" %}

```xml
<!-- setSmallIcon に対応 -->
<meta-data
    android:name="io.karte.android.Tracker.notification_icon"
    android:resource="@drawable/ic_notification" />

<!-- setLargeIcon に対応 -->
<meta-data
    android:name="io.karte.android.Tracker.notification_large_icon"
    android:resource="@drawable/ic_notification_large" />

<!-- setColor に対応 -->
<meta-data
    android:name="io.karte.android.Tracker.notification_color"
    android:resource="@color/colorAccent" />
```

{% endcode %}

次に `src/drawable` に `android:resource` で指定したものに対応する画像ファイルを配置します。

{% hint style="warning" %}
**通知アイコンのデフォルト画像について**

notification\_icon の設定を行わなかった場合、デフォルトではアプリのランチャーアイコンが挿入されます。\
ただし、デフォルトのランチャーアイコンにアルファチャンネルが含まれない場合は、アイコンがグレーになってしまいます。

回避するには、アルファチャンネルを利用して描かれたアイコンを `io.karte.android.Tracker.notification_icon` に指定してもらうことで解決できます。
{% endhint %}

#### 通知チャンネルの作成

通知テンプレート内でチャンネルの指定を行う場合は、あらかじめチャンネルを作成しておく必要があります。

{% tabs %}
{% tab title="Kotlin" %}
{% code overflow="wrap" %}

```kotlin
val channel = NotificationChannel("my_channel", "通知テストチャンネル", NotificationManager.IMPORTANCE_DEFAULT)
channel.description = "テストの説明です"
channel.setShowBadge(true)

// create or update the Notification channel
val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE)
if (notificationManager is NotificationManager) {
  notificationManager.createNotificationChannel(channel)
}
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code overflow="wrap" %}

```java
NotificationChannel channel = new NotificationChannel("my_channel", "通知テストチャンネル", NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription("テストの説明です");
channel.setShowBadge(true);

// create or update the Notification channel
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**指定されたチャンネルが存在しない場合**

通知テンプレートにて指定されたチャンネルが存在しない場合は、SDK 内で作成したデフォルトチャンネル (`krt_default_channel`) を指定して通知を行います。
{% endhint %}

## 動作確認

最後に正しく導入が行われているか確認を行うためにテストメッセージを送信して確認を行います。

詳細については、下記ドキュメントをご覧ください。\
[テストメッセージを送信する](/app-send-notification/app-test-notification.md)

## トラブルシューティング

プッシュ通知に問題がある場合は、[KARTE for Appプッシュ通知で問題が発生した時のチェックリスト](https://support.karte.io/post/5IUmM2QOEjJjyCE5Lq9aEf)を参考にしてください。

**What’s Next**

通知の表示を独自にカスタマイズしたい場合は、以下のドキュメントをご覧ください。

* [通知の表示をカスタマイズする](/android-sdk-appendix/appendix-customize-notification-android-sdk.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://app.developers.karte.io/android-sdk/notification-android-sdk.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
