前提・実現したいこと
JavaでPushyを使用し、iOS端末にVOIP通知を送信したい。
発生している問題・エラーメッセージ
検証用端末で取得したデバイストークンを直接指定してJavaから送信を試みると「DeviceTokenNotForTopic」となってしまう。
該当のソースコード
内容はサンプルほぼそのままです。
Java
1final ApnsClient apnsClient = new ApnsClientBuilder() 2 .setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST) 3 .setSigningKey(ApnsSigningKey.loadFromPkcs8File(new File("p8ファイルパス"), 4 "アカウントに割り当てられているTeamID", "p8ファイル作成時に発行されたキー")) 5 .build(); 6 7final String tokenString = "検証用端末で取得できたデバイストークン(64文字)"; 8final String topic = "Bundle IDと同じもの(例:com.example.app.test)"; 9 10final ApnsPayloadBuilder payloadBuilder = new SimpleApnsPayloadBuilder(); 11payloadBuilder.setAlertBody("Example!"); 12payloadBuilder.setAlertTitle("Title!"); 13final String payload = payloadBuilder.build(); 14final String token = TokenUtil.sanitizeTokenString(tokenString); 15 16final SimpleApnsPushNotification pushNotification; 17 18pushNotification = new SimpleApnsPushNotification(token, topic, payload, Instant.now().plus(Duration.ofDays(1L)), DeliveryPriority.IMMEDIATE, PushType.VOIP); 19 20final PushNotificationFuture<SimpleApnsPushNotification, PushNotificationResponse<SimpleApnsPushNotification>> 21 sendNotificationFuture = apnsClient.sendNotification(pushNotification); 22 23try { 24final PushNotificationResponse<SimpleApnsPushNotification> pushNotificationResponse = 25 sendNotificationFuture.get(); 26if (pushNotificationResponse.isAccepted()) { 27 System.out.println("Push notification accepted by APNs gateway."); 28} else { 29 System.out.println("Notification rejected by the APNs gateway: " + 30 pushNotificationResponse.getRejectionReason()); // ここでDeviceTokenNotForTopic発生 31 32 pushNotificationResponse.getTokenInvalidationTimestamp().ifPresent(timestamp -> { 33 System.out.println("\t…and the token is invalid as of " + timestamp); 34 }); 35} 36} catch (final ExecutionException e) { 37System.err.println("Failed"); 38e.printStackTrace(); 39} catch (InterruptedException e) { 40e.printStackTrace(); 41}
念のため、Cordova側のソースコードです。(こちらも最低限のサンプルコードほぼそのままです)
JavaScript
1function onDeviceReady() { 2 cordova.plugins.backgroundMode.enable(); 3 4 var push = VoIPPushNotification.init(); 5 var cordovaCall = cordova.plugins.CordovaCall; 6 7 push.on('registration', function(data) { 8 $('#content input').val(data.deviceToken); // ここで取得できたデバイストークンをJava側にベタで入れています(今は動作確認をしたいだけなので) 9 $('#json textarea').val(JSON.stringify(data)); 10 }); 11 push.on('notification', function(data) { 12 alert(data); 13 }); 14 push.on('error', function(e) { 15 alert(e); 16 }); 17 cordovaCall.on('receiveCall', function(e) { 18 alert("receiveCall"); 19 alert(e); 20 }); 21 cordovaCall.on('hangup', function(e) { 22 alert("hangup"); 23 alert(e); 24 }); 25} 26var event = typeof cordova === 'undefined' ? 'DOMContentLoaded' : 'deviceready'; 27document.addEventListener(event, onDeviceReady, false);
併せてご教示いただきたいこと
そもそも証明書周りの理解があっているか?
CSR:AppleDeveloperProgramで証明書を発行するためのもの
Certificates:証明書
Identifiers:アプリ
Devices:検証用などの端末のUDID
Provisioning Profile:IdentifiersとDevicesを紐付けたもの
ただ、同じAppleDeveperProgramで開発用証明書・本番用証明書などは上限(2枚?)があるため、複数のアプリを同一名義で配信したい場合、Identifiersはアプリ数分(アプリのBundleIDごとに)作成しますが、Certificatesは使いまわして良い、という理解であっていますか?
※法人アカウント使用
アプリに証明書を設定するまでの流れの認識があっているか?
基本的なフローは
- CRSを作成
- 共有用の
・iOS App DevelopmentのCertificates
・iOS Distribution (App Store and Ad Hoc)のCertificates
を作成(発行上限あり。2枚?)
3. アプリのIdentifiersを作成
4. Deviceを登録
5. #4で登録した紐付けたいデバイス・#3で作成したIdentifiers・#2の証明書を選択してProvisioning Profileを作成
となり、アプリ配信には#2と#5を使用。2つ目のアプリからは3以降を実施する、と理解しています。
但し、PUSH通知を受信するアプリの場合、
- 基本フローで実施
- 基本フローで実施
- アプリのIdentifiersをPushNotificationsをONにして作成
- #3のIdentifiersのPushNotificationsに開発用・本番用それぞれの1のCSR(開発・本番同じものでも良い?)を設定し、開発・本番それぞれのCertificatesを生成。 ←これは直接CSRから作るCertificates(#2)のような発行枚数の上限はない?
- Deviceを登録
- #5で登録した紐付けたいデバイス・#3で作成したIdentifiers・#2で作成したCertificatesを選択してProvisioning Profileを作成
となり、2つ目のアプリ配信には#2と#6を使用、2つ目のアプリからは3以降を実施する、と理解しています。
ただ、#4の証明書はこの証明書をもとにp12ファイルを作成し、PUSH通知送信のバックエンドシステムで使用するものだという認識でしたが(既存アプリはそのように使用しています)、p8ファイル+キーでの認証の場合、#4の証明書を使うことがなく、#4の手順自体が不要になったのでしょうか、、、?
現在設定している証明書等があっているか?
現状、
- 【基本的なフロー】手順#2で作成した共通のiOS App DevelopmentのCertificates
- 【PUSH通知を受信するアプリの場合】手順#5で作成したProvisioning Profile
を使用していますが、これがそもそも誤っているということはないでしょうか。
試したこと
DeviceTokenNotForTopicはTopicIDと証明書のBundleIDの不一致が原因という記事を沢山見ましたが、
CertificatesにはBundleIDを持っていないという理解なので、
- Provisioning Profile作成時に指定したIdentifiersの「Bundle ID」(Explicit)
- アプリ本体のAppID(Cordovaの場合、config.xmlの
xml
1<widget xmlns="http://www.w3.org/ns/widgets" xmlns:android="http://schemas.android.com/apk/res/android" id="ここで指定している値" version="1.0">
が一致していることは何度も確認しました。
新規作成分の証明書などをすべて削除して再度作り直しもしましたが状況は変わりません。
補足
- Java環境:Java1.8, SpringBoot 2.4, Pushy 0.15.0(Windows10環境、サーバはAmazonLinux2)
- iOSアプリ環境:Monaca上でCordova10で実装(現状はコンテンツなしでデバイストークンの発行とVOIP受信時の処理のみ)VOIP用のデバイストークンの発行はcordova-plugin-callkit(ver1)を使用、検証端末はiOS 13.3.1(iPhoneX)
長くなってしまいすみません。
他に必要な情報があればご指示ください。
あなたの回答
tips
プレビュー