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. [インタラクティブ機能] の [機能] セクションに移動して、アプリのホームを構成します。

    1. [1 対 1 のメッセージを受信する] チェックボックスをオンにします。
    2. [App Home をサポートする] チェックボックスをオンにします。
  4. Chat アプリが HTTP サービスを使用している場合は、[接続設定] に移動し、[アプリのホームページ URL] フィールドにエンドポイントを指定します。[HTTP エンドポイント URL] フィールドで指定した URL を使用できます。

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

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

ユーザーがアプリのホームを開いたとき、Chat アプリは、pushCard ナビゲーションと Card を使用して RenderActions のインスタンスを返すことにより、APP_HOME インタラクション イベントを処理する必要があります。インタラクティブなエクスペリエンスを作成するには、カードにボタンやテキスト入力などのインタラクティブなウィジェットを含めることができます。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 を返すことにより、関連する操作イベントを処理します。次の例では、CARD_CLICKED インタラクション イベントを処理してダイアログを開くことで、アプリのホームカードからのボタンクリックに Chat アプリが応答します。

{ 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" }}]
}}}

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