もう先月ですが、Web Push Notificationを勉強して自分で試すことで、 理解を深めました。作ってもみました。
やりたいアプリはJhipsterで Angular使ってるんですが、 ではそういえば、AngularではWeb Pushってどうやるんだろう?! ということからまた勉強が始まりました。 調べてみると、簡単に使えるようになっているんですね(Angular CLI 1.6以降は)。
- 3分クッキング ServiceWorkerで阿部寛さんを超える → いやこれ、単に阿部さんのページはcontents量が少ないから、というだけのjokeですよね
- Angular CLI 1.5によるAngular Service Workerクイックスタート → 「angular.jpで公式ドキュメントの翻訳が完了しているので、こちらをご覧ください」確かに公式見た方がいいですか。
- (Angular公式) Service Workerを始める
- AngularアプリをPWAにする方法
- Creating PWA with Angular 5. Part 1: Getting started with framework, creating an application, hosting it on github-pages., Creating PWA with Angular 5. Part 2: Progressifying the application → PWCatを写経して比較検討しました
- Angular Service Worker - Step-By-Step Guide for turning your Application into a PWA
多くの導きのおかげで、angular5にてどのようにservice workerを導入するか、 はわかってきました。
要するに、アプリをgenerateする時に、Angular CLI(1.6+、現時点では1.7.3)で、
1
|
|
とするか、既にgenerateしてしまったアプリに対しては、 (Angular公式) Service Workerを始めるにあるように、
yarn add @angular/service-worker
ng set apps.0.serviceWorker=true
または.angular-cli.json
を編集してapps
の下レベルに"serviceWorker": true
を挿入src/app/app.module.ts
にService Workerをimport
して登録(但しその際、base hrefを/
の他にしたいならServiceWorkerModule.register('./ngsw-worker.js', {enabled: environment.production})
と./ngsw-worker.js
を相対指定しないとダメ)src/ngsw-config.json
を作成(雛形をコピペ)ng build --prod
としてbuild(ng serve
ではダメ)(base hrefを/
の他にしたいなら--base-href /another/directory/
が必要。←最後が/
でないとダメ)
PWAとしては、あとmanifest.json
が必要?(Progressive Web Apps using the Angular Service Worker, AngularアプリをPWAにする方法)
これで、当該projectをweb browserで表示させると、 service workerが読み込まれ、 offline cacheが効くようになる、筈... なのですが、どう試しても、 offline modeにしてからreloadすると、504 Gateway Timeout (from ServiceWorker)
になってしまいます。 PWCatでは上手くcacheされていることから、 多分これはAngularのbugと思います。
なのでoffline cacheは今は諦めて、push notificationの方策を探りました。 AngularのService Workerの話は、公式も含めて、 cacheやupdateばかりでpush notificationについては触れられてないんですね。 そういう中、A new Angular Service Worker — creating automatic progressive web apps. Part 1: theory, A new Angular Service Worker — creating automatic progressive web apps. Part 2: practiceという記事があり、 PWAtterとそのserverがありましたので、 非常に参考にさせてもらえました。 というかほぼそのままコピペして使わせてもらってます。 PWAtterはtwitterを拾うので物凄い勢いでpush notificationが来て、 明示的に消さないと消えないので、かなりうざいのですが、 これでAngularでPush Notificationが実装できるようになりました。 非Angularで作った時は、notificationの形についてはあまり気にしてなくて、 clickTarget
とかNotification object specを無視していましたが、 Angularではngsw-worker.js
にNOTIFICATION_OPTION_NAMES
があって、 そこで有効なproperty namesが規定されており、 NOTIFICATION_OPTION_NAMES.filter(name => desc.hasOwnProperty(name))
として filterしているので、変なproperty書いても効かないんですね。 ちゃんとNotification object specに則った形のJSONをsendするようにすると、 push notificationが表示されるようになりました。
あとは、Notificationをclickしたら消えたり指定のpageに飛ぶように、 と思ったんですが、どうやったらいいのか。 notification.action
とか色々指定してみたものの、一向に何も起きず。 何でかなーって思ったら、どうやらnot yet implementedなんですね。 現に、node_modules/@angular/service-worker/ngsw-worker.js
に、 addEventListener('push', (event)...
等はあっても、 addEventListener('notificationclick', (event)...
は無いんですね。(- -; workaroundとしては、以前の知見を活かして、 似たようなことを書けばそれだけでpush notificationを実現できることを確認しました。 push notificationの動作確認済のアプリを作成しました。
既に公式Angularでもissuesに似たような話はありましたので、 comment付けておきました。
app.module.ts
中の/ngsw-worker.js
は相対指定であるべき ServiceWorker register generated by cli with base-href don't works #8515notificationclick
event listenerのworkaroundの紹介 Provide means to configure notificationclick in service-worker push #20956, How to handle Notification click events (cannot find docs) #22311
ホントはPull Request作りたかった、です。 上記前者の方は、どこでどうやって書き込んでいるのかわからず、codeに出来ませんでした。 後者は、angular/packages/service-worker/worker/src/driver.ts
とangular/packages/service-worker/worker/src/service-worker.d.ts
だというのはわかって、 書いてみたんですが、 いや難しいですね。 まずevent
ってnotification
以下のJSONを含んでいるわけですが、 同時にevent.notification.close()
っていうmethodもあるわけで、 こういうのを厳密にobjectとして表現しなきゃいけないようになってるんですね。 凄いなぁ。そういうのが曖昧模糊渾然一体としているのがjavascriptなのに。 また、clients.openWindow(...)
のclients
もいきなり出て来るobjectで、 出自がよくわからないのですけど、そういう曖昧さを許さないように出来ています。 他を見てどうやらthis.scope.clients
とすればよさそうなのはわかったんですが、 それでも./build.sh
をかけると driver.ts(246,28): error TS2339: Property 'openWindow' does not exist on type 'Clients'.
と言われて、お手上げでした。 notification.close()
の方も、 error TS2339: Property 'notification' does not exist on type 'Object | Client'
と言われて、 どうしていいかわからず。 生成されるべきcodeはわかってるのに、悔しい、です。 折角Code of ConductやCONTRIBUTING.md読んでcoding ruleやcommit message formatを学んだりCLA(Contributor License Agreement)登録したりDEVELOPER.md読んでbuildやtestの仕方学んだりしたのにー。 でもまぁ確かに、飛び先のURLはどこに書くべきか、とか、 clickしたら飛ばないでただ閉じるように/閉じないようにしたい、とかするには、 eventListener('notificationclick',(event)=>{...});
を 直接いじらないとならないし、 仕様を含めたもっと別の方策が必要だと思います本当は。
favicon等iconを作るのに、Real Favicon Generator、いいですね。