ウェブ機能の Codelab

1. 導入と設定

ウェブ機能

Google は、ウェブとネイティブの間の機能のギャップを埋め、デベロッパーがオープンウェブで優れたエクスペリエンスを簡単に構築できるようにしたいと考えています。Google は、すべてのデベロッパーが優れたウェブ エクスペリエンスを提供するために必要な機能にアクセスできるべきだと強く信じており、ウェブの機能強化に取り組んでいます。

ただし、ファイル システムへのアクセスやアイドル状態の検出など、ネイティブでは使用できるものの、ウェブでは使用できない機能もあります。こうした機能が不足しているため、アプリの種類によっては、ウェブで配信できない、または有用性が低くなっていることがあります。

Google は、既存のオープンウェブ プラットフォーム標準プロセスを利用しながら、これらの新機能をオープンかつ透明性のある方法で設計、開発します。設計の反復作業の中でデベロッパーや他のブラウザ ベンダーから早期のフィードバックを得て、設計の相互運用性を確保します。

作成するアプリの概要

この Codelab では、まったく新しいウェブ API やフラグによってのみ利用可能な、いくつかのウェブ API をいろいろ試してみます。そのため、この Codelab では、特定の最終プロダクトを構築することではなく、API 自体と、これらの API によって実現されるユースケースに重点を置きます。

学習内容

この Codelab では、最先端の API の基本的なメカニズムについて学習します。この仕組みはまだ確定していません。デベロッパー フローに関するフィードバックをいただき、ありがとうございました。

必要なもの

この Codelab で取り上げる API は開発の最先端技術であり、各 API の要件は異なります。各セクションの冒頭にある互換性に関する情報をよくお読みください。

Codelab の進め方

この Codelab は、必ずしも順番に学習することを意図したものではありません。各セクションは 1 つの独立した API を表し、関心のあるものを自由に選んでください。

2. Badging API

Badging API の目的は、ユーザーにバックグラウンドで行われていることに注意を払うことができます。この Codelab のデモを簡単にするため、ここでは API を使用して注意を向けることができますそうすることで、バックグラウンドで行われている処理に精神を移すことができます。

Airhorner をインストールする

この API を機能させるには、ホーム画面にインストールする PWA が必要であるため、まず世界的に有名な airhorner.com などの PWA をインストールします。右上にある [Install] ボタンをクリックするか、その他メニューを使用して手動でインストールします。

8b7fa8b3c94c6bdd.png

確認プロンプトが表示されたら、[インストール] をクリックします。

98e90422167ac786.png

これで、オペレーティング システムのドックに新しいアイコンが表示されます。これをクリックして PWA を起動します。専用のアプリ ウィンドウがあり、スタンドアロン モードで実行されます。

バッジの設定

PWA をインストールしたので、バッジを表示するには数値データが必要です(バッジには数字のみを含めることができます)。The Air Horner では、ため息をつけた回数を簡単に数えられます。実際、インストールされている Airhorner アプリでホーンを曲げて、バッジを確認してください。クラクションを鳴らすたびに 1 つカウントされます。

b5e39de7a1775054.png

では、その仕組みについて説明します。基本的に、コードは次のようになります。

let hornCounter = 0;
const horn = document.querySelector('.horn');
horn.addEventListener('click', () => {
  navigator.setExperimentalAppBadge(++hornCounter);
});

エアホーンを数回鳴らして、PWA のアイコンを確認します。アイコンは毎回更新されます。あります。あります。鳴ります。とても簡単です。

eed10c3ffe59999.png

バッジをクリアする

カウンタは 99 まで進み、その後またスタートします。手動でリセットすることもできます。DevTools コンソールのタブを開き、以下の行を貼り付けて、Enter キーを押します。

navigator.setExperimentalAppBadge(0);

または、次のスニペットに示すように、バッジを明示的にクリアして消去することもできます。これで PWA のアイコンが元の図のように見え、バッジなしで鮮明になります。

navigator.clearExperimentalAppBadge();

33eafb314a3a9f30.png

フィードバック

この API についての感想をお聞かせください。よろしければ、簡単なアンケートにお答えください。

この API は直感的に使えましたか?

はい いいえ

例は実行できましたか?

<ph type="x-smartling-placeholder"></ph> × をご覧ください。

他にご意見がございましたらお聞かせください。不足している機能はありましたか?こちらのアンケートから簡単なフィードバックをお寄せください。ありがとうございました

3. ネイティブ ファイル システム API

デベロッパーは、Native File System API を使用して、ユーザーのローカル デバイス上のファイルとやり取りする強力なウェブアプリを構築できます。ユーザーがウェブアプリにアクセス権を付与すると、ウェブアプリはこの API を使用して、ユーザーのデバイス上のファイルとフォルダの変更の読み取りや保存を直接行えます。

ファイルの読み取り

「Hello, World」ローカル ファイルを読み取ってファイルの内容を取得するというものです。プレーンな .txt ファイルを作成し、テキストを入力します。次に、example.com などの安全なサイト(HTTPS 経由で配信されるサイト)に移動して、DevTools コンソールを開きます。以下のコード スニペットをコンソールに貼り付けます。Native File System API はユーザー操作を必要とするため、ドキュメントにダブルクリック ハンドラをアタッチします。後でファイル ハンドルが必要になるため、グローバル変数にします。

document.ondblclick = async () => {
  window.handle = await window.chooseFileSystemEntries();
  const file = await handle.getFile();
  document.body.textContent = await file.text();
};

c02679081eb4d538.png

次に、example.com ページの任意の場所をダブルクリックすると、ファイル選択ツールが表示されます。

d98962600d62d149.png

以前に作成した .txt ファイルを選択します。ファイルの内容によって、example.com の実際の body の内容が置き換えられます。

eace3d15bd4f8192.png

ファイルを保存する

次に、いくつか変更を加えます。そのため、以下のコード スニペットを貼り付けて、body を編集可能にしましょう。これで、ブラウザがテキスト エディタであるかのようにテキストを編集できます。

document.body.contentEditable = true;

ca32797417449343.png

次に、これらの変更を元のファイルに書き戻します。そのため、ファイル ハンドルに Writer が必要です。これは、以下のスニペットをコンソールに貼り付けることで取得できます。ここでもユーザー操作が必要なので、今度はメイン ドキュメントがクリックされるのを待ちます。

document.onclick = async () => {
  const writer = await handle.createWriter();
  await writer.truncate(0);
  await writer.write(0, document.body.textContent);
  await writer.close();
};

d2729a8f76f43073.png

ドキュメントをダブルクリックではなくクリックしたときに、権限を求めるメッセージが表示されます。権限を付与すると、ファイルの内容は、以前に body で編集したものになります。別のエディタでファイルを開いて変更を確認します(ドキュメントをもう一度ダブルクリックしてファイルを開き直します)。

2eccf61fe4a46109.png

202263abdedae737.png

これで、世界最小のテキスト エディタ「[citation needed]」が作成されました。

フィードバック

この API についての感想をお聞かせください。よろしければ、簡単なアンケートにお答えください。

この API は直感的に使えましたか?

はい いいえ

例は実行できましたか?

<ph type="x-smartling-placeholder"></ph> × をご覧ください。

他にご意見がございましたらお聞かせください。不足している機能はありましたか?こちらのアンケートから簡単なフィードバックをお寄せください。ありがとうございました

4. 形状検出 API

Shape Detection API は、高速の形状検出機能(人の顔など)へのアクセスを提供し、静止画像やライブ画像フィードで動作します。オペレーティング システムには、Android の FaceDetector など、パフォーマンスと高度に最適化された機能検出機能が搭載されています。Shape Detection API は、こうしたネイティブ実装を開いて、一連の JavaScript インターフェースを通じて公開します。

現在サポートされている機能は、FaceDetector インターフェースによる顔検出、BarcodeDetector インターフェースによるバーコード検出、TextDetector インターフェースによるテキスト検出(光学式文字認識)です。

顔検出

Shape Detection API の魅力的な機能は、顔検出です。テストするには、顔を含むページが必要です。作成者の顔を載せているこのページは出発点として最適です。次のスクリーンショットのようになります。サポートされているブラウザでは、顔の境界ボックスと顔ランドマークが認識されます。

Glitch プロジェクト、特に script.js ファイルをリミックスまたは編集することで、これを実現するために必要なコードがどれほど必要だったかがわかります。

f4aa7b77a0a1d1f5.png

作成者の顔を認識するだけでなく、完全に動的に機能したい場合は、プライベート タブまたはゲストモードで、さまざまな顔で構成されたこの Google 検索の検索結果ページにアクセスしてください。表示されたページで、右クリックして [検証] をクリックし、Chrome デベロッパー ツールを開きます。次に、[コンソール] タブに以下のスニペットを貼り付けます。検出された顔が半透明の赤いボックスでハイライト表示されます。

document.querySelectorAll('img[alt]:not([alt=""])').forEach(async (img) => {
  try {
    const faces = await new FaceDetector().detect(img);
    faces.forEach(face => {
      const div = document.createElement('div');
      const box = face.boundingBox;
      const computedStyle = getComputedStyle(img);
      const [top, right, bottom, left] = [
        computedStyle.marginTop,
        computedStyle.marginRight,
        computedStyle.marginBottom,
        computedStyle.marginLeft
      ].map(m => parseInt(m, 10));
      const scaleX = img.width / img.naturalWidth;
      const scaleY = img.height / img.naturalHeight;
      div.style.backgroundColor = 'rgba(255, 0, 0, 0.5)';
      div.style.position = 'absolute';
      div.style.top = `${scaleY * box.top + top}px`;
      div.style.left = `${scaleX * box.left + left}px`;
      div.style.width = `${scaleX * box.width}px`;
      div.style.height = `${scaleY * box.height}px`;
      img.before(div);
    });
  } catch(e) {
    console.error(e);
  }
});

DOMException」のメッセージがいくつかありますが、すべての画像が処理されているわけではありません。これは、スクロールせずに見える範囲の画像はデータ URI としてインライン化されており、アクセスできるためです。スクロールせずに見える範囲の画像は、CORS をサポートするように構成されていない別のドメインから取得されます。このデモでは、これについて心配する必要はありません。

顔ランドマーク検出

macOS では、顔だけでなく、顔のランドマークの検出もサポートされています。顔のランドマークの検出をテストするには、次のスニペットをコンソールに貼り付けます。注: crbug.com/914348 のため、ランドマークのラインナップはまったく完璧ではありませんが、今後の方向性と、この機能がどれほど強力であるかは確認できます。

document.querySelectorAll('img[alt]:not([alt=""])').forEach(async (img) => {
  try {
    const faces = await new FaceDetector().detect(img);
    faces.forEach(face => {
      const div = document.createElement('div');
      const box = face.boundingBox;
      const computedStyle = getComputedStyle(img);
      const [top, right, bottom, left] = [
        computedStyle.marginTop,
        computedStyle.marginRight,
        computedStyle.marginBottom,
        computedStyle.marginLeft
      ].map(m => parseInt(m, 10));
      const scaleX = img.width / img.naturalWidth;
      const scaleY = img.height / img.naturalHeight;
      div.style.backgroundColor = 'rgba(255, 0, 0, 0.5)';
      div.style.position = 'absolute';
      div.style.top = `${scaleY * box.top + top}px`;
      div.style.left = `${scaleX * box.left + left}px`;
      div.style.width = `${scaleX * box.width}px`;
      div.style.height = `${scaleY * box.height}px`;
      img.before(div);

      const landmarkSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
      landmarkSVG.style.position = 'absolute';
      landmarkSVG.classList.add('landmarks');
      landmarkSVG.setAttribute('viewBox', `0 0 ${img.width} ${img.height}`);
      landmarkSVG.style.width = `${img.width}px`;
      landmarkSVG.style.height = `${img.height}px`;
      face.landmarks.map((landmark) => {                    
        landmarkSVG.innerHTML += `<polygon class="landmark-${landmark.type}" points="${
        landmark.locations.map((point) => {          
          return `${scaleX * point.x},${scaleY * point.y} `;
        }).join(' ')
      }" /></svg>`;          
      });
      div.before(landmarkSVG);
    });
  } catch(e) {
    console.error(e);
  }
});

バーコード検出

Shape Detection API の 2 つ目の機能は、バーコード検出です。前回と同様に、こちらのようなバーコードが記載されたページが必要です。ブラウザでアプリを開くと、解読されたさまざまな QR コードが表示されます。Glitch プロジェクト(特に script.js ファイル)をリミックスまたは編集して、作成方法を確認します。

7778003ff472389b.png

より動的な画像が必要な場合は、再び Google 画像検索を使用できます。今度は、ブラウザでプライベート タブまたはゲストモードでこの Google 検索の検索結果ページに移動します。Chrome DevTools コンソールのタブに以下のスニペットを貼り付けます。しばらくすると、認識されたバーコードに未加工の値とバーコードの種類のアノテーションが表示されます。

document.querySelectorAll('img[alt]:not([alt=""])').forEach(async (img) => {
  try {
    const barcodes = await new BarcodeDetector().detect(img);
    barcodes.forEach(barcode => {
      const div = document.createElement('div');
      const box = barcode.boundingBox;
      const computedStyle = getComputedStyle(img);
      const [top, right, bottom, left] = [
        computedStyle.marginTop,
        computedStyle.marginRight,
        computedStyle.marginBottom,
        computedStyle.marginLeft
      ].map(m => parseInt(m, 10));
      const scaleX = img.width / img.naturalWidth;
      const scaleY = img.height / img.naturalHeight;
      div.style.backgroundColor = 'rgba(255, 255, 255, 0.75)';
      div.style.position = 'absolute';
      div.style.top = `${scaleY * box.top + top}px`;
      div.style.left = `${scaleX * box.left - left}px`;
      div.style.width = `${scaleX * box.width}px`;
      div.style.height = `${scaleY * box.height}px`;
      div.style.color = 'black';
      div.style.fontSize = '14px';      
      div.textContent = `${barcode.rawValue}`;
      img.before(div);
    });
  } catch(e) {
    console.error(e);
  }
});

テキスト検出

Shape Detection API の最後の機能は、テキスト検出です。やり方についてはおわかりいただけたでしょうか。Google ブックスのスキャン結果を含むこちらのようなテキストを含む画像のあるページが必要です。サポートされているブラウザでは、テキストが認識され、テキスト文章の周囲に境界ボックスが描画されます。Glitch プロジェクト(特に script.js ファイル)をリミックスまたは編集して、作成方法を確認します。

ec2be17d1e4d01ba.png

これを動的にテストするには、検索結果ページをプライベート タブまたはゲストモードでアクセスしてください。Chrome DevTools コンソールのタブに以下のスニペットを貼り付けます。少し待つと、一部のテキストが認識されます。

document.querySelectorAll('img[alt]:not([alt=""])').forEach(async (img) => {
  try {
    const texts = await new TextDetector().detect(img);
    texts.forEach(text => {
      const div = document.createElement('div');
      const box = text.boundingBox;
      const computedStyle = getComputedStyle(img);
      const [top, right, bottom, left] = [
        computedStyle.marginTop,
        computedStyle.marginRight,
        computedStyle.marginBottom,
        computedStyle.marginLeft
      ].map(m => parseInt(m, 10));
      const scaleX = img.width / img.naturalWidth;
      const scaleY = img.height / img.naturalHeight;
      div.style.backgroundColor = 'rgba(255, 255, 255, 0.75)';
      div.style.position = 'absolute';
      div.style.top = `${scaleY * box.top + top}px`;
      div.style.left = `${scaleX * box.left - left}px`;
      div.style.width = `${scaleX * box.width}px`;
      div.style.height = `${scaleY * box.height}px`;
      div.style.color = 'black';
      div.style.fontSize = '14px';      
      div.innerHTML = text.rawValue;
      img.before(div);
    });
  } catch(e) {
    console.error(e);
  }
});

フィードバック

この API についての感想をお聞かせください。よろしければ、簡単なアンケートにお答えください。

この API は直感的に使えましたか?

はい いいえ

例は実行できましたか?

<ph type="x-smartling-placeholder"></ph> × をご覧ください。

他にご意見がございましたらお聞かせください。不足している機能はありましたか?こちらのアンケートから簡単なフィードバックをお寄せください。ありがとうございました

5. ウェブ共有ターゲット API

Web Share Target API を使用すると、インストール済みのウェブアプリを共有ターゲットとして基盤となるオペレーティング システムに登録して、Web Share API またはシステム イベント(オペレーティング システム レベルの共有ボタンなど)から共有コンテンツを受け取ることができます。

共有先の PWA をインストールする

まず、共有可能な PWA が必要です。今回は Airhorner(幸いなことに)は役に立ちませんが、Web Share Target デモアプリがあなたの味方となります。デバイスのホーム画面にアプリをインストールします。

925df16a12638bb2.png

PWA にコンテンツを共有する

次に、共有対象(Google フォトの写真など)が必要になります。[共有] ボタンを使用し、共有ターゲットとしてスクラップブック PWA を選択します。

7216e8bb1be6d6db.png

アプリアイコンをタップすると、スクラップブック PWA に直接移動し、写真がそのまま表示されます。

9016985cb4bb48fe.png

では、その仕組みについて説明します。詳しくは、Scrapbook PWA のウェブアプリ マニフェストをご覧ください。Web Share Target API を機能させる構成は、マニフェストの "share_target" プロパティにあります。"action" フィールドでは、"params" にリストされているパラメータで装飾された URL を参照します。

その後、共有側はこの URL テンプレートに適宜データを入力します(共有アクションによって処理されるようにするか、デベロッパーが Web Share API を使用してプログラムで制御します)。これにより、受信側はパラメータを抽出して、それを使ってなんらかの処理(表示など)を行うことができます。

{
  "action": "/_share-target",
  "enctype": "multipart/form-data",
  "method": "POST",
  "params": {
    "files": [{
      "name": "media",
      "accept": ["audio/*", "image/*", "video/*"]
    }]
  }
}

フィードバック

この API についての感想をお聞かせください。よろしければ、簡単なアンケートにお答えください。

この API は直感的に使えましたか?

はい いいえ

例は実行できましたか?

<ph type="x-smartling-placeholder"></ph> × をご覧ください。

他にご意見がございましたらお聞かせください。不足している機能はありましたか?こちらのアンケートから簡単なフィードバックをお寄せください。ありがとうございました

6. Wake Lock API

ほとんどのデバイスはバッテリーの消耗を避けるため、アイドル状態のままですぐにスリープ状態になります。ほとんどの場合はこれで問題ありませんが、一部のアプリケーションでは、処理を完了するために画面またはデバイスのスリープ状態を維持する必要があります。Wake Lock API は、デバイスの画面を暗くしたりロックしたりしないようにする方法や、デバイスがスリープ状態にならないようにする機能を提供します。この機能により、これまでネイティブ アプリが必要だった新しいエクスペリエンスが実現します。

スクリーンセーバーを設定する

Wake Lock API をテストするには、まずデバイスがスリープ状態になることを確認する必要があります。そのため、オペレーティング システムの設定ペインで任意のスクリーンセーバーを有効にし、1 分後に開始するようにしてください。その間デバイスを放置して動作を確認します(確かに苦労します)。以下のスクリーンショットは macOS の例ですが、もちろん Android モバイル デバイスやサポートされているデスクトップ プラットフォームで試してみることもできます。

6f345e8c2b6c22c.png

画面の wake lock を設定する

スクリーンセーバーが機能していることを確認したら、"screen" タイプの wake lock を使用して、スクリーンセーバーが機能しないようにします。Wake Lock デモアプリにアクセスし、[Activate ] をクリックします

screen [Wake Lock] チェックボックスをオンにします。

12ed15dd94f51d4d.png

その時点から wake lock がアクティブになります。しばらくデバイスを開いたままにしておくと、スクリーンセーバーが実際に起動していないことがわかります。

では、その仕組みについて説明します。確認するには、Wake Lock デモアプリの Glitch プロジェクトにアクセスして script.js をチェックしてください。コードの要点は、以下のスニペットにあります。新しいタブを開き(または開いているタブを使用して)、Chrome デベロッパー ツールのコンソールに以下のコードを貼り付けます。ウィンドウをクリックすると、ウェイクロックがちょうど 10 秒間表示されます(コンソールログを参照)。スクリーンセーバーは起動しません。

if ('wakeLock' in navigator && 'request' in navigator.wakeLock) {  
  let wakeLock = null;
  
  const requestWakeLock = async () => {
    try {
      wakeLock = await navigator.wakeLock.request('screen');
      wakeLock.addEventListener('release', () => {        
        console.log('Wake Lock was released');                    
      });
      console.log('Wake Lock is active');      
    } catch (e) {      
      console.error(`${e.name}, ${e.message}`);
    } 
  };

  requestWakeLock();
  window.setTimeout(() => {
    wakeLock.release();
  }, 10 * 1000);
}

621c2654d06a7cce.png

フィードバック

この API についての感想をお聞かせください。よろしければ、簡単なアンケートにお答えください。

この API は直感的に使えましたか?

はい いいえ

例は実行できましたか?

<ph type="x-smartling-placeholder"></ph> × をご覧ください。

他にご意見がございましたらお聞かせください。不足している機能はありましたか?こちらのアンケートから簡単なフィードバックをお寄せください。ありがとうございました

7. Contact Picker API

私たちがとても楽しみにしている API は、Contact Picker API です。これにより、ウェブアプリがデバイスのネイティブの連絡先管理ツールから連絡先にアクセスできるため、ウェブアプリが連絡先にアクセスできるようになります。名前、メールアドレス、電話番号などです。連絡先を 1 件のみとするか複数とするか、すべてのフィールドを含めるか、名前、メールアドレス、電話番号の一部のみを含めるかを指定できます。

プライバシーへの配慮

選択ツールが開いたら、共有する連絡先を選択できます。[すべて選択] オプションがオプションです。これは、共有は意識的に決定することを意図しています。同様に、アクセスも継続的ではなく、1 回限りの決定です。

連絡先へのアクセス

連絡先へのアクセスは簡単です。選択ツールが開く前に、必要なフィールド(nameemailtelephone から選択できます)と、複数の連絡先にアクセスするか 1 つの連絡先のみにアクセスするかを指定できます。Android デバイスでこの API をテストするには、デモアプリを開きます。ソースコードの関連するセクションは、基本的に次のスニペットです。

getContactsButton.addEventListener('click', async () => {
  const contacts = await navigator.contacts.select(
      ['name', 'email'],
      {multiple: true});
  if (!contacts.length) {
    // No contacts were selected, or picker couldn't be opened.
    return;
  }
  console.log(contacts);
});

de94db2dfb7c67af.png

8. Async Clipboard API

テキストのコピーと貼り付け

これまでは、画像をプログラムでシステムのクリップボードにコピーして貼り付ける方法はありませんでした。先日、Async Clipboard API に画像のサポートを追加しました。

画像をコピーして貼り付けることができます新機能は、クリップボードに画像を書き込むこともできる点です。非同期クリップボード API は、しばらくの間、テキストのコピーと貼り付けをサポートしていました。navigator.clipboard.writeText() を呼び出してクリップボードにテキストをコピーし、後で navigator.clipboard.readText() を呼び出してそのテキストを貼り付けることができます。

画像のコピーと貼り付け

クリップボードに画像を書き込むこともできます。これを行うには、画像データを blob として用意し、それをクリップボードのアイテム コンストラクタに渡す必要があります。最後に、navigator.clipboard.write() を呼び出してこのクリップボード アイテムをコピーできます。

// Copy: Writing image to the clipboard
try {
  const imgURL = 'https://developers.google.com/web/updates/images/generic/file.png';
  const data = await fetch(imgURL);
  const blob = await data.blob();
  await navigator.clipboard.write([
    new ClipboardItem(Object.defineProperty({}, blob.type, {
      value: blob,
      enumerable: true
    }))
  ]);
  console.log('Image copied.');
} catch(e) {
  console.error(e, e.message);
}

クリップボードから画像を貼り付け直す作業は複雑に見えますが、実際には、クリップボード アイテムから blob を取得するだけで済みます。複数のパターンが存在する可能性があるため、目的の 1 つが得られるまでループする必要があります。セキュリティ上の理由から、現時点では PNG 画像に限定されていますが、今後より多くの画像形式がサポートされる可能性があります。

async function getClipboardContents() {
  try {
    const clipboardItems = await navigator.clipboard.read();
    for (const clipboardItem of clipboardItems) {
      try {
        for (const type of clipboardItem.types) {
          const blob = await clipboardItem.getType(type);
          console.log(URL.createObjectURL(blob));
        }
      } catch (e) {
        console.error(e, e.message);
      }
    }
  } catch (e) {
    console.error(e, e.message);
  }
}

この API の実際の動作はデモアプリで確認できます。ソースコードの関連するスニペットは上に埋め込まれています。クリップボードへの画像のコピーは許可なく実行できますが、クリップボードから貼り付けるにはアクセスを許可する必要があります。

99f6dbf35ff4f393.png

アクセスを許可したら、クリップボードから画像を読み取り、アプリケーションに貼り付けることができます。

ace5945f4aca70ff.png

9. お疲れさまでした。

これでこの Codelab は終了です。繰り返しになりますが、このことは、ほとんどの API が依然として流動的であり、積極的に開発されていることを再認識させています。そのため、フィードバックへのご協力に心より感謝いたします。これらの API を適切に機能させるためには、お客様の皆様とのみ対応してください。

また、機能に関するランディング ページを頻繁に確認することもおすすめします。常に最新の状態に保ちます。開発中の API に関する詳細な記事も掲載しています。その調子です!

Tom、Capabilities チーム全体 🐡?