静的カードの挿入、更新、読み取り、削除は、シンプルな REST API を使用して行えます。また、静的カードにオブジェクト(場所やメディアなど)を添付することもできます。
仕組み
静的カードはデフォルトで Google 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" }
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()
画像が添付されたタイムライン アイテムは、Google Glass では次のようになります。
動画の添付
タイムライン アイテムに動画ファイルを添付する場合は、ペイロード全体を一度にアップロードするのではなく、動画をストリーミングすることをおすすめします。Google Mirror API は、HTTP Live Streaming、プログレッシブ ダウンロード、リアルタイム ストリーミング プロトコル(RTSP)によるストリーミングをサポートしています。RTSP はファイアウォールでブロックされることが多いので、可能であれば他のオプションを使用してください。
動画をストリーミングするには、組み込みのメニュー項目 PLAY_VIDEO
を使用し、動画の URL をメニュー項目の payload
に指定します。詳しくは、組み込みメニュー アイテムの追加とサポートされているメディア形式をご覧ください。
ページ分割
1 つのタイムライン カードに収まらないタイムライン アイテムは、同じカードに関連付けられている場合はページ分けできます。ページネーションされたアイテムはすべて同じ 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}
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 種類があります。
組み込みのメニュー項目を使用すると、タイムライン カードの読み上げ、現在地へのナビゲーション、画像の共有、メッセージへの返信など、Google Glass が提供する特別な機能にアクセスできます。
カスタム メニュー アイテムを使用すると、Glassware に固有の動作をアプリで公開できます。また、ブランディングに合わせてメニュー アイテムのアイコンを指定することもできます。
組み込みのメニュー項目を追加する
組み込みのメニュー項目をタイムライン アイテムに追加するには、挿入時に menuItems array
に入力します。組み込みのメニュー項目を使用するには、各 menuItem
の action
に入力するだけです。
未加工の 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.action
にCUSTOM
を指定します。menuItem.id
を指定します。ユーザーがカスタム メニュー アイテムをタップすると、menuItem.id
が入力された通知が Glassware に届きます。これにより、通知の送信元を特定できます。menuItem.values
を指定して、Glass に表示されるiconUrl
とdisplayName
を追加します。iconUrl
の 50 x 50 の 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"
}]
}
]
}
ユーザーがタイムライン カードを固定できるようにする
ユーザーがタイムライン カードを固定できるようにするメニュー アイテムを作成できます。これにより、タイムライン カードがメインのクロックカードの左側に常に表示されます。同じメニュー項目を使用して、カードの固定を解除することもできます。
固定メニュー項目は組み込みのメニュー項目であるため、menuItem
に TOGGLE_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>"
}
]
}
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 に 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
に設定されます。
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"
}
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
が含まれます。