Thẻ tĩnh

Bạn có thể chèn, cập nhật, đọc và xoá thẻ tĩnh bằng các API REST đơn giản. Ngoài ra, bạn có thể đính kèm các đối tượng vào thẻ tĩnh, chẳng hạn như vị trí hoặc nội dung nghe nhìn.

Cách hoạt động

Theo mặc định, các thẻ tĩnh nằm ở bên phải đồng hồ Glass và hiển thị thông tin liên quan đến người dùng tại thời điểm phân phối. Tuy nhiên, các thẻ này không yêu cầu người dùng phải chú ý ngay lập tức như thẻ trực tiếp và người dùng có thể chọn đọc hoặc hành động trên thẻ theo ý thích.

Khi Glassware chèn thẻ tĩnh vào dòng thời gian, Glass có thể phát âm thanh thông báo để cảnh báo người dùng. Tất cả thẻ tĩnh trước đó cũng sẽ chuyển sang bên phải và biến mất khỏi dòng thời gian sau 7 ngày hoặc khi có 200 thẻ mới hơn.

Khi nào nên sử dụng tiện ích vị trí đơn vị liên kết

Thẻ tĩnh rất phù hợp để phân phối thông báo định kỳ cho người dùng khi có những sự kiện quan trọng xảy ra. Ví dụ: dịch vụ phân phối tin tức gửi các tin bài nổi bật nhất ngay khi chúng xảy ra. Thẻ tĩnh của Mirror API cũng có thể bắt đầu thẻ trực tiếp hoặc màn hình chìm thông qua mục trình đơn OPEN_URI. Điều này cho phép bạn tạo các lượt tương tác kết hợp sử dụng thẻ tĩnh làm thông báo và thẻ trực tiếp hoặc chế độ chìm để mang lại trải nghiệm tương tác cao hơn.

Để biết danh sách đầy đủ các thao tác có thể thực hiện đối với các mục trong dòng thời gian, hãy xem tài liệu tham khảo.

Chèn thẻ tĩnh

Để chèn thẻ tĩnh (mục trong dòng thời gian), hãy POST một biểu diễn JSON của mục trong dòng thời gian đến điểm cuối REST.

Hầu hết các trường trong một mục tiến trình đều không bắt buộc. Ở dạng đơn giản nhất, một mục dòng thời gian chỉ chứa một thông báo văn bản ngắn, như trong ví dụ sau:

HTTP thô

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

Java

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()

Nếu thành công, bạn sẽ nhận được mã phản hồi 201 Created cùng với bản sao đầy đủ của mục đã tạo. Đối với ví dụ trước, phản hồi thành công có thể có dạng như sau:

HTTP thô

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

Mục được chèn sẽ xuất hiện trong dòng thời gian của người dùng như sau:

Chèn một mục dòng thời gian có tệp đính kèm

Một bức ảnh đáng giá ngàn lời nói, nhiều hơn nhiều so với những gì bạn có thể đưa vào một mục dòng thời gian. Để làm việc này, bạn cũng có thể đính kèm hình ảnh và video vào một mục trong dòng thời gian. Dưới đây là ví dụ về cách chèn một mục dòng thời gian có ảnh đính kèm:

HTTP thô

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--

Java

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()

Một mục trong dòng thời gian có hình ảnh đính kèm sẽ có dạng như sau trên Glass:

Đính kèm video

Nếu đính kèm tệp video vào các mục trong dòng thời gian, bạn nên truyền trực tuyến video thay vì tải toàn bộ tải trọng lên cùng một lúc. Google Mirror API hỗ trợ truyền trực tuyến bằng tính năng phát trực tiếp HTTP, tải xuống liên tục và giao thức truyền trực tuyến theo thời gian thực (RTSP). RTSP thường bị tường lửa chặn, vì vậy, hãy sử dụng các tuỳ chọn khác nếu có thể.

Để phát trực tuyến video, hãy sử dụng mục trình đơn tích hợp PLAY_VIDEO và chỉ định URL của video làm payload của mục trình đơn. Hãy xem phần Thêm mục trình đơn tích hợp sẵncác định dạng nội dung nghe nhìn được hỗ trợ để biết thêm thông tin.

Phân trang

Bạn có thể phân trang các mục dòng thời gian không vừa trên một thẻ dòng thời gian, nhưng phải được liên kết với cùng một thẻ. Các mục được phân trang đều có cùng một timeline.id và do đó có cùng một nhóm các mục trong trình đơn. Khi người dùng nhấn vào một mục dòng thời gian được phân trang, mục trình đơn Đọc thêm sẽ xuất hiện.

Glass tự động phân trang các mục dòng thời gian hiển thị text. Để Glass tự động phân trang html, hãy sử dụng thẻ article với thuộc tính lớp được đặt thành auto-paginate như trong ví dụ sau:

<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>

Để phân trang theo cách thủ công, hãy sử dụng thẻ article cho nội dung mà bạn muốn hiển thị trên mỗi thẻ. Glass hiển thị nội dung của mỗi thẻ article trong một thẻ dòng thời gian phụ riêng biệt. Ví dụ: bạn có thể tạo một mục dòng thời gian được phân trang bằng HTML sau:

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

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

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

Theo mặc định, thẻ đầu tiên của mục dòng thời gian được phân trang sẽ hiển thị dưới dạng thẻ trang bìa và sẽ xuất hiện lại khi người dùng chọn mục trình đơn Đọc thêm. Để ngăn thẻ đầu tiên xuất hiện lại sau khi nhấn vào Đọc thêm, bạn có thể chỉ định lớp CSS cover-only cho thẻ <article> đầu tiên:

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

Lớp cover-only cũng hỗ trợ các mục dòng thời gian được phân trang tự động:

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

Gói

Tính năng gói cho phép bạn nhóm các mục có liên quan nhưng riêng biệt với nhau, chẳng hạn như các tin nhắn riêng lẻ trong một chuỗi email. Gói có một thẻ bìa chính mà người dùng nhấn vào để hiển thị một dòng thời gian phụ chứa các thẻ khác trong gói. Gói được phân biệt với các thẻ dòng thời gian thông thường bằng một góc gập ở góc trên bên phải của thẻ bìa của gói.

Để gói các mục dòng thời gian, hãy tạo các mục đó bằng cùng một giá trị cho bundleId. Mục được thêm gần đây nhất là thẻ bìa của gói.

Các hình ảnh sau đây cho thấy một thẻ bao gồm gói có góc gập ở góc trên cùng bên phải và hai thẻ được đóng gói bên dưới.

Đọc các mục trong tiến trình

Dịch vụ của bạn có thể truy cập vào tất cả các mục dòng thời gian mà dịch vụ đã tạo và tất cả các mục dòng thời gian được chia sẻ với dịch vụ. Dưới đây là cách liệt kê các mục trong dòng thời gian mà dịch vụ của bạn có thể thấy.

HTTP thô

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

Java

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

Python

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

Bạn có thể sử dụng các thao tác REST khác để lấy, cập nhậtxoá các mục trong dòng thời gian.

Truy cập vào tệp đính kèm

Bạn có thể truy cập vào tệp đính kèm của một mục dòng thời gian thông qua thuộc tính mảng có tên attachments. Sau đó, bạn có thể lấy dữ liệu nhị phân của tệp đính kèm thông qua thuộc tính contentUrl của tệp đính kèm hoặc bằng điểm cuối của tệp đính kèm.

HTTP thô

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

Java

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

Tạo mục trong trình đơn

Các mục trong trình đơn cho phép người dùng yêu cầu các hành động liên quan đến thẻ dòng thời gian. Các mục này có hai loại: mục trong trình đơn tích hợp và mục trong trình đơn tuỳ chỉnh.

Các mục trong trình đơn tích hợp sẵn cung cấp quyền truy cập vào các chức năng đặc biệt do Glass cung cấp, chẳng hạn như đọc thẻ dòng thời gian, điều hướng đến một vị trí, chia sẻ hình ảnh hoặc trả lời tin nhắn:

Các mục trình đơn tuỳ chỉnh cho phép ứng dụng hiển thị hành vi dành riêng cho Glassware, đồng thời bạn cũng có thể cung cấp biểu tượng mục trình đơn để phù hợp với hoạt động xây dựng thương hiệu.

Thêm các mục trong trình đơn tích hợp

Bạn có thể thêm các mục trình đơn tích hợp vào các mục dòng thời gian bằng cách điền vào menuItems array khi chèn các mục đó. Để sử dụng một mục trình đơn tích hợp, bạn chỉ cần điền action của mỗi menuItem.

HTTP thô

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

Xác định các mục trong trình đơn tuỳ chỉnh

Nếu các mục trong trình đơn tích hợp không phù hợp với bạn, bạn có thể tạo các mục trong trình đơn tuỳ chỉnh bằng các thao tác của riêng mình bằng cách làm như sau khi chèn hoặc cập nhật một mục dòng thời gian:

  • Chỉ định CUSTOM cho menuItem.action.
  • Chỉ định menuItem.id. Khi người dùng nhấn vào mục trình đơn tuỳ chỉnh, Glassware sẽ nhận được thông báo có menuItem.id được điền sẵn. Điều này cho phép bạn xác định nguồn của thông báo.
  • Chỉ định menuItem.values để thêm iconUrldisplayName xuất hiện trên Glass. Trỏ đến hình ảnh PNG 50 x 50 có màu trắng với nền trong suốt cho iconUrl.
  • Chỉ định displayTime. Nếu bạn không chỉ định displayTime, mục dòng thời gian sẽ di chuyển lên đầu dòng thời gian bất cứ khi nào người dùng nhấn vào mục trình đơn tuỳ chỉnh.

HTTP thô

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

Cho phép người dùng ghim thẻ dòng thời gian của bạn

Bạn có thể tạo một mục trong trình đơn cho phép người dùng ghim thẻ dòng thời gian. Thẻ dòng thời gian sẽ hiển thị vĩnh viễn ở bên trái thẻ đồng hồ chính. Người dùng cũng có thể bỏ ghim thẻ bằng cách sử dụng cùng một mục trình đơn.

Mục trong trình đơn ghim là một mục trong trình đơn tích hợp sẵn, vì vậy, tất cả những gì bạn cần làm là cung cấp TOGGLE_PINNED action cho menuItem.

HTTP thô

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

Kênh đăng ký

Mirror API cho phép bạn đăng ký nhận thông báo được gửi khi người dùng thực hiện các hành động cụ thể trên một Mục trong dòng thời gian hoặc khi vị trí của người dùng được cập nhật. Khi đăng ký một thông báo, bạn sẽ cung cấp một URL gọi lại để xử lý thông báo đó.

Nhận thông báo

Thông báo từ Mirror API được gửi dưới dạng yêu cầu POST đến điểm cuối đã đăng ký chứa nội dung yêu cầu JSON.

HTTP thô

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

Java

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)

Dịch vụ của bạn phải phản hồi API bằng mã trạng thái HTTP 200 OK nếu không có lỗi nào xảy ra. Nếu dịch vụ của bạn phản hồi bằng mã lỗi, Mirror API có thể cố gắng gửi lại thông báo cho dịch vụ của bạn.

Loại thông báo

Mirror API gửi một tải trọng thông báo khác nhau cho các sự kiện khác nhau.

Trả lời

Người dùng đã trả lời mục dòng thời gian của bạn bằng mục trình đơn REPLY tích hợp:

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

Thuộc tính itemId được đặt thành ID của mục chứa:

  • Thuộc tính inReplyTo được đặt thành ID của mục dòng thời gian mà thuộc tính này là phản hồi.
  • Thuộc tính text được đặt thành bản chép lời văn bản.
  • Thuộc tính recipients được đặt thành creator của mục dòng thời gian mà nó trả lời, nếu có.

Ví dụ:

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

Xoá

Người dùng đã xoá một mục trong dòng thời gian:

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

Thuộc tính itemId được đặt thành mã nhận dạng của mục đã xoá. Mục này không còn chứa siêu dữ liệu nào khác ngoài mã nhận dạng và thuộc tính isDeleted.

Đã chọn mục trong trình đơn tuỳ chỉnh

Người dùng đã chọn một mục trình đơn tuỳ chỉnh do dịch vụ của bạn đặt:

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

Thuộc tính itemId được đặt thành mã nhận dạng của mục trong trình đơn mà người dùng đã chọn.

Mảng userActions chứa danh sách các hành động tuỳ chỉnh mà người dùng đã thực hiện đối với mục này. Dịch vụ của bạn sẽ xử lý các hành động đó cho phù hợp.

Thông báo cập nhật vị trí

Có một vị trí mới cho người dùng hiện tại:

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

Khi Glassware của bạn nhận được thông tin cập nhật về vị trí, hãy gửi yêu cầu đến điểm cuối glass.locations.get để truy xuất vị trí đã biết mới nhất. Glassware của bạn sẽ nhận được thông tin cập nhật vị trí 10 phút một lần.

Lệnh thoại

Người dùng đã kích hoạt một lệnh thoại, ví dụ: "Ok Glass, ghi chú, Cat Stream, sinh nhật của Chipotle là vào ngày mai". Thông báo sau đây sẽ được gửi đến Glassware:

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

Thông báo này khác với các thông báo khác theo giá trị LAUNCH trong thuộc tính userActions.

Sau đó, bạn có thể sử dụng giá trị trong itemId để tìm nạp mục dòng thời gian:

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

Thuộc tính recipients chứa id của người liên hệ đại diện cho lệnh thoại được sử dụng.