🤯

iOS17でpwaが開けない不具合の対応

2023/10/10に公開

FetchEvent.respondWith received an error

原因

iOS17のアップデート後、突然PWAが開けなくなりました。
pwa上でサイトを開こうとすると白い画面で以下のエラーメッセージが。。。

Safari can’t open the page.
The error was:
“FetchEvent.respondWith received an error: TypeError: Internal error.”

原因を探してみると、iOS17のCacheAPIの不具合に加え、Angularのサービスワーカーでキャッシュ取得の間にエラーハンドリングのロジックが不在していることが分かりました。

Angularのgithubレポジトリでは既に関連イッシューが報告されてました。キャッシュ取得にエラーが発生してもサイトを表示するように@angular/service-worker@16.2.7バージョンにアップデートができたそうです。
参考:
https://github.com/angular/angular/issues/50378#issuecomment-1732611425
https://github.com/angular/angular/pull/51885/files

対応

最新のAngularバージョンを使っている方ならサービスワーカーを16.2.7バージョンにアップデートすれば解除できると思います。ただ、私の場合はangular12を使ってましたので、パッケージをアップデートする代わりに以下の方法を適用しました。

  1. ngsw-worker-workaround.jsファイルの生成
  2. node_modules/@angular/service-worker/ngsw-worker.jsの内容をコピしてngsw-worker-workaround.jsに貼り付け
  3. 以下のコードブラックをtry-catch文に書き換える
    (Angularのバージョンによって内容は少しずつ違いますので、バージョンに合わせて修正してください。)
ngsw-worker.js(修正の必要な箇所)
const cachedResponse = yield cache.match(req, this.config.cacheQueryOptions);
ngsw-worker-workaround.js
let cachedResponse;
try {
    // Safari 16.4/17 is known to sometimes throw an unexpected internal error on cache access
    // This try/catch is here as a workaround to prevent a failure of the handleFetch
    // as the Driver falls back to safeFetch on critical errors.
    cachedResponse = yield cache.match(req, this.config.cacheQueryOptions);
} catch (error) {
    throw new SwCriticalError(`Cache is throwing while looking for a match: ${error}`);
}    
  1. package.jsonのスクリプトにポストビルドを追加
package.json
{
  "scripts": {
    ...
    "postbuild": "cp ngsw-worker-workaround.js ./dist/ngsw-worker.js",
    "build": "ng build && npm run postbuild",
    ...
  },
}

上記の順番により、ビルド後、エラーハンドリングができるサービスワーカーが登録されます。

Cache API operation failed: Internal error

原因

上記の対応でpwaのサイトが開けないエラーは解決できましたが、キャッシュ取得には相変わらず問題が残っています。根本的な問題はiOS17のCacheAPIのため、サービスワーカーのキャシング戦略が活用できなくなります。こちらはiOSで対応を待つしかないですね。

対応

Appleでアップデートパッチをしてくれるまで、iOS17はサービスワーカーを登録しないようにしました。
iOS17のuserAgentにはOSバージョンが記載されてますので、その情報を使います。

  • iOS 17 Safari: Mozilla/5.0 (iPhone; CPU iPhone OS 17_0_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1
  • iOS 17 Chrome: Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/117.0.5938.117 Mobile/15E148 Safari/604.1
app.module.ts
@NgModule({
  imports: [
    ServiceWorkerModule.register('ngsw-worker.js', {
      enabled: !isDevMode() && !window.navigator.userAgent.includes('iPhone OS 17'),
      registrationStrategy: 'registerWhenStable:30000'
    }),
  ]
})

まとめ

iOS17のアップデートにより、CacheAPI仕様が変化されたようです。
Angularサービスワーカーを使っている方、pwaを活用している方は今回の不具合により、色々影響があると思います。
白い画面でエラー文句が表示される現状はngsw-worker.jsの内容をアップデートすることで解除できますが、CacheAPI自体はまだiOSの方で対応前なので、当分の間はiOS17に限ってサービスワーカーのキャッシングは停止した方が良いかもしれません。

Discussion