정적 카드

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

작동 방식

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

Glassware가 타임라인에 정적 카드를 삽입하면 Glass에서 알림 소리를 재생하여 사용자에게 알릴 수 있습니다. 이전의 모든 정적 카드도 오른쪽으로 이동하며 7일 후 또는 200개가 더 새로운 카드가 있으면 타임라인에서 사라집니다.

용도

정적 카드는 중요한 일이 발생할 때 사용자에게 주기적 알림을 전송하는 데 적합합니다. 예를 들어 주요 뉴스가 발생할 때마다 전송하는 뉴스 전송 서비스가 있습니다. Mirror API 정적 카드는 OPEN_URI 메뉴 항목을 통해 라이브 카드 또는 몰입을 시작할 수도 있습니다. 이를 통해 정적 카드를 알림으로 활용하고 라이브 카드 또는 몰입형 환경을 사용하여 보다 양방향적인 환경을 제공하는 하이브리드 상호작용을 만들 수 있습니다.

타임라인 항목에 대해 수행할 수 있는 작업의 전체 목록은 참조 문서를 참고하세요.

정적 카드 삽입

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

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

원시 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 값을 동일하게 지정하여 만듭니다. 가장 최근에 추가된 항목은 번들의 표지 카드입니다.

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

타임라인 항목 읽기

서비스는 자체적으로 생성한 모든 타임라인 항목과 서비스와 공유된 모든 타임라인 항목에 액세스할 수 있습니다. 다음은 서비스에 표시되는 타임라인 항목을 나열하는 방법입니다.

원시 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에서 제공하는 특수 기능에 액세스할 수 있습니다.

맞춤 메뉴 항목을 사용하면 애플리케이션에서 Glassware에만 해당하는 동작을 노출할 수 있으며 브랜딩에 맞는 메뉴 항목 아이콘을 제공할 수도 있습니다.

내장 메뉴 항목 추가

삽입할 때 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를 지정합니다. 사용자가 맞춤 메뉴 항목을 탭하면 Glassware는 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)

오류가 발생하지 않은 경우 서비스는 API에 200 OK HTTP 상태 코드로 응답해야 합니다. 서비스가 오류 코드로 응답하면 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로 설정됩니다.

  • 답장하는 타임라인 항목의 ID로 설정된 inReplyTo 속성입니다.
  • 텍스트 스크립트에 설정된 text 속성
  • 답장하는 타임라인 항목의 creator(있는 경우)로 설정된 recipients 속성입니다.

예:

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

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

음성 명령

사용자가 음성 명령을 활성화했습니다(예: "Ok Glass, 메모 작성해 줘, Cat Stream, Chipotle의 생일은 내일이야"). 다음 알림이 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가 포함되어 있습니다.