手軽く iOS push 通知

Bark というアプリを利用

https://www.jianshu.com/p/dacb3c4a7c9a

ダウンロード：

https://apps.apple.com/jp/app/bark-%E7%BB%99%E4%BD%A0%E7%9A%84%E6%89%8B%E6%9C%BA%E5%8F%91%E6%8E%A8%E9%80%81/id1403753865

ソースはこちら

https://github.com/Finb/Bark

サーバーのソースはこちら

https://github.com/Finb/bark-server

サーバーは Golang 製なので、自分は Golang 分からない。Java で実装可能かを試したらできました。

iOS push 通知必要な情報はここに公開されている：

https://day.app/2018/06/bark-server-document/

Key ID: LH4T9V5U4R
TeamID: 5U8LBRXG3A
AuthKey_LH4T9V5U4R_5U8LBRXG3A.p8　←　ファイルをダウンロード

プッシュサーバーの実装はこちらを参考

https://reftec.work/posts/2020/12/219/

利用するライブラリーはこちら

https://github.com/jchambers/pushy

尚、プッシュするために、お持ちの iOS デバイストークンが必要なので、Docker で上記のサーバーを起動し、iOS 端末から自分のサーバーを追加し、１回プッシュ通知を試す。
そうすると、bark-data のフォルダに、bark.db というファイルに、デバイストークンが保存されているので、boltbrowser というソフトで見ることができる。

https://github.com/br0xen/boltbrowser

push server の java ソース（pushy ほぼそのまま）
.p8 ファイルは、作者のサイトからダウンロード。有効期限は無限らしい。

```java
package jp.co.syslinks.ios_push;

import java.io.File;
import java.util.concurrent.ExecutionException;

import com.eatthepath.pushy.apns.ApnsClient;
import com.eatthepath.pushy.apns.ApnsClientBuilder;
import com.eatthepath.pushy.apns.PushNotificationResponse;
import com.eatthepath.pushy.apns.auth.ApnsSigningKey;
import com.eatthepath.pushy.apns.util.ApnsPayloadBuilder;
import com.eatthepath.pushy.apns.util.SimpleApnsPayloadBuilder;
import com.eatthepath.pushy.apns.util.SimpleApnsPushNotification;
import com.eatthepath.pushy.apns.util.TokenUtil;
import com.eatthepath.pushy.apns.util.concurrent.PushNotificationFuture;

public class App {
    public static void main(String[] args) throws Exception {
        final String teamID = "5U8LBRXG3A"; // 作者サイトから取得
        final String keyId = "LH4T9V5U4R"; // 作者サイトから取得
        final String topic = "me.fin.bark"; // ソースから取得
        final String tokenString = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // iOS デバイストークン。docker の bark.db から取得

        final ApnsClient apnsClient = new ApnsClientBuilder() //
                .setApnsServer(ApnsClientBuilder.PRODUCTION_APNS_HOST) // pro ★★★ここ注意、本番環境で設定★★★
                //.setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST) // dev
                //.setMetricsListener(new MyCustomMetricsListener()) // dev
                .setSigningKey(ApnsSigningKey.loadFromPkcs8File(new File("AuthKey_LH4T9V5U4R_5U8LBRXG3A.p8"), teamID, keyId)) // p8File, TeamID, Key ID
                .build();

        final ApnsPayloadBuilder payloadBuilder = new SimpleApnsPayloadBuilder();
        payloadBuilder.setAlertBody("Example!"); //本文
        payloadBuilder.setAlertTitle("Title!"); //タイトル
        payloadBuilder.setSound("minuet.caf"); //サウンド設定

        SimpleApnsPushNotification pushNotification = new SimpleApnsPushNotification(TokenUtil.sanitizeTokenString(tokenString), topic, payloadBuilder.build());
        final PushNotificationFuture<SimpleApnsPushNotification, PushNotificationResponse<SimpleApnsPushNotification>> sendNotificationFuture = apnsClient.sendNotification(pushNotification);
        try {
            final PushNotificationResponse<SimpleApnsPushNotification> pushNotificationResponse = sendNotificationFuture.get();
            if (pushNotificationResponse.isAccepted()) {
                System.out.println("accepted");
            } else {
                System.out.println("rejected: " + pushNotificationResponse.getRejectionReason());
                pushNotificationResponse.getTokenInvalidationTimestamp().ifPresent(timestamp -> {
                    System.out.println("\t…invalid " + timestamp);
                });
            }
        } catch (final ExecutionException e) {
            System.err.println("Failed");
            e.printStackTrace();
        }
        sendNotificationFuture.whenComplete((response, cause) -> {
            if (response != null) {
                // Handle the push notification response as before from here.
            } else {
                // Something went wrong when trying to send the notification to the
                // APNs server. Note that this is distinct from a rejection from
                // the server, and indicates that something went wrong when actually
                // sending the notification or waiting for a reply.
                cause.printStackTrace();
            }
        });
        apnsClient.close();
        /*final CompletableFuture<Void> closeFuture = apnsClient.close();
        closeFuture.whenComplete((response, cause) -> {
            if (response != null) {

            } else {
                cause.printStackTrace();
            }
        });*/
    }
}
```

これで、iOS 端末に、通知がいくようになる。

以上。