在應用之間共享資料

應用共享是指一個應用將資訊或資料傳遞給同一裝置上的另一個應用的能力。此功能對使用者很有用,因為它允許他們在兩個應用之間共享資訊,而無需這些應用事先了解對方。

例如,在您的移動裝置上,您可以從照片應用中將照片或影片分享到另一個接受影像的應用,例如電子郵件應用。這種共享模式由安裝了這兩個應用的作業系統(OS)編排。

  1. 當用戶發起照片分享時,照片應用會準備所選影像的資料,並將其交給作業系統。
  2. 作業系統會選擇能夠處理共享影像資料的應用列表,並將其顯示給使用者。
  3. 一旦使用者選擇了一個目標應用,作業系統就會用共享的影像啟動該應用。

漸進式 Web 應用 (PWA) 也可以使用相同的 OS 編排模式來共享資訊。PWA 既可以共享資料,也可以接收共享資料。

在構建 PWA 時,接受共享資料可以讓您的 PWA 感覺更熟悉,並更自然地整合到使用者的裝置中。

與他人分享資料

要讓使用者能夠從您的 PWA 與其他應用共享資料,請使用 Web Share API。Web Share API 允許您的應用透過底層作業系統共享機制與其他應用共享文字、連結或檔案。

要共享資料,請在使用者操作(例如單擊按鈕)後使用 navigator.share() 方法。

檢查支援情況

在您的應用中顯示內容共享 UI 之前,請檢查以確保 Web Share API 功能受支援。即使支援 Web Share API 的瀏覽器,也不是所有瀏覽器都支援共享所有型別的資料。因此,最好首先使用 navigator.canShare() 方法來驗證您打算共享的資料是否確實可以從執行您應用的瀏覽器中共享。

此示例顯示瞭如何檢查 Web Share API 是否受支援以及資料是否可以共享

js
function canBrowserShareData(data) {
  if (!navigator.share || !navigator.canShare) {
    return false;
  }

  return navigator.canShare(data);
}

const sharedDataSample = {
  title: "Some text title",
  text: "More text",
  url: "A url we want to share",
};

if (canBrowserShareData(sharedDataSample)) {
  // Enable the share button in the UI.
  renderAppSharingUI();
} else {
  // We can't share on this browser/operating system.
}

處理異常

navigator.share() 方法返回一個 Promise,在共享資料不正確、使用者中止共享操作或資料傳輸失敗等情況下,該 Promise 可能會被拒絕。

因此,捕獲 Promise 拒絕對於避免您的應用 JavaScript 程式碼出錯非常重要。

js
async function shareData(data) {
  try {
    await navigator.share(data);
    // The data was shared successfully.
  } catch (e) {
    // The data could not be shared.
    console.error(`Error: ${e}`);
  }
}

共享文字資料

以下示例演示了在應用中的按鈕被單擊時如何共享連結和一些文字。示例中使用的 canBrowserShareData 函式在 檢查支援情況 中進行了描述,此處不再重複。

js
// Retrieve the button from the DOM. The button is hidden for now.
const button = document.querySelector("#share");

if (canBrowserShareData({ text: "text", url: "https://example.com" })) {
  // Show the button.
  button.style.display = "inline";

  // Listen for click events on the button to share data.
  button.addEventListener("click", async () => {
    try {
      await navigator.share({
        text: "An MDN article to learn how to share data between apps",
        url: "https://mdn.club.tw/docs/Web/Progressive_web_apps/How_to/Share_data_between_apps",
      });

      console.log("The URL was successfully shared");
    } catch (err) {
      console.error(`The URL could not be shared: ${err}`);
    }
  });
}

共享檔案

以下程式碼示例演示了在應用中的按鈕被單擊時如何共享檔案。canBrowserShareFiles 函式用於僅在瀏覽器支援檔案共享時顯示共享按鈕。

js
function canBrowserShareFiles() {
  if (!navigator.share || !navigator.canShare) {
    return false;
  }

  // Create some test data with a file, to check if the browser supports
  // sharing it.
  const testFile = new File(["foo"], "foo.txt", { type: "text/plain" });
  const data = { files: [testFile] };

  return navigator.canShare(data);
}

// Retrieve the button from the DOM. The button is hidden for now.
const button = document.querySelector("#share");

if (canBrowserShareFiles()) {
  // The browser supports sharing files. Show the button.
  button.style.display = "inline";

  // Listen for clicks on the button and share a file.
  button.addEventListener("click", async () => {
    try {
      // Get the file to be shared. This function should return a File
      // object, perhaps by creating it dynamically, or retrieving it
      // from IndexedDB.
      const file = await getTheFileToShare();

      await navigator.share({
        title: "My shared file",
        files: [file],
      });

      console.log("The file was successfully shared");
    } catch (err) {
      console.error(`The file could not be shared: ${err}`);
    }
  });
}

有關更多資訊,請參閱 navigator.share() 方法頁面上的 共享檔案示例

處理來自其他應用的共享資料

要將您的 PWA 註冊為其他應用共享資料的目標,請使用 Web Share Target API,特別是 share_target Web 應用清單成員。

share_target 清單成員允許已安裝的 PWA 在作業系統級別被註冊為其他應用共享內容的潛在目標。這意味著,當用戶從另一個應用共享與您的 PWA 相容的某些資料時,作業系統會將您的 PWA 列在電子郵件或訊息應用等典型共享目標旁邊。請注意,PWA 必須已安裝才能顯示為接收共享資料的潛在目標。

您在清單檔案中使用 share_target 成員提供的資訊,定義了您的應用可以成為哪些資料的目標,以及當用戶選擇您的應用作為目標時,作業系統應如何啟動您的應用。

處理文字資料

這是一個使用 share_target 成員的 Web 應用清單示例

json
{
  "name": "ChattyBox",
  "start_url": "/",
  "display": "standalone",
  "icons": [
    {
      "src": "images/icon-256.png",
      "sizes": "256x256",
      "type": "image/png"
    }
  ],
  "share_target": {
    "action": "/share-handler",
    "method": "GET",
    "params": {
      "text": "description",
      "url": "link"
    }
  }
}

當您的應用被使用者選中以處理其他應用的共享內容時,您的應用將被啟動,共享內容將以類似於 <form> 元素提交的方式傳遞給它。

在前面的 Web 應用清單程式碼示例中,當 ChattyBox 應用被選為目標時,它將透過對 /share-handler URL 發出 HTTP GET 請求來啟動,共享資料將作為名為 descriptionlink 的請求引數傳遞。

GET 請求將如下所示:/shared-handler?description=...&link=...

您的應用的主要 JavaScript 程式碼隨後可以使用 URLSearchParams 介面檢索共享資料。

js
const url = new URL(document.location);
const sharedDescription = url.searchParams.get("description");
const sharedLink = url.searchParams.get("link");

有關更多資訊,請參閱 share_target Web 應用清單成員頁面上的 使用 GET 接收共享資料 示例。

處理共享檔案

在前面的示例中,文字資料被作為 GET 請求處理。然而,處理檔案需要使用 POST 請求,並使用 multipart/form-data 編碼型別

以下程式碼片段展示了 PWA 如何配置為接受不同型別的共享檔案。

json
{
  "name": "ChattyBox",
  "start_url": "/",
  "display": "standalone",
  "icons": [
    {
      "src": "images/icon-256.png",
      "sizes": "256x256",
      "type": "image/png"
    }
  ],
  "share_target": {
    "action": "/share-file-handler",
    "method": "POST",
    "enctype": "multipart/form-data",
    "params": {
      "files": [
        {
          "name": "textFiles",
          "accept": ["text/plain", ".txt"]
        },
        {
          "name": "htmlFiles",
          "accept": ["text/html", ".html"]
        },
        {
          "name": "images",
          "accept": ["image/jpeg", "image/png", "image/webp", "image/gif"]
        }
      ]
    }
  }
}

如本示例所示,files 屬性中的每個檔案物件都必須具有 name 屬性和 accept 屬性。accept 屬性必須指定接受的 MIME 型別或副檔名。

當您的應用被使用者選中以處理共享檔案(或檔案)時,應用將以 POST 請求在 /share-file-handler URL 處啟動,並附帶編碼的表單資料。

由於這是一個 POST 請求,您的應用的主要 JavaScript 程式碼無法直接訪問表單資料。您可以在伺服器端程式碼中處理提交的檔案,透過在 /share-file-handler URL 端點接收它們。但是,為了獲得更好的離線體驗,您可以使用 fetch 事件處理程式在服務工作執行緒程式碼中處理檔案,如下所示。

js
// service-worker.js

self.addEventListener("fetch", (event) => {
  // Only use this event listener for POST requests sent to /share-file-handler.
  const url = new URL(event.request.url);
  if (
    event.request.method !== "POST" ||
    url.pathname !== "/share-file-handler"
  ) {
    return;
  }

  event.respondWith(
    (async () => {
      // Get the data from the submitted form.
      const formData = await event.request.formData();

      // Get the submitted files.
      const textFiles = formData.getAll("textFiles");
      const htmlFiles = formData.getAll("htmlFiles");
      const imageFiles = formData.getAll("images");

      // Send the files to the frontend app.
      sendFilesToFrontend(textFiles, htmlFiles, imageFiles);

      // Redirect the user to a URL that shows the imported files.
      return Response.redirect("/display-new-files", 303);
    })(),
  );
});

在此程式碼示例中,共享檔案從表單資料中提取,使用者被重定向到另一個頁面。您可以使用服務工作執行緒中的程式碼按照自己的意願處理提取的檔案。例如,您可以使用 Worker.postMessage() 方法將它們傳送到您應用的主 JavaScript 程式碼,或者將它們儲存在 Indexed DB 資料庫中,該資料庫可供您的服務工作執行緒和應用的主 JavaScript 程式碼訪問。

有關更多資訊,請參閱 share_target Web 應用清單成員頁面上的 接收共享檔案 示例。

另見