渐进式网络应用程序(PWA)无法在Android手机屏幕上弹出推送通知 [英] Progressive web app (PWA) not able to make push notifications pop up on screen of android phone

查看:40
本文介绍了渐进式网络应用程序(PWA)无法在Android手机屏幕上弹出推送通知的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用需要创建推送通知的PWA(渐进式Web应用),这些推送通知需要尽可能明显。

像大多数聊天应用程序一样,我希望通知弹出在移动屏幕上。在安卓9和10(未测试其他版本)上,推送通知会发出声音,并被添加到抽屉中,但不会弹出。 经过一些研究,我发现Android原生应用程序需要添加通知频道&(Android Oreo中添加的功能),才能将应用程序的通知设置设置为声音和弹出窗口(也可以称为Head-up),而不是只设置声音和声音。对于PWA,我找不到有关此类选项的任何信息。

在我的(已安装的)PWA的Android通知设置中,有一个类别称为&General";,设置为Only Sound,未激活弹出/提示窗口。当我激活它时,会按预期弹出通知。

我的代码使用带有VAPID的FCM(因此不需要Firebase帐户),灵感来自 https://golb.hplar.ch/2019/08/webpush-java.htmlhttps://github.com/ralscha/blog2019/tree/e39cc479044867f40e4c1e2835f7265ee2532760/webpushhttps://github.com/web-push-libs/webpush-java

public class PushMessage {
    private final String title;
    private final String body;
    private final String priority = "high";

    public PushMessage(String title, String body) {
        this.title = title;
        this.body = body;
    }

    public String getTitle() {
        return this.title;
    }

    public String getBody() {
        return this.body;
    }

    public String getPriority() {
        return this.priority;
    }

    @Override
    public String toString() {
        return "PushMessage [title=" + this.title + ", body=" + this.body + "]";
    }
}
private boolean sendPushMessage(PushMessage message, Subscription subscription) throws Exception {
        boolean sent = false;
        // send message to given subscription
        byte[] encryptedMessage = new CryptoService().encrypt(
                new ObjectMapper().writeValueAsString(message),
                subscription.getKeys().getP256dh(), subscription.getKeys().getAuth(), 0);

        ECPrivateKey eCprivateKey = (ECPrivateKey) new CryptoService().convertPKCS8ToECPrivateKey(privateBytes);
        String origin = null;
        try {
            URL url = new URL(subscription.getEndpoint());
            origin = url.getProtocol() + "://" + url.getHost();
        } catch (MalformedURLException e) {
            e.printStackTrace();
            //Application.logger.error("create origin", e);
            return true;
        }

        long expiry = new Date().getTime() + 12 * 60 * 60 * 1000;

        JwtClaimsBuilder claimsBuilder = Jwt.claims().audience(origin).subject("mailto:mhaerdi@gmx.ch");
        JwtSignatureBuilder signBuilder = claimsBuilder.jws();//.algorithm(SignatureAlgorithm.ES256);
        String token = signBuilder.sign(eCprivateKey);

        URI endpointURI = URI.create(subscription.getEndpoint());

        Builder httpRequestBuilder = HttpRequest.newBuilder();
        if (encryptedMessage != null) {
            httpRequestBuilder.POST(BodyPublishers.ofByteArray(encryptedMessage))
                    .header("Content-Type", "application/octet-stream")
                    .header("Content-Encoding", "aes128gcm");
        }
        else {
            httpRequestBuilder.POST(BodyPublishers.ofString(""));
        }

        HttpRequest request = httpRequestBuilder.uri(endpointURI).header("TTL", "86400")
                .header("Urgency", "high")
                .header("Authorization","vapid t=" + token + ", k=" + publicBase64)
                .build();
        try {
            HttpResponse<Void> response = HttpClient.newHttpClient().send(request,
                    BodyHandlers.discarding());

            switch (response.statusCode()) {
                case 201:
                    log.info("Push message successfully sent: "+ subscription.getEndpoint());
                    sent = true;
                    break;
                case 404:
                case 410:
                    log.warn("Subscription not found or gone: "+ subscription.getEndpoint());
                    removeSubscription(subscription);
                    sent = false;
                    break;
                case 429:
                    log.error("Too many requests: "+ request);
                    sent = false;
                    break;
                case 400:
                    log.error("Invalid request: "+ request);
                    sent = false;
                    break;
                case 413:
                    log.error("Payload size too large: "+ request);
                    sent = false;
                    break;
                default:
                    log.error("Unhandled status code: "+ response.statusCode() + " "+ request);
                    sent = false;
            }
        }
        catch (IOException | InterruptedException e) {
            log.error("send push message", e);
        }

        return sent;
    }
client side service worker:

self.addEventListener('push', event => {
  console.log('Push Notification received: ', event);
  if(event.data) {
    let data = JSON.parse(event.data.text())
    event.waitUntil(
      self.registration.showNotification(
        data.title,
        {
          body: data.body,
          icon: 'icons/icon-128x128.png',
          badge: 'icons/icon-128x128.png',
          //image: data.imageUrl,
          image: 'icons/icon-128x128.png',
          vibrate: [100, 50, 100],
          priority: 'max',
          android:{
            priority: 'max'
          },
          data: {
            dateOfArrival: Date.now(),
            primaryKey: 1,
            openUrl: 'https://comunex.ch',//data.openUrl
            priority: 'max'
          },
          actions: [
            {action: 'explore', title: 'Nice!',
              //icon: 'images/checkmark.png'
            },
            {action: 'close', title: 'Close notification',
              //icon: 'images/xmark.png'
            },
          ],
          requireInteraction : true,
        }
      )
    )
  }
});

如您所见,我尝试设置了紧急标头并向消息数据(服务器端和客户端)添加了优先级,但都没有效果。

推荐答案

我认为您自己已经回答了您的问题。Android应用程序需要被授予显示弹出窗口的权限,除非你授予该权限,否则你不会看到弹出窗口。这是Android生态系统的限制,而不是Web推送协议或此库的限制。

这篇关于渐进式网络应用程序(PWA)无法在Android手机屏幕上弹出推送通知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆