정적 카드

간단한 REST API를 사용하여 정적 카드를 삽입하고 업데이트하고 읽을 수 있습니다. 또한 위치나 미디어와 같은 객체를 정적 카드에 연결할 수 있습니다.

작동 방식

정적 카드는 기본적으로 Glass 시계 오른쪽에 있으며 전송 시 사용자와 관련된 정보를 표시합니다. 하지만 실시간 카드와 같은 즉각적인 주의가 필요하지 않으며 사용자는 자신의 여가에 따라 카드를 읽거나 조치를 취할 수 있습니다.

Glass 소프트웨어에서 정적 카드를 타임라인에 삽입하면 Glass에서 알림음을 재생하여 사용자에게 알릴 수 있습니다. 이전의 모든 정적 카드도 오른쪽으로 이동하며 7일 후 또는 200개 최신 카드인 경우 타임라인에서 사라집니다.

용도

정적 카드는 중요한 상황이 발생할 때 사용자에게 주기적 알림을 전달하는 데 유용합니다. 가장 인기 있는 뉴스를 실시간으로 전송하는 뉴스 전송 서비스 등이 여기에 해당합니다. 미러링 API 정적 카드는 OPEN_URI 메뉴 항목을 통해 라이브 카드 또는 몰입을 시작할 수도 있습니다. 이를 통해 정적 카드를 알림으로 활용하고 실시간 카드 또는 몰입도를 사용하여 더 많은 상호작용을 지원하는 하이브리드 상호작용을 만들 수 있습니다.

타임라인 항목에 가능한 작업의 전체 목록은 참조 문서를 확인하세요.

정적 카드 삽입

정적 카드 (타임라인 항목)를 삽입하려면 타임라인 항목의 JSON 표현을 REST 엔드포인트에 게시합니다.

타임라인 항목의 필드는 대부분 선택사항입니다. 가장 간단한 형식의 타임라인 항목에는 다음 예와 같이 짧은 텍스트 메시지만 포함됩니다.

원시 HTTP

POST /mirror/v1/timeline HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer {auth token}
Content-Type: application/json
Content-Length: 26

{ "text": "Hello world" }

자바

TimelineItem timelineItem = new TimelineItem();
timelineItem.setText("Hello world");
service.timeline().insert(timelineItem).execute();

Python

timeline_item = {'text': 'Hello world'}
service.timeline().insert(body=timeline_item).execute()

성공하면 생성된 항목의 전체 사본이 포함된 201 Created 응답 코드가 전송됩니다. 이전 예시에서 성공적인 응답은 다음과 같을 수 있습니다.

원시 HTTP

HTTP/1.1 201 Created
Date: Tue, 25 Sep 2012 23:30:11 GMT
Content-Type: application/json
Content-Length: 303

{
 "kind": "glass#timelineItem",
 "id": "1234567890",
 "selfLink": "https://www.googleapis.com/mirror/v1/timeline/1234567890",
 "created": "2012-09-25T23:28:43.192Z",
 "updated": "2012-09-25T23:28:43.192Z",
 "etag": "\"G5BI0RWvj-0jWdBrdWrPZV7xPKw/t25selcGS3uDEVT6FB09hAG-QQ\"",
 "text": "Hello world"
}

사용자의 타임라인에 표시되는 삽입된 항목은 다음과 같습니다.

첨부파일이 있는 타임라인 항목 삽입

사진 한 장이 천 마디의 말보다 효과적입니다. 이는 타임라인에 넣을 수 있는 것보다 훨씬 많은 양입니다. 이를 위해 이미지 및 동영상을 타임라인 항목에 연결할 수도 있습니다. 다음은 사진이 첨부된 타임라인 항목을 삽입하는 방법의 예입니다.

원시 HTTP

POST /upload/mirror/v1/timeline HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer {auth token}
Content-Type: multipart/related; boundary="mymultipartboundary"
Content-Length: {length}

--mymultipartboundary
Content-Type: application/json; charset=UTF-8

{ "text": "A solar eclipse of Saturn. Earth is also in this photo. Can you find it?" }
--mymultipartboundary
Content-Type: image/jpeg
Content-Transfer-Encoding: binary

[binary image data]
--mymultipartboundary--

자바

TimelineItem timelineItem = new TimelineItem();
timelineItem.setText("Hello world");
InputStreamContent mediaContent = new InputStreamContent(contentType, attachment);
service.timeline().insert(timelineItem, mediaContent).execute();

Python

timeline_item = {'text': 'Hello world'}
media_body = MediaIoBaseUpload(
    io.BytesIO(attachment), mimetype=content_type, resumable=True)
service.timeline().insert(body=timeline_item, media_body=media_body).execute()

이미지가 첨부된 타임라인 항목은 Glass에서 다음과 같이 표시됩니다.

동영상 첨부

타임라인 항목에 동영상 파일을 첨부하는 경우 전체 페이로드를 한 번에 업로드하는 대신 동영상을 스트리밍하는 것이 좋습니다. Google Mirror API는 HTTP 실시간 스트리밍, 프로그레시브 다운로드, 실시간 스트리밍 프로토콜 (RTSP)을 사용한 스트리밍을 지원합니다. RTSP는 방화벽으로 인해 차단되는 경우가 많으므로 가능하면 다른 옵션을 사용합니다.

동영상을 스트리밍하려면 PLAY_VIDEO 내장 메뉴 항목을 사용하고 동영상의 URL을 메뉴 항목의 payload로 지정합니다. 자세한 내용은 내장 메뉴 항목 추가지원되는 미디어 형식 추가를 참고하세요.

페이지 나누기

단일 타임라인 카드에 맞지 않지만 동일한 카드에 연결되어야 하는 타임라인 항목을 페이지로 나눌 수 있습니다. 페이지로 나눈 항목은 모두 동일한 timeline.id를 공유하므로 메뉴 항목 집합이 동일합니다. 사용자가 페이지로 나눈 타임라인 항목을 탭하면 자세히 알아보기 메뉴 항목이 표시됩니다.

Glass는 text를 표시하는 타임라인 항목을 자동으로 페이지로 나눕니다. Glass가 html를 자동으로 페이지 나누기하도록 하려면 다음 예와 같이 클래스 속성이 auto-paginate로 설정된 article 태그를 사용하세요.

<article class="auto-paginate">
 <h3>Very long list</h3>
 <ul>
   <li>First item</li>
   <li>Second item</li>
   <li>Third item</li>
   <li>Fourth item</li>
   <li>Fifth item</li>
   <li>Sixth item</li>
   <li>...</li>
 </ul>
<article>

수동으로 페이지로 나누려면 각 카드에 표시할 콘텐츠의 article 태그를 사용합니다. Glass는 별도의 하위 타임라인 카드에 각 article 태그의 콘텐츠를 표시합니다. 예를 들어 다음 HTML을 사용하여 페이지로 나눈 타임라인 항목을 만들 수 있습니다.

<article>
 <section>
   <p>First page</p>
 </section>
</article>

<article>
 <section>
   <p>Second page</p>
 </section>
</article>

<article>
 <section>
   <p>Third page</p>
 </section>
</article>

기본적으로 페이지로 나눈 타임라인 항목의 첫 번째 카드가 표지 카드로 표시되고 사용자가 자세히 알아보기 메뉴 항목을 선택하면 다시 표시됩니다. 자세히 알아보기를 탭한 후 첫 번째 카드가 다시 표시되지 않도록 하려면 첫 번째 <article> 태그에 cover-only CSS 클래스를 지정하면 됩니다.

<article class="cover-only">
...

cover-only 클래스는 자동 페이지 나누기 타임라인 항목도 지원합니다.

<article class="auto-paginate cover-only">
...

번들로 묶기

번들을 사용하면 이메일 대화목록의 개별 메시지처럼 관련이 있지만 고유한 항목을 그룹화할 수 있습니다. 번들에는 사용자가 탭하는 기본 커버 카드가 있으며, 번들의 다른 카드가 포함된 하위 타임라인을 표시합니다. 번들은 커버 카드의 오른쪽 상단에 모서리를 접히는 일반 타임라인 카드와 구별됩니다.

타임라인 항목을 번들로 묶으려면 bundleId에 동일한 값을 사용하여 항목을 만듭니다. 가장 최근에 추가된 항목은 번들의 표지입니다.

다음 이미지는 오른쪽 상단에 모서리가 접히고 그 아래에 번들 카드 두 개가 있는 번들 표지 카드를 보여줍니다.

타임라인 항목 읽기

서비스는 자신이 만든 모든 타임라인 항목 및 이 서비스와 공유된 모든 타임라인 항목에 액세스할 수 있습니다. 다음은 서비스에 표시되는 타임라인 항목을 나열하는 방법입니다.

원시 HTTP

GET /mirror/v1/timeline HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer {auth token}

자바

TimelineItem timelineItem = new TimelineItem();
service.timeline().list().execute();

Python

service.timeline().list().execute()

다른 REST 작업을 사용하여 타임라인 항목을 가져오기, 업데이트, 삭제할 수 있습니다.

첨부파일 액세스

attachments라는 배열 속성을 통해 타임라인 항목에 대한 첨부파일에 액세스할 수 있습니다. 그런 다음 첨부파일의 contentUrl 속성이나 첨부파일 엔드포인트를 통해 연결의 바이너리 데이터를 가져올 수 있습니다.

원시 HTTP

GET /mirror/v1/timeline/{itemId}/attachments/{attachmentId} HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer {auth token}

자바

TimelineItem item = service.timeline().get(itemId).execute();
String attachmentId = item.getAttachments().get(0).getId();
service.attachments().get(itemId, attachmentId).executeAsInputStream();

메뉴 항목 만들기

메뉴 항목을 통해 사용자는 타임라인 카드와 관련된 작업을 요청할 수 있으며, 두 가지 유형(내장 메뉴 항목 및 맞춤 메뉴 항목)이 제공됩니다.

내장된 메뉴 항목을 통해 타임라인 카드를 소리내어 읽기, 위치로 이동, 이미지 공유, 메시지에 답장하기 등 Glass에서 제공하는 특수 기능에 액세스할 수 있습니다.

맞춤 메뉴 항목을 사용하면 애플리케이션에서 Glass 소프트웨어의 특정 동작을 노출할 수 있으며 메뉴 항목에 아이콘을 추가하여 브랜드와 일치시킬 수도 있습니다.

내장 메뉴 항목 추가

menuItems array을 삽입할 때 기본 제공 메뉴 항목을 타임라인 항목에 추가할 수 있습니다. 내장된 메뉴 항목을 사용하려면 각 menuItemaction만 채우면 됩니다.

원시 HTTP

HTTP/1.1 201 Created
Date: Tue, 25 Sep 2012 23:30:11 GMT
Content-Type: application/json
Content-Length: 303

{
  "text": "Hello world",
  "menuItems": [
    {
      "action": "REPLY"
    }
  ]
}

맞춤 메뉴 항목 정의

기본 제공 메뉴 항목이 작동하지 않는 경우 타임라인 항목을 삽입하거나 업데이트할 때 다음을 실행하여 자체 작업으로 맞춤 메뉴 항목을 만들 수 있습니다.

  • menuItem.actionCUSTOM를 지정합니다.
  • menuItem.id를 지정합니다. 사용자가 맞춤 메뉴 항목을 탭하면 Glass 소프트웨어는 menuItem.id가 채워진 알림을 수신합니다. 이를 통해 알림의 출처를 파악할 수 있습니다.
  • menuItem.values를 지정하여 Glass에 표시되는 iconUrldisplayName를 추가합니다. iconUrl의 투명한 배경에 흰색의 50x50 PNG 이미지를 가리킵니다.
  • displayTime를 지정합니다. displayTime를 지정하지 않으면 사용자가 맞춤 메뉴 항목을 탭할 때마다 타임라인 항목이 타임라인 앞으로 이동합니다.

원시 HTTP

HTTP/1.1 201 Created
Date: Tue, 25 Sep 2012 23:30:11 GMT
Content-Type: application/json
Content-Length: 303

{
  "text": "Hello world",
  "displayTime": "2013-08-08T22:47:31-07:00",
  "menuItems": [
    {
      "action": "CUSTOM",
      "id": "complete"
      "values": [{
        "displayName": "Complete",
        "iconUrl": "http://example.com/icons/complete.png"
      }]
    }
  ]
}

사용자가 타임라인 카드를 고정하도록 허용

사용자가 타임라인 카드를 고정할 수 있는 메뉴 항목을 만들면 타임라인 카드를 기본 시계 카드 왼쪽에 영구적으로 표시할 수 있습니다. 사용자는 동일한 메뉴 항목을 사용하여 카드를 고정 해제할 수도 있습니다.

고정 메뉴 항목은 기본 제공 메뉴 항목이므로 menuItemTOGGLE_PINNED action를 제공하기만 하면 됩니다.

원시 HTTP

HTTP/1.1 201 Created
Date: Tue, 25 Sep 2012 23:30:11 GMT
Content-Type: application/json
Content-Length: 303

{
  "text": "You can pin or unpin this card.",
 "menuItems": [
    {
      "action": "TOGGLE_PINNED"
    }
  ...
 ]
}

구독

Mirror API를 사용하면 사용자가 타임라인 항목에서 특정 작업을 하거나 사용자 위치가 업데이트된 경우 전송되는 알림을 구독할 수 있습니다. 알림을 구독하면 알림을 처리하는 콜백 URL을 제공합니다.

알림 수신

Mirror API의 알림은 JSON 요청 본문이 포함된 구독한 엔드포인트에 POST 요청으로 전송됩니다.

원시 HTTP

{
  "collection": "timeline",
  "itemId": "3hidvm0xez6r8_dacdb3103b8b604_h8rpllg",
  "operation": "UPDATE",
  "userToken": "harold_penguin",
  "verifyToken": "random_hash_to_verify_referer",
  "userActions": [
    {
      "type": "<TYPE>",
      "payload": "<PAYLOAD>"
    }
  ]
}

자바

import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.mirror.model.Notification;

import java.io.IOException;
import java.io.InputStream;
// ...

public class MyClass {
  // ...

  /**
    * Parse a request body into a Notification object.
    *
    * @param requestBody The notification payload sent by the Mirror API.
    * @return Parsed notification payload if successful, {@code null} otherwise.
    */
  static Notification parseNotification(InputStream requestBody) {
    try {
      JsonFactory jsonFactory = new JacksonFactory();

      return jsonFactory.fromInputStream(requetBody, Notification.class);
    } catch (IOException e) {
      System.out.println("An error occurred: " + e);
      return null;
    }
  }

  // ...
}

Python

import json

def parse_notification(request_body):
  """Parse a request body into a notification dict.

  Params:
    request_body: The notification payload sent by the Mirror API as a string.
  Returns:
    Dict representing the notification payload.
  """
  return json.load(request_body)

오류가 발생하지 않은 경우 서비스는 200 OK HTTP 상태 코드로 API에 응답해야 합니다. 서비스가 오류 코드로 응답하면 Mirror API가 서비스에 알림을 다시 전송하려고 시도할 수 있습니다.

알림 유형

Mirror API는 다양한 이벤트에 대해 다른 알림 페이로드를 전송합니다.

답장

사용자가 기본 제공 REPLY 메뉴 항목을 사용하여 타임라인 항목에 응답했습니다.

{
  "collection": "timeline",
  "itemId": "3hidvm0xez6r8_dacdb3103b8b604_h8rpllg",
  "operation": "INSERT",
  "userToken": "harold_penguin",
  "verifyToken": "random_hash_to_verify_referer",
  "userActions": [
    {
      "type": "REPLY"
    }
  ]
}

itemId 속성은 다음을 포함하는 항목의 ID로 설정됩니다.

  • inReplyTo 속성이 답장 대상인 타임라인 항목의 ID로 설정됨
  • text 속성이 텍스트 스크립트 작성으로 설정됩니다.
  • recipients 속성이 속성이 대상인 경우 답장 대상인 타임라인 항목의 creator로 설정

예:

{
  "kind": "glass#timelineItem",
  "id": "3hidvm0xez6r8_dacdb3103b8b604_h8rpllg",
  "inReplyTo": "3236e5b0-b282-4e00-9d7b-6b80e2f47f3d",
  "text": "This is a text reply",
  "recipients": [
    {
      "id": "CREATOR_ID",
      "displayName": "CREATOR_DISPLAY_NAME",
      "imageUrls": [
        "CREATOR_IMAGE_URL"
      ]
    }
  ]
}

삭제

사용자가 타임라인 항목을 삭제한 경우:

{
  "collection": "timeline",
  "itemId": "3hidvm0xez6r8_dacdb3103b8b604_h8rpllg",
  "operation": "DELETE",
  "userToken": "harold_penguin",
  "verifyToken": "random_hash_to_verify_referer",
  "userActions": [
    {
      "type": "DELETE"
    }
  ]
}

itemId 속성은 삭제된 항목의 ID로 설정됩니다. 항목에 더 이상 ID 및 isDeleted 속성 이외의 메타데이터가 포함되지 않습니다.

맞춤 메뉴 항목이 선택됨

사용자가 서비스에 의해 설정된 맞춤 메뉴 항목을 선택했습니다.

{
  "collection": "timeline",
  "itemId": "3hidvm0xez6r8_dacdb3103b8b604_h8rpllg",
  "operation": "UPDATE",
  "userToken": "harold_penguin",
  "userActions": [
    {
      "type": "CUSTOM",
      "payload": "PING"
    }
  ]
}

itemId 속성은 사용자가 선택한 메뉴 항목의 ID로 설정됩니다.

userActions 배열에는 사용자가 이 항목에 실행한 커스텀 작업 목록이 포함됩니다. 서비스에서 이러한 작업을 적절하게 처리해야 합니다.

위치 업데이트

현재 사용자의 새 위치 사용 가능:

{
  "collection": "locations",
  "itemId": "latest",
  "operation": "UPDATE",
  "userToken": "harold_penguin",
  "verifyToken": "random_hash_to_verify_referer"
}

Glass 소프트웨어에서 위치 업데이트를 수신하면 glass.locations.get 엔드포인트에 요청을 전송하여 알려진 최신 위치를 가져옵니다. Glass 소프트웨어는 10분마다 위치 업데이트를 수신합니다.

음성 명령

사용자가 음성 명령을 활성화했습니다(예: "Ok Glass, 메모 작성, 고양이 스트림, 치포틀의 생일은 내일"). 다음 알림이 Glassware로 전송됩니다.

{
  "collection": "timeline",
  "operation": "INSERT",
  "userToken": "chipotle's_owner",
  "verifyToken": "mew mew mew",
  "itemId": "<ITEM_ID>",
  "userActions": [
    {“type”: "LAUNCH"}
  ]
}

이 알림은 userActions 속성의 LAUNCH 값으로 다른 알림과 구별됩니다.

그런 다음 itemId의 값을 사용하여 타임라인 항목을 가져올 수 있습니다.

{
  "id": "<ITEM_ID>",
  "text": "Chipotle's birthday is tomorrow",
  "recipients": [
    {"id": "CAT_STREAM"}
  ]
}

recipients 속성에는 사용된 음성 명령을 나타내는 연락처의 id가 포함되어 있습니다.