ブログ記事

プッシュ通知のご紹介

2021/10/25

この度SeciossLinkでプッシュ通知認証を対応することになりました。

プッシュ通知の実装方法を紹介させていただきます。

Android篇

Android へプッシュ通知送信する場合、Firebase を利用します。正式の名称はFirebase Cloud Messaging(FCM)と言います。
※ Googleのサービスですが、iOSでも利用できます。AndroidとiOSアプリ同時開発する時サーバー側の実装が共通できる、楽になると思います。
※ iOS使う場合、Firebaseの設定に APNs の登録が必要です、今回ブログは割愛します。

Android アプリを実装する場合、Android Studioで開発することはほとんどです。
今回 Android Studio 3.1 を使いました。
既存プロジェクトにプッシュ通知機能を追加する場合、(新規プロジェクトの場合普通のプロジェクト作成した後)
メニューバーの「Tool」を開き、「Firebase」を選んでいただければと思います。
そして、「Cloud Messaging」をクリック「Connected」しましょう。(Google のアカウントが必要になります。)

今回のプッシュ通知はログインで利用するのでユーザー個別で送信します、
端末を特定するため「topic」方式ではなく「token」方式にまります。


トークンの取得は、下記のCallback関数を追加いただけます。

FirebaseMessaging.getInstance().getToken().addOnCompleteListener(task -> {
    if (task.isSuccessful()) {
        String token = task.getResult();
        Log.d("myTag", "myToekn: " + token);
    }
});

トークンはプッシュ通知利用開始前のアカウント登録時にサーバーへ送信し、
サーバー側はユーザーと紐付けます。

サーバー側実装する前に 送信用API のキーなどの情報を取得します。
Android Studio で Firebase と連携できた後、Google 側自動的にプロジェクトが生成されます。
Google Cloud Platform へログインし、連携するプロジェクトを選び、「サービス アカウント」を開きます。
自動で生成されたサービスアカウントが確認できます。
名前は「firebase-adminsdk-xxx」のフォーマットで表示されると思います。(xxx はランダム文字列です)
「キー」タブに移動し、「新しい鍵を作成」で鍵を追加します。JSONのキータイプがお勧めです。
キーをダウンロードすると、下記の模様です。

{
  "type": "service_account",
  "project_id": "fir-pushexample-yyy",
  "private_key_id": "74e6829f25778c8aba1390316453a060485a1310",
  "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhk...省略...aB2sC2mr2A=\n-----END PRIVATE KEY-----\n",
  "client_email": "firebase-adminsdk-xxx@fir-pushexample-yyy.iam.gserviceaccount.com",
  "client_id": "12345678901234567890",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-xxx%40fir-pushexample-yyy.iam.gserviceaccount.com"
}

続けて、サーバー側の実装ができるようになります(すみません、勝手に perl で実装しました)。

# Firebase Cloud Messaging 送信するため、認証用OAuth access_token を先に取得します。
# それから、FCMへプッシュ通知のリクエストを送信します。

# access_token 取得
my %header = ('alg' => 'RS256', 'typ' => 'JWT');
my %payload = (
    'iss' => "firebase-adminsdk-mjmi7@fir-pushexample-6b08d.iam.gserviceaccount.com",
    'scope' => "https://www.googleapis.com/auth/firebase.messaging",
    'aud' => "https://oauth2.googleapis.com/token",
    'exp' => time() + 3590,
    'iat' => time(),
);
my $jwt = OIDC::Lite::Model::IDToken->new(
    header => \%header,
    payload => \%payload,
    key => $key,
);
my $jwt_str = $jwt->get_token_string();
my %data_token = (
    'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
    'assertion' => $jwt_str,
);
$req_token = POST($url_token, \%data_token);
$res_token = $ua->request($req_token);
my $content_token = decode_json($res_token->content);
my $access_token = $content_token->{'access_token'};
$access_token =~ s/\.+$//g;

# message 送信
my $data_msg = {
    'message' => {
        'token' => $token,
        'data' => {
            'sessid' => $sessid,
            'username' => $username,
            # location キーは予約されるキーワードで使えません
        },
        # notification キーが送信されると、dataが取得できなくなる
    }
};
my %header_msg = (
'Content-Type' => 'application/json',
'Authorization' => "Bearer $access_token",
);
$req_msg = POST($url_msg, %header_msg, Content => encode_json($data_msg));
$res_msg = $ua->request($req_msg);

最後では Android 側受け取れ処理を実装すれば完成となります。

public class MyFcmService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);

        // notification キーが送信されると、dataが取得できなくなる
        RemoteMessage.Notification notification = remoteMessage.getNotification();
        if (null != notification) {
            Log.d("myTag", notification.toString());
        }

        // data キーの内容が受けられます
        Map<String, String> data = remoteMessage.getData();
        Log.d("myTag", "myMessage: " + data.toString());

        long[] pattern = {0, 1000, 500, 1000};
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        NotificationChannel notificationChannel = new NotificationChannel("NOTIFICATION_CHANNEL_ID", "NOTIFICATION_CHANNEL_NAME", NotificationManager.IMPORTANCE_HIGH);
        notificationChannel.setDescription("");
        notificationChannel.enableLights(true);
        notificationChannel.setLightColor(Color.RED);
        notificationChannel.setVibrationPattern(pattern);
        notificationChannel.enableVibration(true);
        notificationChannel.setBypassDnd(true);
        manager.createNotificationChannel(notificationChannel);

        // プッシュ通知をタッチする時起動する画面を定義します
        Intent resultIntent = new Intent(this, MainActivity.class);
        resultIntent.putExtra("EXTRA_KEY_SESSID", sessid);
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addNextIntentWithParentStack(resultIntent);
        PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "NOTIFICATION_CHANNEL_ID");
        notificationBuilder
                .setContentTitle("プッシュ通知タイトル")
                .setContentText("プッシュ通知内容")
                .setPriority(NotificationCompat.PRIORITY_HIGH)
                .setCategory(NotificationCompat.CATEGORY_MESSAGE)
                .setDefaults(Notification.DEFAULT_ALL)
                .setColor(ContextCompat.getColor(this, R.color.purple_500))
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.drawable.ic_launcher_background)
                .setContentIntent(resultPendingIntent)
                .setAutoCancel(true);

        manager.notify(1000, notificationBuilder.build());
    }
}

AndroidManifest.xml に下記の定義追加必要になります。

<application
    android:allowBackup="false"
    android:icon="@drawable/ic_secioss"
    android:label="@string/appname">
    <service
        android:name=".MyFcmService"
        android:stopWithTask="false"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT"/>
        </intent-filter>
    </service>
    <meta-data
        android:name="com.google.firebase.messaging.default_notification_channel_id"
        android:value="MyPushNotification" />

実装はこれで以上になります。

プッシュ通知認証使うために、事前にAndroidアプリをダウンロードし、アカウントの登録を済ませて下さい。
登録方法は省略させていただきます。登録すると端末特定するためのトークンがサーバーに送信されます。

認証の流れとしては、

1 ユーザー プッシュ通知ログイン画面を開き、ユーザーIDを入力

2 サーバー ユーザーIDを基でで送信用トークンを取得

3 サーバー FCM送信用 access_token を取得

4 サーバー 認証用ヘッダー( access_token )と送信内容(セッションID)を添付し、トークン(Firebase)への送信リクエストを投げ、送信結果をブラウザまでに返す

5 ブラウザ 送信成功の結果が受けた後にサーバーへ認証可否のポーリングを始め

6 Android アプリ プッシュ通知が 端末までに届く、ユーザー許可を求む

7 ユーザーログイン許可をクリック

8 Android アプリ ログイン許可の結果とプッシュ通知の内容(セッションID)をサーバーへ送信

9 サーバー ログインを許可の結果をポーリング中のブラウザまでに返す

10 ブラウザ ポーリングの結果を基で、ログイン成功の画面に移す。

これで以上になります。

最新記事

カテゴリ

アーカイブ

%d人のブロガーが「いいね」をつけました。