Wednesday, June 19, 2019

Liferayモバイルアプリにプッシュ通知を実装する

こんにちは。おおたにです。

今回は、Liferayモバイルアプリへのプッシュ通知組み込みについて紹介します。Liferayのモバイル対応については別の記事「Liferay Screensでモバイルアプリを作ってみよう(初級編)」「Liferay Screensでモバイルアプリを作ってみよう(ログイン画面実装編)」で紹介していますが、今回はLiferay Screensを使って開発したAndroidアプリにプッシュ通知機能を実装してみようと思います。

必要なもの


モバイルへのプッシュ通知を実現するためには、以下の3つが必要です。
  1. プッシュ通知サービスの設定
    • Android : Firebase Cloud Messaging(FCM)
    • iOS : Apple Push Notification Service(APNS)
  2. モバイルアプリのプッシュ通知対応
  3. プッシュ通知を管理するアプリケーション
    • インストールされたモバイルアプリのデバイストークンの収集
    • プッシュ通知の内容と配信先の管理
    • プッシュ通知の配信(正確にはプッシュ通知サービスへの配信依頼)
今回は3.としてLiferay PushプラグインをインストールしたLiferayを利用します。このプラグインはEnterprise Edition(Liferay DXP)専用ですので、Community Edition(Liferay Portal CE)をお使いの方は、Amazon Simple Notification Service(SNS)等を利用してプッシュ通知管理アプリを開発するか、モバイル組み込みに対応したサードパーティのプッシュ通知配信サービスを利用する必要があります。

では、実際の実装について見ていきましょう。

プッシュ通知サービスの設定


今回はAndroidアプリにプッシュ通知を送信するため、Firebase Cloud Messaging(FCM)を利用します。まずはFirebaseの設定から行います。

1. Firebaseコンソールにログインする

2. 「新しいプロジェクト」をクリックし、プロジェクト名等を適当に入力してプロジェクトを作成する

3. 「開始するにはアプリを追加してください」のAndroidアイコンをクリックし、Androidアプリのパッケージ名(アプリケーションID)を入力してアプリを登録します。詳細な手順はFirebaseのドキュメントに記載されています。登録の後、以下の情報をコピーしておきます。
  • google-services.json
  • 登録したアプリのクラウドメッセージングのサーバーキーと送信者ID

モバイルアプリのプッシュ通知対応


続いて、モバイルアプリにプッシュ通知の対応を実装します。まずは「Liferay Screensでモバイルアプリを作ってみよう(ログイン画面実装編)」でLiferay Screensを使ったアプリを開発し、追加で以下の実装を行います。

1. Androidプロジェクトの app フォルダに google-services.json をコピーする

2. プロジェクトルートの build.gradle に以下のclasspathを追加する
buildscript {
 ...
 dependencies {
  ...
  classpath 'com.google.gms:google-services:4.2.0'
 }
}

3. app フォルダの build.gradle の最後に以下の行を追加する
apply plugin: 'com.google.gms.google-services'

4. app フォルダの build.gradle に以下のimplementationを追加し、画面上部に表示されるSync Nowをクリックする
apply plugin: 'com.android.application'
...
dependencies {
 ...
 implementation 'com.google.firebase:firebase-messaging:17.6.0'
}

5. AndroidManifest.xml に以下の内容を追加する
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>

<receiver
    android:name=".PushReceiver"
    android:permission="com.google.android.c2dm.permission.SEND">
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
        <category android:name="com.liferay.mobile.push"/>
    </intent-filter>
</receiver>

<service android:name=".PushService"/>

<meta-data
    android:name="com.google.firebase.messaging.default_notification_channel_id"
    android:value="@string/fcm_fallback_notification_channel_label" />

6. res/values/strings.xml に以下の行を追加する
<string name="fcm_sender_id">FCMでコピーした送信者ID</string>

7. MainActiity.java のベースクラスを AppCompatActivity から PushScreensActivity に変更し、以下の実装を追加する
@Override
protected Session getDefaultSession() {
   return SessionContext.createSessionFromCurrentSession();
}

@Override
protected void onPushNotificationReceived(final JSONObject jsonObject) {
   LiferayLogger.i("Push notification received: " + jsonObject.toString());
}

@Override
protected void onErrorRegisteringPush(final String message, final Exception e) {
   // Do nothing
}

@Override
protected String getSenderId() {
   return getResources().getString(R.string.fcm_sender_id);
}

8. MainActiity.java の onCreate の実装を以下のように変更する(loadStoredCredentialsAndServerの後にベースクラスのonCreateを呼ぶのがポイントです)
public void onCreate(Bundle savedInstanceState) {
    SessionContext.loadStoredCredentialsAndServer(CredentialsStorageBuilder.StorageType.SHARED_PREFERENCES);
    super.onCreate(savedInstanceState);
    if (!SessionContext.isLoggedIn()) {
        startActivity(new Intent(getApplication(), LoginActivity.class));
    } else {
        setContentView(R.layout.activity_main);
        WebScreenlet screenlet = findViewById(R.id.web_screenlet);
        screenlet.setListener(this);
        WebScreenletConfiguration webScreenConfiguration = new WebScreenletConfiguration.Builder(LiferayServerContext.getServer() + "/web/guest/home")
                .setWebType(WebScreenletConfiguration.WebType.LIFERAY_AUTHENTICATED).load();
        screenlet.setWebScreenletConfiguration(webScreenConfiguration);
        screenlet.load();
        LiferayLogger.i("##### device token : " + FirebaseInstanceId.getInstance().getToken());
    }
}

9. PushService.java を MainActivity.java と同じフォルダに作成し、以下のとおり実装する(プッシュ通知受信時の処理として、Androidの通知エリアに通知を表示する処理を実装しています)
public class PushService extends AbstractPushService {
    @Override
    protected void processJSONNotification(JSONObject json) throws JSONException {
        NotificationCompat.Builder builder;
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String channelId = getResources().getString(R.string.fcm_fallback_notification_channel_label);
            if (notificationManager.getNotificationChannel(channelId) == null) {
                notificationManager.createNotificationChannel(new NotificationChannel(channelId, channelId, NotificationManager.IMPORTANCE_HIGH));
            }
            builder =  new NotificationCompat.Builder(this, channelId);
        } else {
            builder = new NotificationCompat.Builder(this);
        }
        builder.setContentTitle(getString(json, "title"))
                .setContentText(getString(json, "body"))
                .setAutoCancel(true)
                .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)
                .setSmallIcon(R.drawable.liferay_glyph)
                .setPriority(Notification.PRIORITY_HIGH);
        notificationManager.notify(1, builder.build());
    }

    private String getString(final JSONObject json, final String element) throws JSONException {
        return json.has(element) ? json.getString(element) : "";
    }
}

10. PushReceiver.java を MainActivity.java と同じフォルダに作成し、以下のとおり実装する
public class PushReceiver extends AbstractPushReceiver {
    @NonNull
    @Override
    protected Class getPushServiceClass() {
        return PushService.class;
    }
}

ビルドに失敗する場合は、依存するライブラリのバージョン齟齬等を確認してください。sdkVersionやdependencies内のライブラリバージョンを変更する等の対応が必要なことがあるかもしれません。

Liferay Pushの設定


最後に、Liferay側の設定を行います。設定自体はいたってシンプルです。

1. Liferay MarketplaceからLiferay Pushをダウンロードし、ファイルをLiferayの deploy フォルダにコピーしてインストールする

2. インストール完了後、Liferayを再起動する

3. 管理者としてLiferayにログインし、Control Panel -> Configuration -> System Settings -> Platform -> Notifications -> Android のAPI Key欄に、FCMでコピーしたサーバーキーを入力してUpdateをクリックする

テストしてみよう


では、実際にテストしてみましょう。テストの手順は以下のとおりです。

1. モバイルアプリを起動し、Liferayにログインする

2. 管理者としてブラウザでLiferayのにログインし、Control Panel -> Configuration -> Push Notifications -> Devices に、モバイルアプリにログインしたユーザ名と併せてデバイストークン/Platform(今回はAndroid)が記録されていることを確認する(アプリ側でデバイストークンをログ出力する等しておくと確認しやすい)


3. Testタブに移動し、Message欄にプッシュ通知のペイロードをJSON形式で入力してSendをクリックする(今回はモバイルアプリ側でtitleとbodyを表示するよう実装したので、以下のようなプッシュ通知ペイロードを指定する)
{
  "title": "プッシュ通知テスト",
  "body": "これはプッシュ通知のテストです。"
}

4. Android端末側でプッシュ通知を受信したことを確認する(今回のサンプルコードではAndroidの通知エリアに通知が表示されます)



今回の紹介は以上になります。実用的なプッシュ通知の実装には、モバイルアプリのバックグラウンド/フォアグラウンドの判定や、それに応じてプッシュ通知の通知方法を変えるなどの考慮が必要ですが、エッセンシャルな部分は上記記事の内容でカバーできているかと思います。
また、実際にプッシュ通知を配信するためには PushNotificationsDeviceLocalService を利用する必要がありますので、こちらのドキュメントを参考にしてください。

No comments: