การ์ดแบบคงที่

คุณสามารถแทรก อัปเดต อ่าน และลบการ์ดแบบคงที่โดยใช้ REST API ง่ายๆ นอกจากนี้ คุณยังแนบวัตถุลงในการ์ดแบบคงที่ได้ด้วย เช่น สถานที่หรือสื่อ

วิธีการทำงาน

การ์ดแบบคงที่จะอยู่ทางด้านขวาของนาฬิกา Glass โดยค่าเริ่มต้น และแสดงข้อมูลที่ตรงกับผู้ใช้ ณ เวลาแสดง แต่ผู้ใช้ไม่จำเป็นต้องสนใจการ์ดเหล่านี้ในทันทีเหมือนการ์ดแบบเรียลไทม์ และผู้ใช้สามารถเลือกอ่านหรือดำเนินการกับการ์ดได้ตามต้องการ

เมื่อ Glassware แทรกการ์ดแบบคงที่ลงในไทม์ไลน์ Glass อาจเล่นเสียงการแจ้งเตือนเพื่อแจ้งให้ผู้ใช้ทราบ การ์ดแบบคงที่ก่อนหน้านี้ทั้งหมดจะเลื่อนไปทางขวาเช่นกัน และจะหายไปจากไทม์ไลน์หลังจากผ่านไป 7 วันหรือเมื่อมีการ์ดใหม่กว่า 200 ใบ

ควรใช้ในกรณีใด

การ์ดแบบคงที่เหมาะอย่างยิ่งในการส่งการแจ้งเตือนเป็นระยะให้ผู้ใช้ทราบเมื่อเกิดเหตุการณ์สำคัญ เช่น บริการส่งข่าวที่ส่งเรื่องราวข่าวเด่นทันทีที่เหตุการณ์เกิดขึ้น การ์ดแบบคงที่ของ Mirror API ยังเริ่มการ์ดแบบเรียลไทม์หรือประสบการณ์การดื่มด่ำผ่านรายการเมนู OPEN_URI ได้อีกด้วย ซึ่งช่วยให้คุณสร้างการโต้ตอบแบบผสมผสานได้โดยใช้การ์ดแบบคงที่เป็นการแจ้งเตือนและการ์ดแบบเรียลไทม์หรือการแชร์ประสบการณ์เพื่อประสบการณ์การโต้ตอบที่มากขึ้น

ดูรายการการดำเนินการทั้งหมดที่เป็นไปได้สำหรับรายการไทม์ไลน์ได้ที่เอกสารอ้างอิง

การแทรกการ์ดแบบคงที่

หากต้องการแทรกการ์ดแบบคงที่ (รายการไทม์ไลน์) ให้ POST การนำเสนอรายการไทม์ไลน์ในรูปแบบ 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" }

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

หากดำเนินการสำเร็จ คุณจะได้รับโค้ดตอบกลับ 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"
}

รายการที่แทรกซึ่งจะปรากฏในไทม์ไลน์ของผู้ใช้จะมีลักษณะดังนี้

การแทรกรายการไทม์ไลน์ที่มีไฟล์แนบ

รูปภาพ 1 รูปแทนถ้อยคำนับพันได้ ซึ่งมากกว่าที่คุณจะใส่ลงในรายการไทม์ไลน์ได้ คุณจึงแนบรูปภาพและวิดีโอไปกับรายการไทม์ไลน์ได้ด้วย ตัวอย่างวิธีแทรกรายการไทม์ไลน์พร้อมไฟล์แนบรูปภาพมีดังนี้

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

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

รายการไทม์ไลน์ที่มีรูปภาพแนบมาจะมีลักษณะดังนี้ใน Glass

กำลังแนบวิดีโอ

หากคุณแนบไฟล์วิดีโอกับรายการไทม์ไลน์ เราขอแนะนำให้คุณสตรีมวิดีโอแทนการอัปโหลดเพย์โหลดทั้งหมดในครั้งเดียว Google Mirror API รองรับสตรีมมิงด้วย HTTP Live Streaming, การดาวน์โหลดแบบเป็นขั้นๆ และโปรโตคอลสตรีมมิงแบบเรียลไทม์ (RTSP) ไฟร์วอลล์มักบล็อก RTSP ดังนั้นโปรดใช้ตัวเลือกอื่นๆ หากเป็นไปได้

หากต้องการสตรีมวิดีโอ ให้ใช้รายการเมนูในตัว PLAY_VIDEO และระบุ URL ของวิดีโอเป็น payload ของรายการเมนู ดูข้อมูลเพิ่มเติมที่หัวข้อการเพิ่มรายการเมนูในตัวและรูปแบบสื่อที่รองรับ

การแบ่งหน้า

คุณสามารถแบ่งหน้ารายการไทม์ไลน์ที่ไม่พอดีกับการ์ดไทม์ไลน์ใบเดียวได้ แต่ควรเชื่อมโยงกับการ์ดเดียวกัน รายการแบบแบ่งหน้าทั้งหมดใช้ timeline.id เดียวกัน จึงมีชุดรายการในเมนูเดียวกัน เมื่อผู้ใช้แตะรายการไทม์ไลน์แบบแบ่งหน้า รายการเมนูอ่านเพิ่มเติมจะปรากฏขึ้น

Glass จะแบ่งหน้ารายการไทม์ไลน์ที่แสดงโดยอัตโนมัติ text หากต้องการให้ Glass แบ่งหน้าhtmlโดยอัตโนมัติ ให้ใช้แท็ก article โดยตั้งค่าพร็อพเพอร์ตี้คลาสเป็น auto-paginate ดังตัวอย่างต่อไปนี้

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

โดยค่าเริ่มต้น การ์ดแรกของรายการไทม์ไลน์แบบแบ่งหน้าจะแสดงเป็นการ์ดหน้าปก และจะแสดงอีกครั้งเมื่อผู้ใช้เลือกรายการเมนูอ่านเพิ่มเติม หากต้องการป้องกันไม่ให้การ์ดแรกปรากฏขึ้นอีกหลังจากแตะอ่านเพิ่มเติม ให้ระบุคลาส cover-only CSS สำหรับแท็ก <article> แรก ดังนี้

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

Java

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}

Java

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

การสร้างรายการเมนู

รายการเมนูช่วยให้ผู้ใช้ส่งคำขอการดำเนินการที่เกี่ยวข้องกับการ์ดไทม์ไลน์ได้ โดยมี 2 ประเภท ได้แก่ รายการเมนูในตัวและรายการเมนูที่กำหนดเอง

รายการเมนูในตัวช่วยให้เข้าถึงฟังก์ชันพิเศษที่ Glass มีให้ เช่น การอ่านการ์ดไทม์ไลน์ออกเสียง การนำทางไปยังสถานที่ การแชร์รูปภาพ หรือการตอบกลับข้อความ

รายการเมนูที่กำหนดเองช่วยให้แอปพลิเคชันแสดงลักษณะการทำงานเฉพาะสำหรับ Glassware ได้ นอกจากนี้ คุณยังระบุไอคอนรายการเมนูให้ตรงกับการสร้างแบรนด์ของคุณได้ด้วย

การเพิ่มรายการในเมนูที่มาพร้อมแอป

คุณสามารถเพิ่มรายการเมนูในตัวลงในรายการไทม์ไลน์ได้โดยป้อนข้อมูลใน menuItems array เมื่อแทรกรายการ หากต้องการใช้รายการเมนูในตัว คุณเพียงแค่ต้องป้อนข้อมูล action ของ menuItem แต่ละรายการ

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

การกําหนดรายการในเมนูที่กําหนดเอง

หากรายการเมนูในตัวใช้งานไม่ได้ คุณสามารถสร้างรายการเมนูที่กำหนดเองด้วยการดำเนินการของคุณเองได้โดยทำดังนี้เมื่อแทรกหรืออัปเดตรายการไทม์ไลน์

  • ระบุ CUSTOM สำหรับ menuItem.action
  • ระบุ menuItem.id เมื่อผู้ใช้แตะรายการเมนูที่กำหนดเอง แก้วของคุณจะได้รับการแจ้งเตือนพร้อมmenuItem.idที่สร้างขึ้น ซึ่งจะช่วยให้คุณระบุแหล่งที่มาของการแจ้งเตือนได้
  • ระบุ menuItem.values เพื่อเพิ่ม iconUrl และ displayName ที่ปรากฏบน Glass ชี้ไปที่รูปภาพขนาด 50 x 50 ที่เป็น PNG สีขาวและมีพื้นหลังโปร่งใสสำหรับ iconUrl
  • ระบุ 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"
      }]
    }
  ]
}

อนุญาตให้ผู้ใช้ปักหมุดการ์ดไทม์ไลน์

คุณสามารถสร้างรายการเมนูที่อนุญาตให้ผู้ใช้ปักหมุดการ์ดไทม์ไลน์ ซึ่งจะแสดงการ์ดไทม์ไลน์ทางด้านซ้ายของการ์ดนาฬิกาหลักอย่างถาวร ผู้ใช้สามารถเลิกปักหมุดการ์ดได้ด้วยโดยใช้รายการเมนูเดียวกัน

รายการในเมนูสำหรับปักหมุดเป็นรายการในเมนูในตัว คุณจึงต้องระบุ TOGGLE_PINNED action สำหรับ menuItem

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 เป็นคำขอ POST ไปยังปลายทางที่สมัครใช้บริการซึ่งมีเนื้อหาคำขอ JSON

HTTP ดิบ

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

บริการของคุณต้องตอบกลับ API ด้วยรหัสสถานะ HTTP 200 OK หากไม่เกิดข้อผิดพลาด หากบริการตอบกลับด้วยรหัสข้อผิดพลาด 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 ได้รับการตั้งค่าเป็นรหัสของรายการที่ลบ รายการจะไม่มีข้อมูลเมตาอื่นๆ นอกเหนือจากรหัสและพร็อพเพอร์ตี้ isDeleted อีกต่อไป

เลือกรายการเมนูที่กำหนดเอง

ผู้ใช้เลือกรายการเมนูที่กำหนดเองที่ตั้งค่าโดยบริการของคุณ

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

แอตทริบิวต์ itemId ได้รับการตั้งค่าเป็นรหัสของรายการเมนูที่ผู้ใช้เลือก

อาร์เรย์ 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"}
  ]
}

การแจ้งเตือนนี้จะแตกต่างจากการแจ้งเตือนอื่นๆ โดยค่า LAUNCH ในพร็อพเพอร์ตี้ userActions

จากนั้นใช้ค่าใน itemId เพื่อดึงข้อมูลรายการไทม์ไลน์

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

พร็อพเพอร์ตี้ recipients มี id ของรายชื่อติดต่อที่แสดงถึงคำสั่งเสียงที่ใช้