PWA의 웹푸시 기능 테스트를 하면서 안드로이드의 경우 큰 문제없이 푸시발송이 되지만, iOS는 처음부터 정상적으로 되지 않았다. 그래서 푸시발송을 위해 반드시 필요한 부분을 기억하고자 정리하게 되었다.
iOS의 웹푸시는 작년(2023년 하반기 정식지원)부터 지원하는 기능으로 안드로이드보다 불편한것 같다. 여러 가지 제약으로 인해 많은 사용이 되지는 않을 것 같지만, 꼭 필요한 사람에게는 유용한 기능일듯 하다.
아래는 iOS의 safari에서 웹푸시를 수신하기 위한 내용이다.
준비사항
우선 Apple Web Push로 push를 전송하고 safari에서 웹푸시를 받기 위해서 아래사항을 반드시 지켜야 한다.
- 웹화면에 추가
- iOS 버전 확인 (16.4 이상) 및 safari의 Notificaiton API 활성화
- Settings → Safari → Advanced → Experimental Features. (iOS 16 일 경우)
- Web Push Server의 subject 항목 필수
1. 웹화면에 추가
iOS에서 웹푸시를 수신하기 위해서, 웹앱이 홈스크린에 추가되어야 한다. 그렇지 않으면 Notification.requestPermission() 에서 항상 denied로 리턴받는다.
아래의 그림처럼 웹앱을 홈스크린에 추가하고 다시 실행해야 한다.
subscription 생성
웹푸시 요청을 통해 subscription을 생성한다.
2. safari의 Notificaiton API 활성화
iOS 16 버전 이하일 경우 설정해야 한다.
3. Web Push Server의 subject 항목 필수
Chrome은 잘 되는데 Safari로 푸시 전송하면 응답결과로 BadJwtToken
이 나오는 경우가 있다.
VAPID로 생성된 public key와 private key만 사용하고 subject는 없는 경우 발생할 수 있다. 그래서 subject는 반드시 넣어야 한다.
java로 전송할 때 사용되는 web-push
모듈의 사용법은 아래와 같다.
[web-push의 pom.xml]
<dependency>
<groupId>nl.martijndwars</groupId>
<artifactId>web-push</artifactId>
<version>5.1.1</version>
</dependency>
PushService를 만들 때 반드시 subject를 아래와 같은 형식으로 넣어주자.
@Value("${vapid.public.key}")
private String publicKey;
@Value("${vapid.private.key}")
private String privateKey;
@Value("${vapid.subject}") // mailto:rudaks@mail.com
private String subject;
@PostConstruct
private void init() throws GeneralSecurityException {
Security.addProvider(new BouncyCastleProvider());
if (pushService == null) {
pushService = new PushService(publicKey, privateKey, subject);
}
}
mailto:rudaks@mail.com 형식에 공백이 들어가도 안된다.
또한 mailto 대신 url을 사용해도 된다고 한다.subject는 Google Web Push에서는 없어도 되지만 App Web Push는 반드시 필요로 한다.
[push 소스]
private HttpEntity sendPush(Subscription subscription, String message) {
try {
HttpResponse response = pushService.send(new Notification(subscription, message), Encoding.AES128GCM);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != 201) {
System.out.println("Server error, status code:" + statusCode);
InputStream content = response.getEntity().getContent();
List<String> strings = IOUtils.readLines(content, "UTF-8");
} else {
System.out.println("OK");
}
return response.getEntity();
} catch (GeneralSecurityException | IOException | JoseException | ExecutionException
| InterruptedException e) {
e.printStackTrace();
}
return null;
}
private String getMessage(PushMessage pushMessage) {
try {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(pushMessage);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class PushMessage {
private String title;
private String content;
}
결과 화면
iOS에서도 웹푸시가 정상적으로 수신되는 것을 확인할 수 있다.