iOSでホーム画面に追加したURLが勝手に変わる?原因と対策(PWA・manifestの罠)

iPhoneでWebページをホーム画面に追加したとき、開いていたURLとは違うページが保存されてしまうことがあります。

僕もPetalを作っている時に、この問題に当たりました。

本来は /petal/{token} のような個別ページを開いて、そのページをホーム画面に追加したかったんです。

ところが実際には、ホーム画面から開くと /petal/@username のような別のURLに飛んでしまいました。

最初はSafariのキャッシュか、iOSの謎挙動かと思いました。

でも結論から言うと、原因はかなりシンプルでした。

manifest.json の start_url に固定URLを書いていたことです。

完全に自分のミスです。ただ、ややこしいのは、そのミスが最初から表に出ていたわけではないことです。

起きた現象

やりたかったことは、かなり単純です。

  • ユーザーごとに違うPetal名刺ページを開く
  • そのページをiPhoneのホーム画面に追加する
  • 次回から、その人のページを直接開けるようにする

つまり、開いているURLそのものをホーム画面に残したかったわけです。

ところが、ホーム画面に追加したアイコンから開くと、今見ていたページではなく、manifestに書かれていた固定URLが開かれてしまいました。

個別ページを保存したつもりなのに、毎回同じページに戻される。

これは、名刺や個人ページのようなサービスではかなり致命的です。

問題のあったmanifest.json

当時のmanifestは、ざっくり言うとこういう形でした。

{
 "name": "Petal",
 "short_name": "Petal",
 "display": "standalone",
 "start_url": "/petal/@ojapp",
 "icons": [
 {
 "src": "/icon.png",
 "sizes": "192x192",
 "type": "image/png",
 "purpose": "maskable"
 }
 ]
}

一見、普通のPWA設定に見えます。

でも、今回の用途では start_url が完全に邪魔でした。

start_url は、ホーム画面から起動した時にどのURLを開くかを指定する項目です。

つまり、ここに固定URLを書いていると、ユーザーがどのページを開いてホーム画面に追加しても、起動時にはその固定URLが優先される場合があります。

今回で言えば、/petal/{token} を追加したつもりでも、/petal/@ojapp が開かれてしまう、ということです。

本当の原因はmaskableではなく、固定start_url

最初は purpose: "maskable" が原因だと思いました。

実際、purpose: "maskable" を入れたあたりから、急にPWAっぽい挙動が強く出て、start_url が効き始めたように見えたからです。

でも、整理すると本質はそこではありません。

本当の問題は、個別URLを保存したいサービスなのに、manifestに固定のstart_urlを書いていたことです。

maskable単体の指定は、環境によって挙動を不安定に見せるきっかけにはなります。

ただ、URLが上書きされる直接の原因は、start_url に固定URLが入っていたことです。

なので、今回の教訓はこれです。

ユーザーごと・ページごとにホーム画面追加させたいなら、start_urlに固定URLを書かない。

なぜiOSで気づきにくいのか

iOSのPWAまわりは、Android Chromeほど素直ではありません。

Androidではmanifestの指定が比較的わかりやすく反映されます。

一方でiPhone Safariは、manifestを全部そのまま使うわけではなく、効く項目と効きにくい項目があります。

そのため、開発中は「この設定はiOSでは無視されている」と思いがちです。

今回も、最初は固定の start_url を書いていても、大きな問題として見えていませんでした。

ところが、manifestやアイコン設定を触っているうちに、急にPWAとしての扱いが強くなったように見え、結果として start_url のミスが表に出ました。

こういうところがiOS PWAの怖いところです。

昨日まで問題に見えなかった設定が、別の項目を変更したことで急に事故として出てくることがあります。

対策1:start_urlを固定しない

個別ページをホーム画面に追加させたい場合、まず見直すべきは start_url です。

トップページに固定したいPWAなら、次のような指定でも問題ありません。

{
 "start_url": "/"
}

でも、Petalのようにユーザーごとのページをホーム画面に置かせたい場合は、固定URLは危険です。

その場合は、次のように "." を使う方が自然です。

{
 "start_url": "."
}

"." は、現在の場所を基準にする指定です。

ページごとにホーム画面追加したいサービスでは、この方が意図に合いやすいです。

PWA LABでも、複数ページや生成ページを扱う場合は start_url: "." の方が扱いやすい場面が多いと感じました。

対策2:maskable単体ではなくany maskableにする

Androidのホーム画面アイコンをきれいに見せたい場合、maskableアイコンは便利です。

ただし、purpose: "maskable" だけを指定するのは、個人的にはあまりおすすめしません。

検証している中では、次のように any maskable と書いた方が安定しやすいと感じました。

{
 "src": "/icon.png",
 "sizes": "512x512",
 "type": "image/png",
 "purpose": "any maskable"
}

any maskable にしておくと、通常アイコンとしても、maskableアイコンとしても扱いやすくなります。

特にiPhone、Android、PC Chromeをまたいで検証する場合、単体の maskable より事故が少ない印象です。

もちろん、きっちりやるなら通常用アイコンとmaskable用アイコンを分けるのが理想です。

でも、個人開発や小さなPWAでは、まず any maskable で安定させる方が現実的です。

対策3:apple-touch-iconの優先にも注意する

iPhoneでは、manifestのiconsより apple-touch-icon が強く効くことがあります。

たとえば、HTMLに次のような指定がある場合です。

<link rel="apple-touch-icon" href="/icon.png">

単一のPWAなら、これは問題になりにくいです。

むしろiPhoneのホーム画面アイコンを安定させるために便利です。

ただし、PetalやOJappのように、ページごと・ユーザーごとに違うアイコンを使いたい場合は注意が必要です。

固定の apple-touch-icon があると、manifest側で別のアイコンを指定していても、iPhoneではそちらが優先されることがあります。

つまり、URLだけでなくアイコンも「思ったものと違う」状態になる可能性があります。

ユーザーごとにホーム画面アイコンを変えたい場合は、apple-touch-icon を固定で入れるべきかどうかも見直した方がいいです。

ページごとのホーム画面追加で安全なmanifest例

今回のような用途なら、manifestは次のような形の方が安全です。

{
 "name": "Petal",
 "short_name": "Petal",
 "display": "standalone",
 "start_url": ".",
 "background_color": "#ffffff",
 "theme_color": "#ffffff",
 "icons": [
 {
 "src": "/icon.png",
 "sizes": "512x512",
 "type": "image/png",
 "purpose": "any maskable"
 }
 ]
}

ポイントは2つです。

  • start_url を固定URLにしない
  • purposeany maskable にする

これだけでも、今回のような「開いていたURLと違うページが保存される」事故はかなり避けやすくなります。

トップ固定型PWAとページ保存型PWAは設計が違う

ここはかなり大事です。

PWAには、大きく分けて2つの考え方があります。

  • トップ固定型:ホーム画面から常にトップページやアプリ本体を開く
  • ページ保存型:今見ている個別ページをホーム画面に残す

一般的なPWAアプリなら、トップ固定型で問題ありません。

たとえば、タスク管理アプリ、ECサイト、ブログアプリのようなものです。

この場合は start_url: "/"start_url: "/app/" が自然です。

でも、Petalの名刺ページや、OJappで作るホーム画面用URLのようなものは、ページ保存型です。

その場合、固定の start_url はむしろ邪魔になります。

今見ているページを残したいのに、起動時だけ別の場所へ飛ばされるからです。

つまり、PWAの書き方として正しいかどうかではなく、そのサービスが何をホーム画面に残したいのかで設計を変える必要があります。

今回の失敗でわかったこと

今回のミスは、かなり単純です。

固定の start_url を書いていた。

それだけです。

ただ、それがすぐに問題として見えなかったことで、原因の切り分けがややこしくなりました。

僕の場合、もともと間違ったURLを start_url に書いていたのに、最初はPWAとして強く発動していなかったのか、大きな問題になっていませんでした。

そこへ purpose: "maskable" を追加したことで、PWAっぽい扱いが強くなり、眠っていた start_url のミスが表に出たような形です。

完全に「なんでやねん」案件でした。

でも、こういう事故はPWAではわりと起きます。

manifest、Service Worker、Safariキャッシュ、apple-touch-icon、ホーム画面追加済みの古い情報。

どれか1つを直しても、別の場所に古い設定が残っていることがあります。

だから、iOS PWAで急に挙動が変わったときは、まずmanifestを疑うのが早いです。

まとめ:URLが勝手に変わる時はstart_urlを疑う

iPhoneでホーム画面に追加したURLが勝手に変わる場合、まず確認すべきなのはmanifest.jsonの start_url です。

  • 固定の start_url が入っていないか
  • 個別ページ保存型なのにトップURLを指定していないか
  • purpose: "maskable" 単体になっていないか
  • apple-touch-icon が固定アイコンを優先していないか
  • 古いmanifestやキャッシュが残っていないか

対策としては、ページごとにホーム画面追加させたい場合、start_url: "." を使うのがかなり有効です。

アイコンは purpose: "any maskable" にしておくと、Androidも含めて安定しやすくなります。

PWAは便利ですが、manifestの1行で体験が大きく変わります。

特にiOSは、効いているのか無視されているのかがわかりにくい場面があります。

開いているURLをそのままホーム画面に残したいなら、固定の start_url はかなり慎重に扱った方がいいです。

>OJapp Tips

OJapp Tips

PWA開発やWebデザインの現場で使える実践的なノウハウをお届けする「OJapp tips」。iOS特有の挙動ハックからmanifest.jsonの緻密な設計まで、ツール開発者が実機検証(PWA LAB)を繰り返して得た泥臭いリアルな知見を発信中。

私たちが運営する「Petal」は、その仕組みを使って“人のページを名刺のように持つ”ためのミニマルなSNS。QRからすぐ開けて、ログインなしでも見れる。でも、必要なときだけつながれる。そんな「弱いつながり」を未来へ残すために作られています。