링크 미리보기

사용자가 Google Chat에서 링크를 공유할 때 컨텍스트 전환을 방지하기 위해 채팅 앱은 추가 정보를 제공하고 사용자가 Google Chat에서 바로 조치를 취할 수 있도록 하는 카드를 메시지에 첨부하여 링크를 미리 볼 수 있습니다.

예를 들어 회사의 모든 고객 서비스 상담사와 Case-y라는 Chat 앱이 포함된 Google Chat 스페이스를 생각해 보세요. 상담사는 Chat 스페이스에서 고객 서비스 케이스 링크를 자주 공유하며, 이때마다 동료가 케이스 링크를 열어 담당자, 상태, 제목과 같은 세부정보를 확인해야 합니다. 마찬가지로 케이스의 소유권을 가져오거나 상태를 변경하려는 경우 링크를 열어야 합니다.

링크 미리보기를 사용하면 스페이스의 상주 채팅 앱인 Case-y에서 사용자가 케이스 링크를 공유할 때마다 담당자, 상태, 제목을 보여주는 카드를 첨부할 수 있습니다. 카드의 버튼을 사용하면 상담사가 케이스의 소유권을 가져와 채팅 스트림에서 직접 상태를 변경할 수 있습니다.

누군가 메시지에 링크를 추가하면 채팅 앱에서 링크를 미리 볼 수 있음을 알려주는 칩이 표시됩니다.

Chat 앱에서 링크 미리보기를 표시할 수 있음을 나타내는 칩

메시지를 보낸 후 채팅 앱으로 링크가 전송되면 앱에서 카드를 생성하여 사용자 메시지에 첨부합니다.

메시지에 카드를 첨부하여 링크를 미리 보는 Chat 앱

카드에서는 링크와 함께 버튼과 같은 상호작용 요소를 비롯하여 링크에 관한 추가 정보를 제공합니다. Chat 앱은 버튼 클릭과 같은 사용자 상호작용에 응답하여 첨부된 카드를 업데이트할 수 있습니다.

Chat 앱에서 메시지에 카드를 첨부하여 링크를 미리 보지 못하게 하려면 미리보기 칩에서 아이콘을 클릭하면 됩니다. 사용자는 언제든지 미리보기 삭제를 클릭하여 첨부된 카드를 삭제할 수 있습니다.

기본 요건

Node.js

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

Python

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

자바

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

Apps Script

양방향 기능이 사용 설정된 Google Chat 앱 Apps Script에서 양방향 Chat 앱을 만들려면 이 빠른 시작을 완료하세요.

채팅 앱에서 미리 볼 수 있도록 특정 링크(예: example.com, support.example.com, support.example.com/cases/)를 Google Cloud 콘솔의 채팅 앱 구성 페이지에서 URL 패턴으로 등록합니다.

링크 미리보기 구성 메뉴

  1. Google Cloud 콘솔을 엽니다. 
  2. 'Google Cloud' 옆에 있는 아래쪽 화살표 를 클릭하고 채팅 앱의 프로젝트를 엽니다.
  3. 검색창에 Google Chat API를 입력하고 Google Chat API를 클릭합니다.
  4. 관리 > 구성을 클릭합니다.
  5. 링크 미리보기에서 URL 패턴을 추가하거나 수정합니다.
    1. 새 URL 패턴의 링크 미리보기를 구성하려면 URL 패턴 추가를 클릭합니다.
    2. 기존 URL 패턴에 대한 구성을 수정하려면 아래쪽 화살표 를 클릭합니다.
  6. 호스트 패턴 입력란에 URL 패턴의 도메인을 입력합니다. 채팅 앱에서 이 도메인으로 연결되는 링크를 미리 볼 수 있습니다.

    subdomain.example.com과 같은 특정 하위 도메인의 채팅 앱 미리보기 링크를 사용하려면 하위 도메인을 포함합니다.

    전체 도메인에 채팅 앱 미리보기 링크를 사용하려면 하위 도메인으로 별표 (*)가 있는 와일드 카드 문자를 지정합니다. 예를 들어 *.example.comsubdomain.example.comany.number.of.subdomains.example.com와 일치합니다.

  7. 경로 접두사 필드에 호스트 패턴 도메인에 추가할 경로를 입력합니다.

    호스트 패턴 도메인의 모든 URL과 일치시키려면 경로 접두사를 비워 둡니다.

    예를 들어 호스트 패턴이 support.example.com인 경우 support.example.com/cases/에 호스팅된 케이스의 URL과 일치시키려면 cases/을 입력합니다.

  8. 완료를 클릭합니다.

  9. 저장을 클릭합니다.

이제 사용자가 Chat 앱이 포함된 Chat 스페이스의 메시지에 링크 미리보기 URL 패턴과 일치하는 링크를 포함할 때마다 앱에서 링크를 미리 봅니다.

특정 링크의 링크 미리보기를 구성하면 Chat 앱에서 더 많은 정보를 링크에 연결하여 링크를 인식하고 미리 볼 수 있습니다.

Chat 앱이 포함된 Chat 스페이스 내에서 다른 사용자의 메시지에 링크 미리보기 URL 패턴과 일치하는 링크가 포함되면 Chat 앱은 MESSAGE 상호작용 이벤트를 수신합니다. 상호작용 이벤트의 JSON 페이로드에는 matchedUrl 필드가 포함됩니다.

JSON

message: {
  matchedUrl: {
    url: "https://support.example.com/cases/case123"
  },
  ... // other message attributes redacted
}

MESSAGE 이벤트 페이로드에 matchedUrl 필드가 있는지 확인하면 채팅 앱에서 미리보기된 링크로 메시지에 정보를 추가할 수 있습니다. Chat 앱은 기본 문자 메시지로 답장하거나 카드를 첨부할 수 있습니다.

SMS로 답장하기

기본 응답의 경우 채팅 앱은 링크에 간단한 텍스트 메시지로 답장하여 링크를 미리 볼 수 있습니다. 이 예에서는 링크 미리보기 URL 패턴과 일치하는 링크 URL을 반복하는 메시지를 첨부합니다.

Node.js

node/preview-link/index.js
// Reply with a text message for URLs of the subdomain "text"
if (event.message.matchedUrl.url.includes("text.example.com")) {
  return {
    text: 'event.message.matchedUrl.url: ' + event.message.matchedUrl.url
  };
}

Python

python/preview-link/main.py
# Reply with a text message for URLs of the subdomain "text"
if 'text.example.com' in event.get('message').get('matchedUrl').get('url'):
  return {
    'text': 'event.message.matchedUrl.url: ' +
            event.get('message').get('matchedUrl').get('url')
  }

자바

java/preview-link/src/main/java/com/google/chat/preview/App.java
// Reply with a text message for URLs of the subdomain "text"
if (event.at("/message/matchedUrl/url").asText().contains("text.example.com")) {
  return new Message().setText("event.message.matchedUrl.url: " +
    event.at("/message/matchedUrl/url").asText());
}

Apps Script

apps-script/preview-link/preview-link.gs
// Reply with a text message for URLs of the subdomain "text"
if (event.message.matchedUrl.url.includes("text.example.com")) {
  return {
    text: 'event.message.matchedUrl.url: ' + event.message.matchedUrl.url
  };
}

미리보기된 링크에 카드를 연결하려면 UPDATE_USER_MESSAGE_CARDS 유형의 ActionResponse를 반환합니다. 이 예에서는 기본 카드를 첨부합니다.

메시지에 카드를 첨부하여 링크를 미리 보는 Chat 앱

Node.js

node/preview-link/index.js
// Attach a card to the message for URLs of the subdomain "support"
if (event.message.matchedUrl.url.includes("support.example.com")) {
  // A hard-coded card is used in this example. In a real-life scenario,
  // the case information would be fetched and used to build the card.
  return {
    actionResponse: { type: 'UPDATE_USER_MESSAGE_CARDS' },
    cardsV2: [{
      cardId: 'attachCard',
      card: {
        header: {
          title: 'Example Customer Service Case',
          subtitle: 'Case basics',
        },
        sections: [{ widgets: [
          { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
          { decoratedText: { topLabel: 'Assignee', text: 'Charlie'}},
          { decoratedText: { topLabel: 'Status', text: 'Open'}},
          { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
          { buttonList: { buttons: [{
            text: 'OPEN CASE',
            onClick: { openLink: {
              url: 'https://support.example.com/orders/case123'
            }},
          }, {
            text: 'RESOLVE CASE',
            onClick: { openLink: {
              url: 'https://support.example.com/orders/case123?resolved=y',
            }},
          }, {
            text: 'ASSIGN TO ME',
            onClick: { action: { function: 'assign'}}
          }]}}
        ]}]
      }
    }]
  };
}

Python

python/preview-link/main.py
# Attach a card to the message for URLs of the subdomain "support"
if 'support.example.com' in event.get('message').get('matchedUrl').get('url'):
  # A hard-coded card is used in this example. In a real-life scenario,
  # the case information would be fetched and used to build the card.
  return {
    'actionResponse': { 'type': 'UPDATE_USER_MESSAGE_CARDS' },
    'cardsV2': [{
      'cardId': 'attachCard',
      'card': {
        'header': {
          'title': 'Example Customer Service Case',
          'subtitle': 'Case basics',
        },
        'sections': [{ 'widgets': [
          { 'decoratedText': { 'topLabel': 'Case ID', 'text': 'case123'}},
          { 'decoratedText': { 'topLabel': 'Assignee', 'text': 'Charlie'}},
          { 'decoratedText': { 'topLabel': 'Status', 'text': 'Open'}},
          { 'decoratedText': { 'topLabel': 'Subject', 'text': 'It won\'t turn on...' }},
          { 'buttonList': { 'buttons': [{
            'text': 'OPEN CASE',
            'onClick': { 'openLink': {
              'url': 'https://support.example.com/orders/case123'
            }},
          }, {
            'text': 'RESOLVE CASE',
            'onClick': { 'openLink': {
              'url': 'https://support.example.com/orders/case123?resolved=y',
            }},
          }, {
            'text': 'ASSIGN TO ME',
            'onClick': { 'action': { 'function': 'assign'}}
          }]}}
        ]}]
      }
    }]
  }

자바

java/preview-link/src/main/java/com/google/chat/preview/App.java
// Attach a card to the message for URLs of the subdomain "support"
if (event.at("/message/matchedUrl/url").asText().contains("support.example.com")) {
  // A hard-coded card is used in this example. In a real-life scenario,
  // the case information would be fetched and used to build the card.
  return new Message()
    .setActionResponse(new ActionResponse()
      .setType("UPDATE_USER_MESSAGE_CARDS"))
    .setCardsV2(List.of(new CardWithId()
      .setCardId("attachCard")
      .setCard(new GoogleAppsCardV1Card()
        .setHeader(new GoogleAppsCardV1CardHeader()
          .setTitle("Example Customer Service Case")
          .setSubtitle("Case basics"))
        .setSections(List.of(new GoogleAppsCardV1Section().setWidgets(List.of(
          new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
            .setTopLabel("Case ID")
            .setText("case123")),
          new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
            .setTopLabel("Assignee")
            .setText("Charlie")),
          new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
            .setTopLabel("Status")
            .setText("Open")),
          new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
            .setTopLabel("Subject")
            .setText("It won't turn on...")),
          new GoogleAppsCardV1Widget()
            .setButtonList(new GoogleAppsCardV1ButtonList().setButtons(List.of(
              new GoogleAppsCardV1Button()
                .setText("OPEN CASE")
                .setOnClick(new GoogleAppsCardV1OnClick()
                  .setOpenLink(new GoogleAppsCardV1OpenLink()
                    .setUrl("https://support.example.com/orders/case123"))),
              new GoogleAppsCardV1Button()
                .setText("RESOLVE CASE")
                .setOnClick(new GoogleAppsCardV1OnClick()
                  .setOpenLink(new GoogleAppsCardV1OpenLink()
                    .setUrl("https://support.example.com/orders/case123?resolved=y"))),
              new GoogleAppsCardV1Button()
                .setText("ASSIGN TO ME")
                .setOnClick(new GoogleAppsCardV1OnClick()
                  .setAction(new GoogleAppsCardV1Action().setFunction("assign")))))))))))));
}

Apps Script

이 예에서는 카드 JSON을 반환하여 카드 메시지를 전송합니다. Apps Script 카드 서비스를 사용할 수도 있습니다.

apps-script/preview-link/preview-link.gs
// Attach a card to the message for URLs of the subdomain "support"
if (event.message.matchedUrl.url.includes("support.example.com")) {
  // A hard-coded card is used in this example. In a real-life scenario,
  // the case information would be fetched and used to build the card.
  return {
    actionResponse: { type: 'UPDATE_USER_MESSAGE_CARDS' },
    cardsV2: [{
      cardId: 'attachCard',
      card: {
        header: {
          title: 'Example Customer Service Case',
          subtitle: 'Case basics',
        },
        sections: [{ widgets: [
          { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
          { decoratedText: { topLabel: 'Assignee', text: 'Charlie'}},
          { decoratedText: { topLabel: 'Status', text: 'Open'}},
          { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
          { buttonList: { buttons: [{
            text: 'OPEN CASE',
            onClick: { openLink: {
              url: 'https://support.example.com/orders/case123'
            }},
          }, {
            text: 'RESOLVE CASE',
            onClick: { openLink: {
              url: 'https://support.example.com/orders/case123?resolved=y',
            }},
          }, {
            text: 'ASSIGN TO ME',
            onClick: { action: { function: 'assign'}}
          }]}}
        ]}]
      }
    }]
  };
}

Chat 앱은 사용자가 카드의 버튼을 클릭하는 등 카드와 상호작용할 때 링크 미리보기 카드를 업데이트할 수 있습니다.

카드를 업데이트하려면 Chat 앱에서 CARD_CLICKED 상호작용 이벤트를 처리하고 링크 미리보기가 포함된 메시지를 보낸 사용자를 기반으로 actionResponse를 반환해야 합니다.

  • 사용자가 메시지를 보낸 경우 actionResponse.typeUPDATE_USER_MESSAGE_CARDS로 설정합니다.
  • Chat 앱에서 메시지를 전송한 경우 actionResponse.typeUPDATE_MESSAGE로 설정합니다.

메시지를 보낸 사용자를 확인하려면 상호작용 이벤트의 message.sender.type 필드를 사용하여 발신자가 HUMAN 사용자인지 BOT인지 확인하면 됩니다.

다음 예에서는 사용자가 카드의 Assignee 필드를 업데이트하고 버튼을 사용 중지하여 사용자가 Assign to Me 버튼을 클릭할 때마다 채팅 앱에서 링크 미리보기를 업데이트하는 방법을 보여줍니다.

메시지에 첨부된 카드의 업데이트된 버전이 포함된 링크를 미리 보는 채팅 앱

Node.js

node/preview-link/index.js
/**
 * Updates a card that was attached to a message with a previewed link.
 *
 * @param {Object} event The event object from Chat.
 *
 * @return {Object} Response from the Chat app. Either a new card attached to
 * the message with the previewed link, or an update to an existing card.
 */
function onCardClick(event) {
  // To respond to the correct button, checks the button's actionMethodName.
  if (event.action.actionMethodName === 'assign') {
    // A hard-coded card is used in this example. In a real-life scenario,
    // an actual assign action would be performed before building the card.

    // Checks whether the message event originated from a human or a Chat app
    // and sets actionResponse.type to "UPDATE_USER_MESSAGE_CARDS if human or
    // "UPDATE_MESSAGE" if Chat app.
    const actionResponseType = event.message.sender.type === 'HUMAN' ?
      'UPDATE_USER_MESSAGE_CARDS' :
      'UPDATE_MESSAGE';

    // Returns the updated card that displays "You" for the assignee
    // and that disables the button.
    return {
      actionResponse: { type: actionResponseType },
      cardsV2: [{
        cardId: 'attachCard',
        card: {
          header: {
            title: 'Example Customer Service Case',
            subtitle: 'Case basics',
          },
          sections: [{ widgets: [
            { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
            // The assignee is now "You"
            { decoratedText: { topLabel: 'Assignee', text: 'You'}},
            { decoratedText: { topLabel: 'Status', text: 'Open'}},
            { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
            { buttonList: { buttons: [{
              text: 'OPEN CASE',
              onClick: { openLink: {
                url: 'https://support.example.com/orders/case123'
              }},
            }, {
              text: 'RESOLVE CASE',
              onClick: { openLink: {
                url: 'https://support.example.com/orders/case123?resolved=y',
              }},
            }, {
              text: 'ASSIGN TO ME',
              // The button is now disabled
              disabled: true,
              onClick: { action: { function: 'assign'}}
            }]}}
          ]}]
        }
      }]
    };
  }
}

Python

python/preview-link/main.py
def on_card_click(event: dict) -> dict:
  """Updates a card that was attached to a message with a previewed link."""
  # To respond to the correct button, checks the button's actionMethodName.
  if 'assign' == event.get('action').get('actionMethodName'):
    # A hard-coded card is used in this example. In a real-life scenario,
    # an actual assign action would be performed before building the card.

    # Checks whether the message event originated from a human or a Chat app
    # and sets actionResponse.type to "UPDATE_USER_MESSAGE_CARDS if human or
    # "UPDATE_MESSAGE" if Chat app.
    actionResponseType = 'UPDATE_USER_MESSAGE_CARDS' if \
      event.get('message').get('sender').get('type') == 'HUMAN' else \
      'UPDATE_MESSAGE'

    # Returns the updated card that displays "You" for the assignee
    # and that disables the button.
    return {
      'actionResponse': { 'type': actionResponseType },
      'cardsV2': [{
        'cardId': 'attachCard',
        'card': {
          'header': {
            'title': 'Example Customer Service Case',
            'subtitle': 'Case basics',
          },
          'sections': [{ 'widgets': [
            { 'decoratedText': { 'topLabel': 'Case ID', 'text': 'case123'}},
            # The assignee is now "You"
            { 'decoratedText': { 'topLabel': 'Assignee', 'text': 'You'}},
            { 'decoratedText': { 'topLabel': 'Status', 'text': 'Open'}},
            { 'decoratedText': { 'topLabel': 'Subject', 'text': 'It won\'t turn on...' }},
            { 'buttonList': { 'buttons': [{
              'text': 'OPEN CASE',
              'onClick': { 'openLink': {
                'url': 'https://support.example.com/orders/case123'
              }},
            }, {
              'text': 'RESOLVE CASE',
              'onClick': { 'openLink': {
                'url': 'https://support.example.com/orders/case123?resolved=y',
              }},
            }, {
              'text': 'ASSIGN TO ME',
              # The button is now disabled
              'disabled': True,
              'onClick': { 'action': { 'function': 'assign'}}
            }]}}
          ]}]
        }
      }]
    }

자바

java/preview-link/src/main/java/com/google/chat/preview/App.java
// Updates a card that was attached to a message with a previewed link.
Message onCardClick(JsonNode event) {
  // To respond to the correct button, checks the button's actionMethodName.
  if (event.at("/action/actionMethodName").asText().equals("assign")) {
    // A hard-coded card is used in this example. In a real-life scenario,
    // an actual assign action would be performed before building the card.

    // Checks whether the message event originated from a human or a Chat app
    // and sets actionResponse.type to "UPDATE_USER_MESSAGE_CARDS if human or
    // "UPDATE_MESSAGE" if Chat app.
    String actionResponseType =
      event.at("/message/sender/type").asText().equals("HUMAN")
      ? "UPDATE_USER_MESSAGE_CARDS" : "UPDATE_MESSAGE";

    // Returns the updated card that displays "You" for the assignee
    // and that disables the button.
    return new Message()
    .setActionResponse(new ActionResponse()
      .setType(actionResponseType))
    .setCardsV2(List.of(new CardWithId()
      .setCardId("attachCard")
      .setCard(new GoogleAppsCardV1Card()
        .setHeader(new GoogleAppsCardV1CardHeader()
          .setTitle("Example Customer Service Case")
          .setSubtitle("Case basics"))
        .setSections(List.of(new GoogleAppsCardV1Section().setWidgets(List.of(
          new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
            .setTopLabel("Case ID")
            .setText("case123")),
          new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
            .setTopLabel("Assignee")
            // The assignee is now "You"
            .setText("You")),
          new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
            .setTopLabel("Status")
            .setText("Open")),
          new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
            .setTopLabel("Subject")
            .setText("It won't turn on...")),
          new GoogleAppsCardV1Widget()
            .setButtonList(new GoogleAppsCardV1ButtonList().setButtons(List.of(
              new GoogleAppsCardV1Button()
                .setText("OPEN CASE")
                .setOnClick(new GoogleAppsCardV1OnClick()
                  .setOpenLink(new GoogleAppsCardV1OpenLink()
                    .setUrl("https://support.example.com/orders/case123"))),
              new GoogleAppsCardV1Button()
                .setText("RESOLVE CASE")
                .setOnClick(new GoogleAppsCardV1OnClick()
                  .setOpenLink(new GoogleAppsCardV1OpenLink()
                    .setUrl("https://support.example.com/orders/case123?resolved=y"))),
              new GoogleAppsCardV1Button()
                .setText("ASSIGN TO ME")
                // The button is now disabled
                .setDisabled(true)
                .setOnClick(new GoogleAppsCardV1OnClick()
                  .setAction(new GoogleAppsCardV1Action().setFunction("assign")))))))))))));
  }
  return null;
}

Apps Script

이 예에서는 카드 JSON을 반환하여 카드 메시지를 전송합니다. Apps Script 카드 서비스를 사용할 수도 있습니다.

apps-script/preview-link/preview-link.gs
/**
 * Updates a card that was attached to a message with a previewed link.
 *
 * @param {Object} event The event object from Chat.
 *
 * @return {Object} Response from the Chat app. Either a new card attached to
 * the message with the previewed link, or an update to an existing card.
 */
function onCardClick(event) {
  // To respond to the correct button, checks the button's actionMethodName.
  if (event.action.actionMethodName === 'assign') {
    // A hard-coded card is used in this example. In a real-life scenario,
    // an actual assign action would be performed before building the card.

    // Checks whether the message event originated from a human or a Chat app
    // and sets actionResponse.type to "UPDATE_USER_MESSAGE_CARDS if human or
    // "UPDATE_MESSAGE" if Chat app.
    const actionResponseType = event.message.sender.type === 'HUMAN' ?
      'UPDATE_USER_MESSAGE_CARDS' :
      'UPDATE_MESSAGE';

    // Returns the updated card that displays "You" for the assignee
    // and that disables the button.
    return {
      actionResponse: { type: actionResponseType },
      cardsV2: [{
        cardId: 'attachCard',
        card: {
          header: {
            title: 'Example Customer Service Case',
            subtitle: 'Case basics',
          },
          sections: [{ widgets: [
            { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
            // The assignee is now "You"
            { decoratedText: { topLabel: 'Assignee', text: 'You'}},
            { decoratedText: { topLabel: 'Status', text: 'Open'}},
            { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
            { buttonList: { buttons: [{
              text: 'OPEN CASE',
              onClick: { openLink: {
                url: 'https://support.example.com/orders/case123'
              }},
            }, {
              text: 'RESOLVE CASE',
              onClick: { openLink: {
                url: 'https://support.example.com/orders/case123?resolved=y',
              }},
            }, {
              text: 'ASSIGN TO ME',
              // The button is now disabled
              disabled: true,
              onClick: { action: { function: 'assign'}}
            }]}}
          ]}]
        }
      }]
    };
  }
}

제한사항 및 고려사항

Chat 앱의 링크 미리보기를 구성할 때 다음 제한사항과 고려사항에 유의하세요.

  • 각 채팅 앱은 최대 5개의 URL 패턴에 대한 링크 미리보기를 지원합니다.
  • Chat 앱은 메시지당 하나의 링크를 미리 봅니다. 단일 메시지에 미리 볼 수 있는 링크가 여러 개 있는 경우 미리 볼 수 있는 첫 번째 링크만 미리 볼 수 있습니다.
  • Chat 앱은 https://로 시작하는 링크만 미리보기하므로 https://support.example.com/cases/는 미리보기를 하지만 support.example.com/cases/는 미리보기를 하지 않습니다.
  • 슬래시 명령어와 같이 채팅 앱으로 전송되는 다른 정보가 메시지에 포함되어 있지 않으면 링크 URL만 채팅 앱으로 링크 미리보기를 통해 전송됩니다.
  • 사용자가 링크를 게시하는 경우 채팅 앱은 사용자가 버튼 클릭과 같이 카드와 상호작용할 때만 링크 미리보기 카드를 업데이트할 수 있습니다. Message 리소스에서 Chat API의 update() 메서드를 호출하여 사용자의 메시지를 비동기식으로 업데이트할 수 없습니다.
  • 채팅 앱은 스페이스의 모든 사용자에게 링크를 미리 보여야 하므로 메시지에서 privateMessageViewer 필드를 생략해야 합니다.

링크 미리보기를 구현할 때 앱의 로그를 읽어 채팅 앱을 디버그해야 할 수 있습니다. 로그를 읽으려면 Google Cloud 콘솔의 로그 탐색기를 방문하세요.