manifest.json

結論: 無理なのでCordovaで普通のアプリとしました。

PWAでWebサイトを「インストール」してアプリみたいにして使おうとしたときに、必ず要るのがmanifest.json。

たいてい/manifest.jsonに置かれていて、ここにアプリとしての見た目を整える様々な設定が書かれている。

1
2
3
4
5
6
7
{
"short_name": "name",
"name": "name",
///略 PWAのmanifest.jsonはJSON with comment
"background_color": "#000",
"display": "fullscreen",
}

さて、これは恐怖体験である。

これはあるWebサービスのmanifest.json(抜粋)で、このサイトは情報収集に使っているのだが、なんとdisplayがfullscreenなのである。

私にはdisplayがfullscreenで許されるのはゲームだけという信念がある。どうにかして非fullscreen: standaloneにしてこのWebサイトをインストールしたいという気持ちに駆られた。

なぜだめなのか

Android端末の場合、fullscreenはstandaloneとは違って上下のステータスバーやナビゲーションバーが出ない。昨今16:9以上の縦長ディスプレイが受け容れられているのは、実質上下が吸い取られているからだろう。(ただ、Android 10からはジェスチャーナビゲーションがデフォルトになっている)

fullscreenになると、コンテンツ閲覧中にホーム画面に戻りたくなってもまず画面下端から引っ張り上げてそこからホームボタンを押さなければならない。時計も上から引っ張らないと見れない。情報収集はすき間時間にやるということを考えると致命的なことである。

もしかして自分が知らないだけで割とfullscreenが主流なのかもしれないと、いろいろなサービスを「ホーム画面に追加」してみたが、MastodonもTwitterもMisskeyもstandaloneであった。

変えたい

Remote debug

まず最初に考えたのは、Remote devicesとしてAndroid端末をデバッグして、そこでmanifest.jsonを変更することだった。

しかし、ブラウザは最初のロード時に得たmanifest.jsonを大事に抱えるので、後から変更しても無意味だった。


Remote devices

ローカルDNS

おおもとのコンテンツを変更しなければならない。となるとかなりリスキーだがローカルでDNSを建てて自分が管理しているどっかの自鯖のIPアドレスを解決させるしかないようだ。

まずはDNS作りから。Windows環境やWSL環境でbindを試してみたが、どちらも上手くいかなかった。なので、pDNSという比較的新しい日本人によって作成されたソフトを使ってみた。

使い方はかなり簡単で、zipを落とした後Adminなcmdでサービスをインストールし、zones.txtをbind風に書いてそのサービスを開始するだけだった。

pDNSサービス

192.168.11…..にDNSが建ったので、これをAndroidのWiFiの優先DNSに設定したらOKかと思ったが、これがなかなか上手くいかない。なぜか普通にすべてのサイトが解決できてしまうのだ。今繋いでいるメイン回線はV6プラスだし、もしかしてDNSもIPv6で指定しないとダメだったりするのかとかいろいろ考えた挙句、いわゆる賃貸の無料インタネッツ回線がご丁寧に埋め込みWiFiまで付いて(良くて15Mbps)鎮座していることを思い出しそっちに繋ぎなおして事なきを得た。

こちらでDNSを例のものにすると確かにアクセスできなくなるが、ついでに指定しているはずのドメインの解決さえできなくなった。これにも悩まされたが、結局これはファイアウォールを一時的に全部無効にしたら通った。

解決するIPアドレスはOracle CloudのOpenStickerが乗っている方にした。たまたまPowerShellの履歴の新しい方にsshした跡があったからという理由である。ディレクトリにmanifestを指定したindex.htmlと、理想のmanifest.jsonをつっこむ。

バーチャルホストとしてそのサイトと同じものを指定しないといけないのだが、それにHSTSが効いていたか知らないがHTTPSに勝手にリダイレクトしてしまうことが判明した。もちろん正当に所持しているドメインではないのでLE(Let’s Encrypt)はできない。

久しぶりにオレオレ証明書の出番だ。適当にカタカタ作ってNginxのconfとして保存する。当然証明書エラーで真っ赤になるが、これをスルー(…(安全ではありません)をタップ)してもmanifest.jsonは読んでくれた。

これでようやく理想のPWAサイトになった。

わけではない。

manifest.jsonは読んでくれてもServiceWorkerは正しいHTTPSサイトでないと読んでくれないのだ。(もちろんsame-originの縛りがあるので、サブドメイン等のSWであっても、httpsと書いた瞬間にアウトである)

ホーム画面に追加するとManifest.json通りなPWAアプリ風のものがホーム画面に現れるが、これはただのショートカットでAndroid内の「アプリ」として認識されて検索に引っかかるいったことはない。ただ、ショートカットを押せばPWAのようにふるまうのでfullscreenからstandaloneへ変更できたことにはなる。

こうなれば正しい証明書として認識させるためにオレオレ証明書を端末にインストールしてやる以外に方法が無いが、これはAndroid 7.0以降禁じ手となっていてroot化しないとできないようになっている。

無念。

ひらめいた

というかCordovaでWebviewにそれだけ表示するアプリ書けばそれでいいではないか。

Cordovaはconfig.xmlのcontent src=””に外部URLを指定してもそのまま出してくれる。

そのサービスはGoogle OAuthを使っていたので、

1
<allow-navigation href="https://accounts.google.com/*" />

をしないとGoogle認証時に外部ブラウザに飛んでしまう。

あと、Googleは内部ブラウザでOAuthされるのをなるべく防ごうと(セキュリティの問題もあるし、ユーザもパスワードマネージャが使えなかったりして辛い)ユーザーエージェントで制限をかけているので、

1
<preference name="OverrideUserAgent" value="Mozilla/5.0 (Linux; Android 10; SM-G9750) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Mobile Safari/537.36" />

とユーザーエージェントを上書きする。

Googleの2段階認証プロセス(スマホで「ログインしようとしていますか?」と出るやつ)を通すとaccounts.google.com外に飛ばされた挙句Bad Request(400)に遭遇してしまったが、アプリを起動しなおすといけた。

Cordova書いたの3年ぶりだった。PWAとReact Nativeの狭間で存在感を薄めつつあるCordovaだが、このように外部URLを無理やりPWA化したりするような場合には有用だろう。