Google Chat 앱의 홈페이지 빌드하기

이 페이지에서는 Google Chat 앱을 사용하여 채팅 메시지 홈페이지를 만드는 방법을 설명합니다. 홈페이지(Google Chat API에서 앱 홈이라고 함)는 사용자와 채팅 앱 간 채팅 메시지 공간 탭에 표시되는 맞춤설정 가능한 카드 인터페이스입니다.

위젯이 2개 있는 앱 홈 카드
그림 1: 채팅 앱과의 채팅 메시지에 표시되는 홈페이지의 예

앱 홈을 사용하여 채팅 앱과 상호작용하거나 사용자가 Chat의 외부 서비스 또는 도구에 액세스하고 이를 사용하도록 하기 위한 팁을 공유할 수 있습니다.


카드 작성 도구를 사용하여 Chat 앱의 메시지 및 사용자 인터페이스를 디자인하고 미리 볼 수 있습니다.

카드 빌더를 엽니다.

기본 요건

Node.js

대화형 기능이 사용 설정된 Google Chat 앱 HTTP 서비스를 사용하여 대화형 Chat 앱을 만들려면 이 빠른 시작을 완료하세요.

Python

대화형 기능이 사용 설정된 Google Chat 앱 HTTP 서비스를 사용하여 대화형 Chat 앱을 만들려면 이 빠른 시작을 완료하세요.

자바

양방향 기능이 사용 설정된 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. Support App Home 체크박스를 선택합니다.
  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/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"
      }}
    }]}}
  ]}]};
}

앱 홈 상호작용에 응답

초기 앱 홈 카드에 버튼이나 선택 입력과 같은 대화형 위젯이 포함된 경우 채팅 앱은 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/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()
  }]}}};
}

대화상자 열기

채팅 앱은 대화상자를 열어 앱 홈의 상호작용에 응답할 수도 있습니다.

다양한 위젯이 표시된 대화상자
그림 3: 사용자에게 연락처를 추가하라는 메시지가 표시되는 대화상자

앱 홈에서 대화상자를 열려면 Card 객체가 포함된 updateCard 탐색으로 renderActions를 반환하여 관련 상호작용 이벤트를 처리합니다. 다음 예에서는 채팅 앱이 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: 대화상자를 닫고 채팅 앱의 초기 앱 홈 카드로 돌아갑니다.
  • CLOSE_DIALOG_AND_EXECUTE: 대화상자를 닫고 앱 홈 카드를 새로고침합니다.

다음 코드 샘플은 CLOSE_DIALOG를 사용하여 대화상자를 닫고 앱 홈 카드로 돌아갑니다.

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

사용자로부터 정보를 수집하기 위해 순차 대화상자를 빌드할 수도 있습니다. 순차 대화상자를 빌드하는 방법을 알아보려면 대화상자 열기 및 응답을 참고하세요.