Google Chat アプリのホームページを作成する

このページでは、Google Chat アプリでダイレクト メッセージのホームページを作成する方法について説明します。ホームページ(Google Chat API ではアプリホーム)は、ユーザーと Chat アプリ間のダイレクト メッセージ スペースの [ホーム] タブに表示されるカスタマイズ可能なカード インターフェースです。

2 つのウィジェットを含むアプリのホームカード。
図 1: Chat 用アプリとのダイレクト メッセージに表示されるホームページの例。

アプリホームを使用すると、Chat アプリの操作に関するヒントを共有したり、ユーザーが Chat から外部のサービスやツールにアクセスして使用できるようにしたりできます。


カード作成ツールを使用して、Chat 用アプリのメッセージとユーザー インターフェースを設計してプレビューします。

カードビルダーを開く

前提条件

Node.js

インタラクション イベントを受信して応答する Google Chat 用アプリ。HTTP サービスを使用してインタラクティブな Chat 用アプリを作成するには、このクイックスタートを完了してください。

Python

インタラクション イベントを受信して応答する Google Chat 用アプリ。HTTP サービスを使用してインタラクティブな Chat 用アプリを作成するには、このクイックスタートを完了してください。

Java

インタラクション イベントを受信して応答する Google Chat 用アプリ。HTTP サービスを使用してインタラクティブな Chat 用アプリを作成するには、このクイックスタートを完了してください。

Apps Script

インタラクション イベントを受信して応答する Google Chat 用アプリ。Apps Script で双方向の Chat 用アプリを作成するには、このクイック スタートを完了してください。

Chat 用アプリのアプリホームを構成する

アプリホームをサポートするには、APP_HOME インタラクション イベントを受け取るように Chat 用アプリを構成する必要があります。ユーザーが Chat 用アプリとのダイレクト メッセージから [ホーム] タブをクリックするたびに、Chat 用アプリはこのイベントを受け取ります。

Google Cloud コンソールで構成設定を更新する手順は次のとおりです。

  1. Google Cloud コンソールで、メニュー > [その他のプロダクト] > [Google Workspace] > [プロダクト ライブラリ] > [Google Chat API] に移動します。

    Google Chat API に移動

  2. [管理] をクリックし、[構成] タブをクリックします。

  3. [インタラクティブ機能] の [機能] セクションで、[アプリのホームをサポートする] を選択します。

  4. Chat 用アプリで HTTP サービスを使用している場合は、[接続設定] に移動し、[アプリのホーム URL] フィールドのエンドポイントを指定します。[HTTP エンドポイント URL] フィールドで指定した URL を使用できます。

  5. [保存] をクリックします。

アプリのホームカードを作成する

ユーザーがアプリのホームを開くと、Chat 用アプリは pushCard ナビゲーションと Card を含む RenderActions のインスタンスを返すことで、APP_HOME インタラクション イベントを処理する必要があります。インタラクティブなエクスペリエンスを作成するために、カードには、Chat 用アプリが処理して追加のカードやダイアログで応答できるボタンやテキスト入力などのインタラクティブなウィジェットを含めることができます。

次の例では、Chat 用アプリは、カードが作成された時刻とボタンを表示する初期アプリのホームカードを表示します。ユーザーがボタンをクリックすると、Chat 用アプリは更新されたカードを返します。このカードには、更新されたカードが作成された時刻が表示されます。

Node.js

node/app-home/index.js
app.post('/', async (req, res) => {
  let event = req.body.chat;

  let body = {};
  if (event.type === 'APP_HOME') {
    // App home is requested
    body = { action: { navigations: [{
      pushCard: getHomeCard()
    }]}}
  } else if (event.type === 'SUBMIT_FORM') {
    // The update button from app home is clicked
    commonEvent = req.body.commonEventObject;
    if (commonEvent && commonEvent.invokedFunction === 'updateAppHome') {
      body = updateAppHome()
    }
  }

  return res.json(body);
});

// Create the app home card
function getHomeCard() {
  return { sections: [{ widgets: [
    { textParagraph: {
      text: "Here is the app home 🏠 It's " + new Date().toTimeString()
    }},
    { buttonList: { buttons: [{
      text: "Update app home",
      onClick: { action: {
        function: "updateAppHome"
      }}
    }]}}
  ]}]};
}

Python

python/app-home/main.py
@app.route('/', methods=['POST'])
def post() -> Mapping[str, Any]:
  """Handle requests from Google Chat

  Returns:
      Mapping[str, Any]: the response
  """
  event = request.get_json()
  match event['chat'].get('type'):

    case 'APP_HOME':
      # App home is requested
      body = { "action": { "navigations": [{
        "pushCard": get_home_card()
      }]}}

    case 'SUBMIT_FORM':
      # The update button from app home is clicked
      event_object = event.get('commonEventObject')
      if event_object is not None:
        if 'update_app_home' == event_object.get('invokedFunction'):
          body = update_app_home()

    case _:
      # Other response types are not supported
      body = {}

  return json.jsonify(body)


def get_home_card() -> Mapping[str, Any]:
  """Create the app home card

  Returns:
      Mapping[str, Any]: the card
  """
  return { "sections": [{ "widgets": [
    { "textParagraph": {
      "text": "Here is the app home 🏠 It's " +
        datetime.datetime.now().isoformat()
    }},
    { "buttonList": { "buttons": [{
      "text": "Update app home",
      "onClick": { "action": {
        "function": "update_app_home"
      }}
    }]}}
  ]}]}

Java

java/app-home/src/main/java/com/google/chat/app/home/App.java
// Process Google Chat events
@PostMapping("/")
@ResponseBody
public GenericJson onEvent(@RequestBody JsonNode event) throws Exception {
  switch (event.at("/chat/type").asText()) {
    case "APP_HOME":
      // App home is requested
      GenericJson navigation = new GenericJson();
      navigation.set("pushCard", getHomeCard());

      GenericJson action = new GenericJson();
      action.set("navigations", List.of(navigation));

      GenericJson response = new GenericJson();
      response.set("action", action);
      return response;
    case "SUBMIT_FORM":
      // The update button from app home is clicked
      if (event.at("/commonEventObject/invokedFunction").asText().equals("updateAppHome")) {
        return updateAppHome();
      }
  }

  return new GenericJson();
}

// Create the app home card
GoogleAppsCardV1Card getHomeCard() {
  return new GoogleAppsCardV1Card()
    .setSections(List.of(new GoogleAppsCardV1Section()
      .setWidgets(List.of(
        new GoogleAppsCardV1Widget()
          .setTextParagraph(new GoogleAppsCardV1TextParagraph()
            .setText("Here is the app home 🏠 It's " + new Date())),
        new GoogleAppsCardV1Widget()
          .setButtonList(new GoogleAppsCardV1ButtonList().setButtons(List.of(new GoogleAppsCardV1Button()
            .setText("Update app home")
            .setOnClick(new GoogleAppsCardV1OnClick()
              .setAction(new GoogleAppsCardV1Action()
                .setFunction("updateAppHome"))))))))));
}

Apps Script

すべての APP_HOME インタラクション イベントの後に呼び出される onAppHome 関数を実装します。

この例では、カード JSON を返すことでカード メッセージを送信します。Apps Script カードサービスを使用することもできます。

apps-script/app-home/app-home.gs
/**
 * Responds to a APP_HOME event in Google Chat.
 */
function onAppHome() {
  return { action: { navigations: [{
    pushCard: getHomeCard()
  }]}};
}

/**
 * Returns the app home card.
 */
function getHomeCard() {
  return { sections: [{ widgets: [
    { textParagraph: {
      text: "Here is the app home 🏠 It's " + new Date().toTimeString()
    }},
    { buttonList: { buttons: [{
      text: "Update app home",
      onClick: { action: {
        function: "updateAppHome"
      }}
    }]}}
  ]}]};
}

アプリのホーム画面の操作に応答する

アプリの最初のホームカードにボタンや選択入力などのインタラクティブなウィジェットが含まれている場合、Chat 用アプリは、updateCard ナビゲーションを含む RenderActions のインスタンスを返すことで、関連するインタラクション イベントを処理する必要があります。インタラクティブ ウィジェットの処理について詳しくは、ユーザーが入力した情報を処理するをご覧ください。

前の例では、アプリの最初のホームカードにボタンが含まれていました。ユーザーがボタンをクリックするたびに、CARD_CLICKED インタラクション イベントがトリガーされ、次のコードに示すように、関数 updateAppHome がアプリのホームカードを更新します。

Node.js

node/app-home/index.js
// Update the app home
function updateAppHome() {
  return { renderActions: { action: { navigations: [{
    updateCard: getHomeCard()
  }]}}}
};

Python

python/app-home/main.py
def update_app_home() -> Mapping[str, Any]:
  """Update the app home

  Returns:
      Mapping[str, Any]: the update card render action
  """
  return { "renderActions": { "action": { "navigations": [{
    "updateCard": get_home_card()
  }]}}}

Java

java/app-home/src/main/java/com/google/chat/app/home/App.java
// Update the app home
GenericJson updateAppHome() {
  GenericJson navigation = new GenericJson();
  navigation.set("updateCard", getHomeCard());

  GenericJson action = new GenericJson();
  action.set("navigations", List.of(navigation));

  GenericJson renderActions = new GenericJson();
  renderActions.set("action", action);

  GenericJson response = new GenericJson();
  response.set("renderActions", renderActions);
  return response;
}

Apps Script

この例では、カード JSON を返すことでカード メッセージを送信します。Apps Script カードサービスを使用することもできます。

apps-script/app-home/app-home.gs
/**
 * Updates the home app.
 */
function updateAppHome() {
  return { renderActions: { action: { navigations: [{
    updateCard: getHomeCard()
  }]}}};
}

ダイアログを開く

Chat 用アプリは、ダイアログを開いて、アプリのホームでのインタラクションに応答することもできます。

さまざまなウィジェットが表示されたダイアログ。
図 3: ユーザーに連絡先の追加を求めるダイアログ。

アプリのホームからダイアログを開くには、Card オブジェクトを含む updateCard ナビゲーションで renderActions を返すことで、関連するインタラクション イベントを処理します。次の例では、Chat 用アプリがアプリのホームカードのボタンクリックに応答して、CARD_CLICKED インタラクション イベントを処理し、ダイアログを開きます。

{ renderActions: { action: { navigations: [{ updateCard: { sections: [{
  header: "Add new contact",
  widgets: [{ "textInput": {
    label: "Name",
    type: "SINGLE_LINE",
    name: "contactName"
  }}, { textInput: {
    label: "Address",
    type: "MULTIPLE_LINE",
    name: "address"
  }}, { decoratedText: {
    text: "Add to favorites",
    switchControl: {
      controlType: "SWITCH",
      name: "saveFavorite"
    }
  }}, { decoratedText: {
    text: "Merge with existing contacts",
    switchControl: {
      controlType: "SWITCH",
      name: "mergeContact",
      selected: true
    }
  }}, { buttonList: { buttons: [{
    text: "Next",
    onClick: { action: { function: "openSequentialDialog" }}
  }]}}]
}]}}]}}}

ダイアログを閉じるには、次のインタラクション イベントを処理します。

  • CLOSE_DIALOG: ダイアログを閉じて、Chat 用アプリの最初のアプリホームカードに戻ります。
  • CLOSE_DIALOG_AND_EXECUTE: ダイアログを閉じ、アプリのホームカードを更新します。

次のコードサンプルでは、CLOSE_DIALOG を使用してダイアログを閉じ、アプリのホームカードに戻ります。

{ renderActions: { action: {
  navigations: [{ endNavigation: { action: "CLOSE_DIALOG" }}]
}}}

ユーザーから情報を収集するために、連続したダイアログを構築することもできます。順次ダイアログを構築する方法については、ダイアログを開いて応答するをご覧ください。