u-ryo's blog

various information for coding...

Category: Push notification

Push Notification on Angular5

| Comments

もう先月ですが、Web Push Notificationを勉強して自分で試すことで、 理解を深めました。作ってもみました

やりたいアプリはJhipsterAngular使ってるんですが、 ではそういえば、AngularではWeb Pushってどうやるんだろう?! ということからまた勉強が始まりました。 調べてみると、簡単に使えるようになっているんですね(Angular CLI 1.6以降は)。

多くの導きのおかげで、angular5にてどのようにservice workerを導入するか、 はわかってきました。

要するに、アプリをgenerateする時に、Angular CLI(1.6+、現時点では1.7.3)で、

1
ng new application-name --service-worker

とするか、既にgenerateしてしまったアプリに対しては、 (Angular公式) Service Workerを始めるにあるように、

  1. yarn add @angular/service-worker
  2. ng set apps.0.serviceWorker=true または .angular-cli.jsonを編集してappsの下レベルに"serviceWorker": trueを挿入
  3. src/app/app.module.tsにService Workerをimportして登録(但しその際、base hrefを/の他にしたいならServiceWorkerModule.register('./ngsw-worker.js', {enabled: environment.production})./ngsw-worker.jsを相対指定しないとダメ)
  4. src/ngsw-config.jsonを作成(雛形をコピペ)
  5. 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.jsNOTIFICATION_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付けておきました。

ホントはPull Request作りたかった、です。 上記前者の方は、どこでどうやって書き込んでいるのかわからず、codeに出来ませんでした。 後者は、angular/packages/service-worker/worker/src/driver.tsangular/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 ConductCONTRIBUTING.md読んでcoding ruleやcommit message formatを学んだりCLA(Contributor License Agreement)登録したりDEVELOPER.md読んでbuildやtestの仕方学んだりしたのにー。 でもまぁ確かに、飛び先のURLはどこに書くべきか、とか、 clickしたら飛ばないでただ閉じるように/閉じないようにしたい、とかするには、 eventListener('notificationclick',(event)=>{...});を 直接いじらないとならないし、 仕様を含めたもっと別の方策が必要だと思います本当は。

favicon等iconを作るのに、Real Favicon Generator、いいですね。