ウェブアプリはリーチが広いです。複数のプラットフォームで実行できます。リンクで簡単に共有できます。しかし、従来はオペレーティング システムとの統合が不足していました。少し前まではインストールすらできませんでした。幸いなことに、この状況は変化し、この統合を利用して PWA に便利な機能を追加できるようになりました。これらのオプションをいくつか見てみましょう。
ファイル システムの操作
ファイルを使用する一般的なユーザー ワークフローは次のようになります。
- デバイスからファイルまたはフォルダを選択して直接開きます。
- これらのファイルやフォルダに変更を加え、変更を直接保存します。
- 新しいファイルとフォルダを作成する。
File System Access API が登場する前は、ウェブアプリでこの操作を行うことはできませんでした。ファイルを開くにはファイルのアップロードが必要で、変更を保存するにはユーザーがダウンロードする必要があり、ウェブはユーザーのファイルシステムで新しいファイルやフォルダを作成する権限をまったく持っていませんでした。
ファイルを開く
ファイルを開くには、window.showOpenFilePicker() メソッドを使用します。なお、このメソッドでは、ボタンのクリックなどのユーザー操作が必要です。ファイルを開くための残りの設定は次のとおりです。
- ファイル システム アクセスのファイル選択ツール API からファイル ハンドルを取得します。ファイルに関する基本情報が表示されます。
- ハンドルの
getFile()メソッドを使用すると、ファイルに関する追加の読み取り専用プロパティ(名前や最終更新日など)を含むFileという特殊な種類のBlobが取得されます。Blob であるため、text()などの Blob メソッドを呼び出してコンテンツを取得できます。
// Have the user select a file.
const [ handle ] = await window.showOpenFilePicker();
// Get the File object from the handle.
const file = await handle.getFile();
// Get the file content.
// Also available, slice(), stream(), arrayBuffer()
const content = await file.text();
変更を保存しています
ファイルへの変更を保存するには、ユーザー操作も必要です。
- ファイル ハンドルを使用して
FileSystemWritableFileStreamを作成します。 - ストリームに変更を加えます。この場合、ファイルはインプレースで更新されず、通常は一時ファイルが作成されます。
- 最後に、変更が完了したらストリームを閉じます。これにより、変更が一時的なものから永続的なものに移行します。
コードで見てみましょう。
// Make a writable stream from the handle.
const writable = await handle.createWritable();
// Write the contents of the file to the stream.
await writable.write(contents);
// Close the file and write the contents to disk.
await writable.close();
ファイル処理
File System Access API を使用すると、アプリ内からファイルを開くことができますが、その逆はどうでしょうか?ユーザーは、ファイルをデフォルトで開くアプリとしてお気に入りのアプリを設定したいと考えています。ファイル処理 API は、インストールされた PWA がユーザーのデバイスでファイル ハンドラとして登録し、ウェブアプリ マニフェストで PWA がサポートする MIME タイプとファイル拡張子を指定できるようにする試験運用版の API です。サポートされている拡張機能のカスタム ファイル アイコンを指定できます。
登録すると、インストールされた PWA がユーザーのファイル システムのオプションとして表示され、ユーザーはファイルを直接開くことができます。テキスト ファイルを読み取る PWA のマニフェスト設定の例を次に示します。
...
"file_handlers": [
{
"action": "/open-file",
"accept": {
"text/*": [".txt"]
}
}
]
...
URL の処理
URL 処理を使用すると、PWA はスコープの一部であるリンクをオペレーティング システムからキャプチャし、デフォルトのブラウザのタブではなく、PWA ウィンドウ内でレンダリングできます。たとえば、PWA にリンクするメッセージを受信した場合や、PWA 内のディープリンク(特定のコンテンツを指す URL)をクリックした場合、コンテンツはスタンドアロン ウィンドウで開きます。
この動作は、WebAPK が使用されている場合(ユーザーが Chrome で PWA をインストールする場合など)に Android で自動的に利用できます。iOS と iPadOS の Safari からインストールされた PWA の URL を取得することはできません。
パソコンのブラウザでは、ウェブ ブラウザ コミュニティが新しい仕様を作成しました。この仕様は現在試験運用中で、新しいマニフェスト ファイル メンバー url_handlers を追加します。このプロパティには、PWA がキャプチャするオリジンの配列を指定します。PWA のオリジンは自動的に付与されます。他のオリジンは、web-app-origin-association という名前のファイルを通じてオペレーティングの処理を受け入れる必要があります。たとえば、PWA のマニフェストが web.dev でホストされていて、app.web.dev オリジンを追加する場合は、次のようになります。
"url_handlers": [
{"origin": "https://app.web.dev"},
]
この場合、ブラウザは app.web.dev/.well-known/web-app-origin-association にファイルが存在するかどうかを確認し、PWA スコープ URL からの URL 処理を受け入れます。デベロッパーがこのファイルを作成する必要があります。次の例では、ファイルは次のようになります。
{
"web_apps": [
{
"manifest": "/mypwa/app.webmanifest",
"details": {
"paths": [ "/*" ]
}
}
]
}
URL プロトコルの処理
URL 処理は標準の https プロトコル URL で動作しますが、pwa:// などのカスタム URI スキームを使用することもできます。いくつかのオペレーティング システムでは、インストールされたアプリがスキームを登録することで、この機能が有効になります。
PWA の場合、この機能はデスクトップ デバイスでのみ利用可能な URL プロトコル ハンドラ API を使用して有効になります。モバイル デバイスでカスタム プロトコルを許可するには、アプリストアで PWA を配布する必要があります。
登録するには、registerProtocolHandler() メソッドを使用するか、マニフェストで protocol_handlers メンバーを使用します。このメンバーには、目的のスキームと、PWA のコンテキストで読み込む URL を指定します。例:
...
{
"protocol_handlers": [
{
"protocol": "web+pwa",
"url": "/from-protocol?value=%s"
},
]
}
...
URL from-protocol を正しいハンドラにルーティングし、PWA でクエリ文字列 value を取得できます。%s は、オペレーションをトリガーしたエスケープされた URL のプレースホルダです。たとえば、<a href="web+pwa://testing"> のようなリンクがある場合、PWA は /from-protocol?value=testing を開きます。
他のアプリを呼び出す
URI スキームを使用すると、すべてのプラットフォームで、ユーザーのデバイスにインストールされている他のアプリ(PWA かどうかを問わず)に接続できます。リンクを作成するか、navigator.href を使用して、目的の URI スキームを指定し、URL エスケープ形式で引数を渡すだけです。
電話の tel:、メール送信の mailto:、テキスト メッセージの sms: などのよく知られた標準スキームを使用できます。また、よく知られたメッセージング、地図、ナビゲーション、オンライン会議、ソーシャル ネットワーク、アプリストアなどの他のアプリの URL スキームについて学ぶこともできます。
ウェブ共有
Web Share API を使用すると、PWA は共有チャンネルを通じてデバイスにインストールされている他のアプリにコンテンツを送信できます。
この API は、Android、iOS、iPadOS、Windows、ChromeOS など、share メカニズムを備えたオペレーティング システムでのみ利用できます。次のものを含むオブジェクトを共有できます。
- テキスト(
titleプロパティとtextプロパティ) - URL(
urlプロパティ) - ファイル(
filesプロパティ)。
現在のデバイスが共有できるかどうかを確認するには、テキストなどの単純なデータの場合は navigator.share() メソッドの有無を確認し、ファイルの場合は navigator.canShare() メソッドの有無を確認します。
共有アクションをリクエストするには、navigator.share(objectToShare) を呼び出します。この呼び出しは、undefined で解決されるか、例外で拒否される Promise を返します。

Web Share Target
Web Share Target API を使用すると、PWA かどうかを問わず、デバイス上の別のアプリからの共有操作のターゲットとして PWA を指定できます。PWA が別のアプリから共有されたデータを受信します。
現在、Android(WebAPK)と ChromeOS で利用可能で、ユーザーが PWA をインストールした後にのみ動作します。アプリがインストールされると、ブラウザはオペレーティング システム内で共有ターゲットを登録します。
マニフェストでウェブ共有ターゲットを設定するには、ウェブ共有ターゲットのドラフト仕様で定義されている share_target メンバーを使用します。share_target は、いくつかのプロパティを持つオブジェクトに設定されます。
action- 共有データを受け取る PWA ウィンドウに読み込まれる URL。
method- HTTP 動詞メソッド(
GET、POST、PUTなど)がアクションに使用されます。 enctype- (省略可)パラメータのエンコード タイプ。デフォルトは
application/x-www-form-urlencodedですが、POSTなどのメソッドではmultipart/form-dataに設定することもできます。 params- 共有データ(ウェブ共有のキー
title、text、url、filesから)を、ブラウザが URL(method: 'GET')または選択したエンコードを使用してリクエストの本文で渡す引数にマッピングするオブジェクト。
たとえば、マニフェストに次のように追加することで、共有データ(タイトルと URL のみ)を受け取るように PWA を定義できます。
...
"share_target": {
"action": "/receive-share/",
"method": "GET",
"params": {
"title": "shared_title",
"url": "shared_url"
}
}
...
前のサンプルで、システム内のアプリがタイトル付きの URL を共有していて、ユーザーがダイアログから PWA を選択した場合、ブラウザはオリジンの /receive-share/?shared_title=AAA&shared_url=BBB への新しいナビゲーションを作成します。ここで、AAA は共有されたタイトル、BBB は共有された URL です。JavaScript を使用して、URL コンストラクタで解析することで、window.location 文字列からデータを読み取ることができます。
ブラウザは、マニフェストの PWA の名前とアイコンを使用して、オペレーティング システムの共有エントリにフィードします。別のセットをその目的で使用することはできません。
詳細な例とファイルの受信方法については、Web Share Target API を使用して共有データを受信するをご覧ください。
連絡先ピッカー
連絡先選択ツール API を使用すると、デバイスにユーザーのすべての連絡先を含むネイティブ ダイアログを表示するようリクエストできます。これにより、ユーザーは 1 つ以上の連絡先を選択できます。これにより、PWA はそれらの連絡先から必要なデータを受け取ることができます。
連絡先選択ツール API は主にモバイル デバイスで利用でき、互換性のあるプラットフォームの navigator.contacts インターフェースを介してすべての処理が行われます。
navigator.contacts.getProperties() でクエリする利用可能なプロパティをリクエストし、必要なプロパティのリストを使用して 1 つまたは複数の連絡先の選択をリクエストできます。
プロパティの例としては、name、email、address、tel などがあります。1 つ以上の連絡先を選択するようユーザーに求める場合は、navigator.contacts.select(properties) を呼び出し、取得するプロパティの配列を渡します。
次のサンプルは、ピッカーで受信した連絡先を一覧表示します。
async function getContacts() {
const properties = ['name', 'email', 'tel'];
const options = { multiple: true };
try {
const contacts = await navigator.contacts.select(properties, options);
console.log(contacts);
} catch (ex) {
// Handle any errors here.
}
}