البطاقات الثابتة

يمكنك إدراج البطاقات الثابتة وتعديلها وقراءتها وحذفها باستخدام واجهة برمجة تطبيقات بسيطة لخدمات معالجة البيانات (REST). بالإضافة إلى ذلك، يمكنك إرفاق عناصر بطاقة ثابتة، مثل موقع جغرافي أو وسائط.

آلية عملها

تظهر البطاقات الثابتة تلقائيًا على يسار ساعة Glass وتعرض معلومات مفيدة للمستخدم في وقت عرضها. ومع ذلك، لا تتطلّب هذه البطاقات انتباهًا فوريًا، ويمكن للمستخدمين اختيار قراءة البطاقة أو اتّخاذ إجراء بشأنها في الوقت الذي يناسبهم.

عندما تُدرج تطبيقات Glassware بطاقات ثابتة في المخطط الزمني، قد يشغّل جهاز Glass صوت إشعار لتنبيه المستخدمين. يتم أيضًا نقل جميع البطاقات الثابتة السابقة إلى اليسار وتتم إزالتها من المخطط الزمني بعد 7 أيام أو عندما تصبح 200 بطاقة أحدث.

حالات الاستخدام

تُعدّ البطاقات الثابتة رائعة لإرسال إشعارات دورية إلى المستخدمين عند حدوث أحداث مهمة. على سبيل المثال، خدمة إرسال الأخبار التي تُرسِل أبرز القصص الإخبارية فور وقوعها يمكن أيضًا أن تبدأ البطاقات الثابتة في Mirror 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" }

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

يظهر العنصر المُدرَج الذي سيظهر في المخطط الزمني للمستخدم على النحو التالي:

إدراج عنصر في المخطط الزمني مع مرفق

الصورة تساوي ألف كلمة، وهو عدد أكبر بكثير من الكلمات التي يمكنك إدراجها في أحد عناصر المخطط الزمني. ويمكنك أيضًا إرفاق الصور والفيديوهات بعنصر في المخطط الزمني. في ما يلي مثال على كيفية إدراج عنصر مخطط زمني مع ملف مُرفَق بالصورة:

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" وتحميل المحتوى تدريجيًا وبروتوكول البث في الوقت الفعلي (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>

يتم تلقائيًا عرض البطاقة الأولى لعنصر المخطط الزمني المُقسّم إلى صفحات بصفتها بطاقة الغلاف، ويتم عرضها مرة أخرى عندما يختار المستخدم قراءة المزيد من القائمة. لمنع ظهور البطاقة الأولى مرة أخرى بعد النقر على قراءة المزيد، يمكنك تحديد فئة CSS cover-only للعلامة <article> الأولى:

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

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

إنشاء عناصر القائمة

تسمح عناصر القائمة للمستخدمين بطلب إجراءات ذات صلة ببطاقة المخطط الزمني، ويتوفر منها نوعان: عناصر قائمة مضمّنة وعناصر قائمة مخصّصة.

تتيح لك عناصر القائمة المدمجة الوصول إلى وظائف خاصة يوفّرها 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. عندما ينقر المستخدمون على عنصر القائمة المخصّص، يتلقّى تطبيق Glassware إشعارًا تم فيه تعبئة menuItem.id. يتيح لك ذلك تحديد مصدر الإشعار.
  • حدِّد menuItem.values لإضافة iconUrl و displayName يظهران على شاشة Glass. حدِّد صورة PNG بحجم 50 x ‏50 بكسل بلون أبيض مع خلفية شفافة للرمز 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)

يجب أن تستجيب خدمتك لواجهة برمجة التطبيقات باستخدام رمز حالة 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 تعديلات الموقع الجغرافي كل عشر دقائق.

بطلب صوتي

فعَّل المستخدم طلبًا صوتيًا، على سبيل المثال: "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 جهة الاتصال التي تمثّل الأمر الصوتي المستخدَم.