Moves APIの使い方まとめ(サンプルコード付き)

Moves APIの使い方まとめ(サンプルコード付き)

持ってるだけで、歩数や距離、消費カロリーなんかを計算してくれる次世代健康管理アプリの「Moves」。今じゃすっかり有名になってFacebookに買収されちゃいましたが、登場当時は感動したのを覚えています。MovesのAPIを使って、何か面白いwebサービスを作りませんか?ブログにMovesの記録を自動で掲載してみたくありませんか?この記事がMovesのAPIでプログラムを開発する人たちの「嫁」みたいな存在になれることを目指して、Moves APIの使い方をまとめました。

アプリケーションの登録

MovesのAPIを利用するためには、Movesに対して「このプログラム(〜.phpなど)があなたのAPIを利用しますよ」と申請する必要があります。それが「アプリケーション登録」です。

アカウントを取得する

Googleアカウントが必要
Googleアカウントが必要

MovesのAPIを利用するのに、開発者は「Googleのアカウント」でログインする必要があります。もし、Googleのアカウントを持っていない人は、下記で取得して下さい。

アプリケーションを登録する

アプリケーションを登録するには、下記のページにアクセスします。まだの場合は、ログインが求められますので、Googleのアカウントでログインして下さいね!

Manage Your Apps

Manage Your Apps
Manage Your Apps

「Manage Your Apps」の画面には、登録したアプリケーションが表示されます。まだ登録していないので、何もありませんよね。「Create a New App」をクリックして、アプリの登録を始めましょう!

Create a New App

Create a New App
Create a New App

はじめに入力するのは「アプリ名(Application name)」と「開発者名(Developer)」です。お試し段階なのでアプリ名は「Test」で大丈夫です。また、開発者名に関しては、フルネームが気が引けるならニックネームでいいと思います。サンプル画像はクリックで拡大表示できます。

アプリケーションキーを確認する

Development
Development

登録が完了すると、上記図の画面に移動します。上部にあるタブの内、「Development」を選択すると「Client ID」と「Client secret」を確認することができます。この2つは、あなたのアプリを表す識別キーなので、他人に知られないように管理して下さい。「Reset Secret」をクリックすれば、クライアントシークレットを変更することができます。

Redirect URIを確認する

また、重要なのが「Redirect URI」の設定です。後ほど、アプリ認証を行なうためにPHPプログラムを作成するのですが、そのファイルの設置先となるURLを入力して下さい。ユーザーはこのURLにアクセスして、アプリ認証を行なうことになります。

リダイレクトURIの登録
リダイレクトURIの登録

URIを入力し、「Save Changes」をクリックすると登録することができます。上記のメッセージ(Redirect URI(s) updated)が出れば成功です。

アプリアイコンの設定など

多人数向けではなく個人的にMoves APIを利用する分には、調整する必要のない他の項目を一応、紹介しておきます。

Images

アプリイメージの登録
アプリイメージの登録

「Image」のタブを開くと、アプリのアイコン(512x512のPNG限定)と、スクリーンショット(PNG限定)を登録することができます。APIを利用して作成したwebサービスを本格的に公開する場合のみ、こちらから登録して下さい。

Info

アプリ詳細情報の登録
アプリ詳細情報の登録

「info」のタブを開くと、概要や、webサイトのURL、iTuneのidなどといった、アプリの詳細情報を登録することができます。作成したプログラムを公開しないのであれば、登録する必要はありません。

OAuth認証をする

それでは、Movesに保存されているユーザーの個人的なデータを利用するために、そのユーザーの「アクセストークン」を取得しましょう。「アクセストークン」を取得するには、アプリ認証をする必要があります。MovesはOAuth2.0という認証形式を採用しています。

認証の仕組み

Twitterのアプリ認証
Twitterのアプリ認証

例えばTwitterやFacebookなどでは、アプリ認証をする時、ユーザーが「アプリを認証する」というボタンをクリックすれば、それで完了でした。しかし、Movesの場合はそれだけではなく、「スマホでMovesを起動し、指定されたPINコードを入力する」という作業を行なう必要があります。

これからアプリ認証のサンプルプログラムを通して、一緒に見ていきましょう。なお、アプリ認証に関する公式ドキュメントは下記のページで確認することができます。

サンプルプログラム

下記が、Movesでアプリ認証を行なうためのサンプルプログラムです。$client_id$client_secret$redirect_uriをそれぞれ設定して下さい。$redirect_uriには、自動的にこのプログラムのURLが指定されるようになっていますが、上手く動作しない場合は、直接指定して下さい。アプリ登録の際に設定した「Redirect URI」と一致している必要があります。

$scopeにはパーミッションを設定します。Movesの場合、「activity」「location」の2種類のパーミッションがあります。「activity」は運動データ、「location」は位置データを取得する権限です。両方指定する場合は、半角スペースで区切って下さい。

PHP

<?php

	// 設定項目
	$client_id = '' ;				// クライアントID
	$client_secret = '' ;		// クライアントシークレット
	$redirect_uri = ( !isset($_SERVER['HTTPS']) || empty($_SERVER['HTTPS']) ? 'http://' : 'https://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ;		// このプログラムを設置するURL
 	$scope = 'activity location' ;			// アプリの権限

	// セッションスタート
	session_start() ;

	// HTML用
	$html = '' ;

	// アプリ認証から帰ってきた場合はアクセストークンを取得
	if( isset($_GET['code']) && is_string($_GET['code']) )
	{
		// セッションにCSRF対策用の[state]がない場合は不正と判断してエラー
		if( !isset($_SESSION['state']) || empty($_SESSION['state']) )
		{
			$error = 'セッションが上手く機能してないかもしれません。' ;
		}

		// CSRF対策
		elseif( !isset($_GET['state']) || empty($_GET['state']) || $_GET['state'] != $_SESSION['state'] )
		{
			$error = 'セッションに保存してあるstateと、返ってきたstateの値が違います…。' ;
		}

		// アクセストークンの取得
		else
		{
			// リクエスト用のコンテキストを作成
			$context = array(
				'http' => array(
					'method' => 'POST' ,
					'content' => http_build_query( array(
						'grant_type' => 'authorization_code' ,
						'code' => $_GET['code'] ,
						'client_id' => $client_id ,
						'client_secret' => $client_secret ,
						'redirect_uri' => $redirect_uri ,
					) ) ,
				) ,
			) ;

			// CURLを使ってリクエスト
			$curl = curl_init() ;

			// オプションのセット
			curl_setopt( $curl , CURLOPT_URL , 'https://api.moves-app.com/oauth/v1/access_token' ) ;
			curl_setopt( $curl , CURLOPT_HEADER, 1 ) ; 
			curl_setopt( $curl , CURLOPT_CUSTOMREQUEST , $context['http']['method'] ) ;			// メソッド
			curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false ) ;								// 証明書の検証を行わない
			curl_setopt( $curl , CURLOPT_RETURNTRANSFER , true ) ;								// curl_execの結果を文字列で返す
			curl_setopt( $curl , CURLOPT_POSTFIELDS , $context['http']['content'] ) ;			// リクエストボディ
			curl_setopt( $curl , CURLOPT_TIMEOUT , 5 ) ;										// タイムアウトの秒数

			// 実行
			$res1 = curl_exec( $curl ) ;
			$res2 = curl_getinfo( $curl ) ;

			// 終了
			curl_close( $curl ) ;

			// 取得したデータ
			$json = substr( $res1, $res2['header_size'] ) ;										// 取得したデータ(JSONなど)
			$header = substr( $res1, 0, $res2['header_size'] ) ;								// レスポンスヘッダー (検証に利用したい場合にどうぞ)

			// JSONをオブジェクトに変換
			$obj = json_decode( $json ) ;

			// アクセストークンが取得できない場合はエラー
			if( !isset($obj->access_token) || empty($obj->access_token) )
			{
				$error = 'アクセストークンを取得できませんでした…。' ;
			}
			else
			{
				// 各データを整理
				$user_id = $obj->user_id ;				// ユーザーID
				$access_token = $obj->access_token ;	// アクセストークン
				$refresh_token = $obj->refresh_token ;	// リフレッシュトークン
				$expires_in = $obj->expires_in ;		// アクセストークンの有効期限

				// 出力する
				$html .= '<h2>実行結果</h2>' ;
				$html .= '<dl>' ;
				$html .=  	'<dt>ユーザーID</dt>' ;
				$html .=  		'<dd>' . $user_id . '</dd>' ;
				$html .=  	'<dt>アクセストークン</dt>' ;
				$html .=  		'<dd>' . $access_token . '</dd>' ;
				$html .=  	'<dt>リフレッシュトークン</dt>' ;
				$html .=  		'<dd>' . $refresh_token . '</dd>' ;
				$html .=  	'<dt>アクセストークンの有効期限 (残りの秒数)</dt>' ;
				$html .=  		'<dd>' . $expires_in . ' (' . date( 'Y/m/d H:i:s' , ( time() + $expires_in ) ) . ' まで)' . '</dd>' ;
				$html .=  '</dl>' ;
			}
		}

		// 出力する
		$html .= '<h2>取得したデータ</h2>' ;
		$html .= '<p>下記のデータを取得しました。</p>' ;
		$html .= 	'<h3>JSON</h3>' ;
		$html .= 	'<p><textarea rows="8">' . $json . '</textarea></p>' ;
		$html .= 	'<h3>レスポンスヘッダー</h3>' ;
		$html .= 	'<p><textarea rows="8">' . $header . '</textarea></p>' ;

		// セッション終了
		$_SESSION = array() ;
		session_destroy() ;
	}

	// 初回アクセスの場合
	else
	{
		// CSRF対策
		session_regenerate_id( true ) ;
		$state = sha1( uniqid( mt_rand() , true ) ) ;
		$_SESSION['state'] = $state ;

		// ユーザーをアプリ認証画面へアクセス(リダイレクト)させる
		header( 'Location: https://api.moves-app.com/oauth/v1/authorize?response_type=code&client_id=' . $client_id . '&state=' . $state . '&scope=' . rawurlencode( $scope ) ) ;
	}

	// エラー時の処理
	if( isset($error) || !empty($error) )
	{
		$html = '<p><mark>' . $error . '</mark>もう一度、認証をするには、<a href="' . explode( '?' , $_SERVER['REQUEST_URI'] )[0] . '">こちら</a>をクリックして下さい。</p>' ;
	}

?>

<?php
	// ブラウザに[$html]を出力 (HTMLのヘッダーとフッターを付けましょう)
	echo $html ;
?>

このコードの動作を確認する

PINコードの入力作業

Moves APIのOAuth認証では、スマホアプリの操作が必要です。よく分からないという人のために、解説します。

[1] PINコードの発行

PINコードが発行される
PINコードが発行される

問題がなければ、上記の画面が表示されるはずです。青い枠で囲んである6180 3228の部分がPINコードにあたります。ユーザーはこの画面を確認後、スマホでアプリを起動し、このPINコードを入力します。

[2] Optionを開く

Movesのオプション
Movesのオプション

Movesを起動すると、画面右下に「M」というボタンがあり、タップすると上記図のようなオプションが表示されます。そのうち、「接続されているアプリ」をタップして下さい。

[3] PINの入力画面に移動する

PINの入力画面に移動する
PINの入力画面に移動する

画面右上にある「Enter PIN」のボタンをタップして、PINコードの入力画面に移動します。

[4] PINコードを入力する

PINコードの入力フォーム
PINコードの入力フォーム

PINコードの入力フォームが現れるので、先ほど画面に表示されていた「PINコード」を入力します。なお、半角スペースは省略してかまいません。

[5] アプリ連携を許可する

アプリ連携を許可する
アプリ連携を許可する

ここで初めて、ユーザーは「アプリの認証」を行ないます。アプリがデータにアクセスするのを許可する場合、「Allow」をタップします。これで、PINコードの入力作業が完了します。

アクセストークンの確認

ユーザーがスマホのMovesアプリ上で連携を許可すると、先ほど、PINコードを表示していた画面が、$redirect_uriで設定したURLに移動し、アクセストークンとリフレッシュトークンが表示されます。この2つのキーを誰にも知らないよう、管理(メモ)して下さい。

リフレッシュトークンに関しては、この記事内の「アクセストークンの有効期限切れ対策」の項で説明するので、今は保存だけしておいて下さい。ユーザー向けに、Moves APIを利用したサービスを提供するには、「PINコードの入力方法」の案内だったり、この2つのキーをデータベースに保存するシステム作りが必要になってきますねー。

サマリーの取得 [Summaries]

前章では「アクセストークン」を取得しました。これらを使って、この章からはユーザーの様々なデータを取得していきましょう。まずはユーザーのサマリーデータを取得します。公式ドキュメント(英語)は下記ページをご覧下さい。

リクエスト方法

Summariesのデータを取得するためには、それぞれの指定されたURLに、GETメソッドでリクエストを送ります。なお、どのリクエストも、パラメータにaccess_tokenというプロパティ名で、アクセストークンを付与する必要があります。アプリのパーミッションで「activity」を指定している必要があります。

GET https://api.moves-app.com/api/1.1/user/summary/daily{取得期間}

fromtopastDaysを利用する場合は、スラッシュ(/)を除く必要がある点にご注意下さい。

GET https://api.moves-app.com/api/1.1/user/summary/daily?from={YYYYMM}&to={YYYYMM}

データを取得する期間の調整

どの期間のサマリーデータを取得するかを、URLの組み立て方によって調整することができます。

YYYYMMDD
1日分の指定。
例: 20170611
YYYY-Www
1週間分。年と、週番号を指定する。
例: 2017W23
YYYYMM
1ヶ月分。年と、月を指定する。
例: 201706
from={YYYYMM}&to={YYYYMM}
fromtoパラメータにそれぞれ日付(YYYYMMDD)を指定することで、細かく期間を調整することができる。最大31日間まで指定可。
例: from=20170604&to=20170609
pastDays={日数}
pastDaysパラメータに日数を示す数値を指定することで、現在から過去〜日間というように期間を指定できる。最大31日間まで指定可。
例: pastDays=30

取得できるJSON

Summariesでは下記のJSONデータを取得できます。1日ごとのデータが配列形式で含まれています。また、それぞれの日ごとの「歩き(walking)」「走り(run)」「サイクリング(cycling)」といったカテゴリ別のデータが、summaryの中に配列方式で格納されています。

JSON

[{"date":"20150710","summary":[{"activity":"walking","group":"walking","duration":9694.0,"distance":8543.0,"steps":8838,"calories":448},{"activity":"transport","group":"transport","duration":18443.0,"distance":337519.0}],"caloriesIdle":1509,"lastUpdate":"20150711T113318Z"},{"date":"20150711","summary":[{"activity":"walking","group":"walking","duration":3274.0,"distance":4047.0,"steps":5558,"calories":212}],"caloriesIdle":1509,"lastUpdate":"20150713T124818Z"},{"date":"20150712","summary":[{"activity":"walking","group":"walking","duration":50.0,"distance":25.0,"steps":0,"calories":1}],"caloriesIdle":1509,"lastUpdate":"20150713T124818Z"},{"date":"20150713","summary":[{"activity":"walking","group":"walking","duration":6434.0,"distance":4825.0,"steps":0,"calories":253}],"caloriesIdle":1509,"lastUpdate":"20150714T053316Z"},{"date":"20150714","summary":[{"activity":"walking","group":"walking","duration":2066.0,"distance":1878.0,"steps":690,"calories":98}],"caloriesIdle":1509,"lastUpdate":"20150714T113320Z"},{"date":"20150715","summary":[{"activity":"walking","group":"walking","duration":7843.0,"distance":8279.0,"steps":11447,"calories":434},{"activity":"transport","group":"transport","duration":1625.0,"distance":15169.0}],"caloriesIdle":1509,"lastUpdate":"20150715T163318Z"},{"date":"20150716","summary":[{"activity":"walking","group":"walking","duration":711.0,"distance":718.0,"steps":737,"calories":38}],"caloriesIdle":1509,"lastUpdate":"20150715T203330Z"},{"date":"20150717","summary":[{"activity":"walking","group":"walking","duration":429.0,"distance":337.0,"steps":543,"calories":18},{"activity":"transport","group":"transport","duration":1236.0,"distance":4778.0}],"caloriesIdle":1509,"lastUpdate":"20150718T153332Z"}]

各プロパティの解説

date
日付。
activity
運動項目。
group
運動カテゴリ。
duration
時間(秒)。
distance
距離(メートル)。
calories
消費カロリー。
steps
歩数。歩き、走りなど、歩数に対応した運動のオブジェクトにのみ含まれる。
caloriesIdle
1日の総消費カロリー。
lastUpdate
データの最終更新日時。

運動カテゴリの種類

JSONデータ内ではgroupに格納される、運動カテゴリの種類は下記の通りです。運動項目の種類については、この記事内の「運動項目のデータを取得する」をご参考下さい!

walking
ウォーキング。
running
ランニング。
cycling
サイクリング。
transport
交通機関(電車、車など)。

サンプルプログラム

それでは、早速1週間分のサマリーデータを取得してみましょう。そのためのサンプルプログラムが、下記です。プログラムを実行すると、指定した日の運動データが一覧で簡易表示されます。このサンプルデモでは、著者である、あらゆの運動記録を取得しています。自分のデータを見る時は、実際のMovesアプリ上のデータと合っているか比較してみて下さいね!

PHP

<?php

	// 設定項目
	$request_url = 'https://api.moves-app.com/api/1.1/user/summary/daily?from=20150710&to=20150717' ;	// リクエストURL
	$access_token = '' ;	// アクセストークン

	// リクエストURLにアクセストークンを結合
	$is_param = explode( '?' , $request_url ) ;
	$request_url .= ( ( isset( $is_param[1] ) && !empty( $is_param[1] ) ) ? '&' : '?' ) . 'access_token=' . $access_token ;
   
	// JSONデータを取得する
	$curl = curl_init() ;
	curl_setopt( $curl , CURLOPT_URL , $request_url ) ;
	curl_setopt( $curl , CURLOPT_HEADER, 1 ) ; 
	curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false ) ;								// 証明書の検証を行わない
	curl_setopt( $curl , CURLOPT_RETURNTRANSFER , true ) ;								// curl_execの結果を文字列で返す
	curl_setopt( $curl , CURLOPT_TIMEOUT , 5 ) ;										// タイムアウトの秒数
	$res1 = curl_exec( $curl ) ;
	$res2 = curl_getinfo( $curl ) ;
	curl_close( $curl ) ;

	// 取得したデータ
	$json = substr( $res1, $res2['header_size'] ) ;										// 取得したデータ(JSONなど)
	$header = substr( $res1, 0, $res2['header_size'] ) ;								// レスポンスヘッダー (検証に利用したい場合にどうぞ)

	// オブジェクトに変換する
	$obj = json_decode( $json ) ;

	// HTML用
	$html = '' ;

	// エラー判定
	if( !$obj )
	{
		$html .= '<p>データを取得できませんでした…。</p>' ;
	}
	else
	{
		// HTML
		$html .= '<h2>実行結果</h2>' ;
		$html .= '<p>下記の内容で取得しました。</p>' ;

		foreach( $obj as $item )
		{
			// 1日ごとのサマリーを解析
			$html .= '<h3>' . $item->date . '</h3>' ;

			// 内容がなければスキップ
			if( !isset($item->summary) || empty($item->summary) )
			{
				continue ;
			}

			// データを確認
			foreach( $item->summary as $summary )
			{
				// 各データの整理
				$value = $summary->activity ;	// 運動項目
				$category = $summary->group ;	// 運動カテゴリ
				$duration = $summary->duration ;	// 時間(秒)
				$distance = $summary->distance ;	// 距離(メートル)
				$cal = ( isset($summary->calories) ) ? $summary->calories : '-' ;	// カロリー(kcal)
				$steps = ( isset($summary->steps) ) ? $summary->steps : '-' ;	// 歩数

				// 出力
				$html .= '<dl>' ;
				$html .= 	'<dt>項目</dt>' ;
				$html .= 		'<dd>' . $value . '</dd>' ;
				$html .= 	'<dt>カテゴリ</dt>' ;
				$html .= 		'<dd>' . $category . '</dd>' ;
				$html .= 	'<dt>時間 (秒数)</dt>' ;
				$html .= 		'<dd>' . $duration . '</dd>' ;
				$html .= 	'<dt>距離 (メートル)</dt>' ;
				$html .= 		'<dd>' . $distance . '</dd>' ;
				$html .= 	'<dt>カロリー</dt>' ;
				$html .= 		'<dd>' . $cal . '</dd>' ;
				$html .= 	'<dt>歩数</dt>' ;
				$html .= 		'<dd>' . $steps . '</dd>' ;
				$html .= '</dl>' ;
			}
		}
	}

	// 取得したデータ
	$html .= '<h2>取得したデータ</h2>' ;
	$html .= '<p>下記のデータを取得できました。</p>' ;
	$html .= 	'<h3>JSON</h3>' ;
	$html .= 	'<p><textarea rows="8">' . $json . '</textarea></p>' ;
	$html .= 	'<h3>レスポンスヘッダー</h3>' ;
	$html .= 	'<p><textarea rows="8">' . $header . '</textarea></p>' ;

?>

<?php
	// ブラウザに[$html]を出力 (HTMLのヘッダーとフッターを付けましょう)
	echo $html ;
?>

このコードの動作を確認する

アクティビティの取得 [Activities]

前章では「サマリーデータ」を取得しました。サマリーデータはその名の通り、概要(まとめ)でしかありません。アクティビティAPIでは、運動に関するさらに細かいデータを取得することが可能です。公式ドキュメントは下記ページをご覧下さい。

リクエスト方法

Activitiesのデータを取得するためには、それぞれの指定されたURLに、GETメソッドでリクエストを送ります。全てのリクエストのパラメータにはaccess_tokenのプロパティ名で、アクセストークンを付与して下さい。また、アプリのパーミッションで「activity」を指定している必要があります。

GET https://api.moves-app.com/api/1.1/user/activities/daily/{取得期間}

fromtopastDaysといったクエリを付ける場合は、スラッシュ(/)を除いて下さい。

GET https://api.moves-app.com/api/1.1/user/activities/daily?pastDays=3

データを取得する期間の調整

どの期間のアクティビティデータを取得するかを、URLの組み立て方によって調整することができます。これらは「サマリーデータ」の時と全く一緒です。

YYYYMMDD
1日分の指定。
例: 20170611
YYYY-Www
1週間分。年と、週番号を指定する。
例: 2017W23
YYYYMM
1ヶ月分。年と、月を指定する。
例: 201706
from={YYYYMM}&to={YYYYMM}
fromtoパラメータにそれぞれ日付(YYYYMMDD)を指定することで、細かく期間を調整することができる。最大31日間まで指定可。
例: from=20170604&to=20170609
pastDays={日数}
pastDaysパラメータに日数を示す数値を指定することで、現在から過去〜日間というように期間を指定できる。最大31日間まで指定可。
例: pastDays=30

取得できるJSON

取得できるJSONデータは下記の通りです。2日分ですが、サイズは膨大です。summary内にはSummariesで取得できるものと同じJSONデータが含まれています。segmentsには、その日のセグメントが配列形式で、それぞれのセグメント内のactivitiesには、セグメントごとの運動内容が配列形式で含まれます。

JSON

[{"date":"20150710","summary":[{"activity":"walking","group":"walking","duration":9694.0,"distance":8543.0,"steps":8838,"calories":448},{"activity":"transport","group":"transport","duration":18443.0,"distance":337519.0}],"segments":[{"type":"place","startTime":"20150708T201707+0900","endTime":"20150710T082046+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T081522+0900","endTime":"20150710T081633+0900","duration":71.0,"distance":36.0,"steps":0,"calories":2}],"lastUpdate":"20150710T015057Z"},{"type":"move","startTime":"20150710T082046+0900","endTime":"20150710T100922+0900","activities":[{"activity":"transport","group":"transport","manual":false,"startTime":"20150710T082046+0900","endTime":"20150710T100922+0900","duration":6516.0,"distance":135254.0}],"lastUpdate":"20150710T015057Z"},{"type":"place","startTime":"20150710T100922+0900","endTime":"20150710T112200+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T101103+0900","endTime":"20150710T102202+0900","duration":659.0,"distance":494.0,"steps":540,"calories":26},{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T110436+0900","endTime":"20150710T111036+0900","duration":360.0,"distance":270.0,"steps":356,"calories":14}],"lastUpdate":"20150710T042204Z"},{"type":"move","startTime":"20150710T112200+0900","endTime":"20150710T122915+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T112200+0900","endTime":"20150710T112831+0900","duration":391.0,"distance":377.0,"steps":367,"calories":20},{"activity":"transport","group":"transport","manual":false,"startTime":"20150710T112831+0900","endTime":"20150710T122434+0900","duration":3363.0,"distance":37436.0},{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T122434+0900","endTime":"20150710T122915+0900","duration":281.0,"distance":303.0,"steps":329,"calories":16}],"lastUpdate":"20150710T042204Z"},{"type":"place","startTime":"20150710T122915+0900","endTime":"20150710T131545+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T123134+0900","endTime":"20150710T124635+0900","duration":901.0,"distance":676.0,"steps":235,"calories":35},{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T131015+0900","endTime":"20150710T131253+0900","duration":158.0,"distance":119.0,"steps":0,"calories":6}],"lastUpdate":"20150710T072628Z"},{"type":"move","startTime":"20150710T131545+0900","endTime":"20150710T141135+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T131545+0900","endTime":"20150710T141135+0900","duration":3350.0,"distance":3348.0,"steps":3834,"calories":175}],"lastUpdate":"20150710T072628Z"},{"type":"place","startTime":"20150710T141135+0900","endTime":"20150710T143518+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T141227+0900","endTime":"20150710T141534+0900","duration":187.0,"distance":140.0,"steps":39,"calories":7}],"lastUpdate":"20150710T072632Z"},{"type":"move","startTime":"20150710T143518+0900","endTime":"20150710T150027+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T143518+0900","endTime":"20150710T143937+0900","duration":259.0,"distance":220.0,"steps":221,"calories":12},{"activity":"transport","group":"transport","manual":false,"startTime":"20150710T143937+0900","endTime":"20150710T144737+0900","duration":480.0,"distance":1306.0},{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T144737+0900","endTime":"20150710T150028+0900","duration":771.0,"distance":575.0,"steps":1023,"calories":30}],"lastUpdate":"20150710T072632Z"},{"type":"place","startTime":"20150710T150028+0900","endTime":"20150710T155402+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T150144+0900","endTime":"20150710T151345+0900","duration":721.0,"distance":541.0,"steps":348,"calories":28}],"lastUpdate":"20150710T105110Z"},{"type":"move","startTime":"20150710T155402+0900","endTime":"20150710T160309+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T155402+0900","endTime":"20150710T160309+0900","duration":547.0,"distance":563.0,"steps":476,"calories":29}],"lastUpdate":"20150710T105110Z"},{"type":"move","startTime":"20150710T160910+0900","endTime":"20150710T165229+0900","activities":[{"activity":"transport","group":"transport","manual":false,"startTime":"20150710T160910+0900","endTime":"20150710T165229+0900","duration":2599.0,"distance":26302.0}],"lastUpdate":"20150710T105110Z"},{"type":"place","startTime":"20150710T165230+0900","endTime":"20150710T171455+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T165243+0900","endTime":"20150710T165413+0900","duration":90.0,"distance":61.0,"steps":121,"calories":3},{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T170429+0900","endTime":"20150710T171007+0900","duration":338.0,"distance":288.0,"steps":384,"calories":15}],"lastUpdate":"20150710T105117Z"},{"type":"move","startTime":"20150710T171455+0900","endTime":"20150710T171903+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T171455+0900","endTime":"20150710T171904+0900","duration":249.0,"distance":233.0,"steps":170,"calories":12}],"lastUpdate":"20150710T105117Z"},{"type":"move","startTime":"20150710T172532+0900","endTime":"20150710T174309+0900","activities":[{"activity":"transport","group":"transport","manual":false,"startTime":"20150710T172532+0900","endTime":"20150710T174310+0900","duration":1058.0,"distance":34268.0}],"lastUpdate":"20150710T105117Z"},{"type":"place","startTime":"20150710T174309+0900","endTime":"20150710T185730+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T174416+0900","endTime":"20150710T174616+0900","duration":120.0,"distance":108.0,"steps":143,"calories":6},{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T181335+0900","endTime":"20150710T181405+0900","duration":30.0,"distance":26.0,"steps":51,"calories":1}],"lastUpdate":"20150710T130006Z"},{"type":"move","startTime":"20150710T185730+0900","endTime":"20150710T201417+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T185730+0900","endTime":"20150710T190031+0900","duration":181.0,"distance":145.0,"steps":160,"calories":8},{"activity":"transport","group":"transport","manual":false,"startTime":"20150710T190031+0900","endTime":"20150710T201418+0900","duration":4427.0,"distance":102953.0}],"lastUpdate":"20150710T130006Z"},{"type":"place","startTime":"20150710T201417+0900","endTime":"20150711T183611+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150710T201713+0900","endTime":"20150710T201743+0900","duration":30.0,"distance":20.0,"steps":41,"calories":1}],"lastUpdate":"20150711T113318Z"}],"caloriesIdle":1509,"lastUpdate":"20150711T113318Z"},{"date":"20150711","summary":[{"activity":"walking","group":"walking","duration":3274.0,"distance":4047.0,"steps":5558,"calories":212}],"segments":[{"type":"place","startTime":"20150710T201417+0900","endTime":"20150711T183611+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150711T045727+0900","endTime":"20150711T045734+0900","duration":7.0,"distance":4.0,"steps":0,"calories":0},{"activity":"walking","group":"walking","manual":false,"startTime":"20150711T183542+0900","endTime":"20150711T183544+0900","duration":2.0,"distance":1.0,"steps":0,"calories":0}],"lastUpdate":"20150711T113318Z"},{"type":"move","startTime":"20150711T183611+0900","endTime":"20150711T190956+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150711T183611+0900","endTime":"20150711T190956+0900","duration":2025.0,"distance":2458.0,"steps":3516,"calories":129}],"lastUpdate":"20150711T113318Z"},{"type":"place","startTime":"20150711T190956+0900","endTime":"20150711T192252+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150711T191222+0900","endTime":"20150711T191522+0900","duration":180.0,"distance":146.0,"steps":195,"calories":8}],"lastUpdate":"20150711T113318Z"},{"type":"move","startTime":"20150711T192252+0900","endTime":"20150711T193932+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150711T192252+0900","endTime":"20150711T193932+0900","duration":1000.0,"distance":1392.0,"steps":1755,"calories":73}],"lastUpdate":"20150711T113318Z"},{"type":"place","startTime":"20150711T193932+0900","endTime":"20150712T194926+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150711T194254+0900","endTime":"20150711T194354+0900","duration":60.0,"distance":46.0,"steps":92,"calories":2}],"lastUpdate":"20150713T124818Z"}],"caloriesIdle":1509,"lastUpdate":"20150713T124818Z"}]

各プロパティの解説

date
日付。
segments
セグメント。
summary
Summariesのエンドポイントで取得できるのと同じ内容。
type
セグメントの種類。
startTime
セグメントの開始時間。
endTime
セグメントの終了時間。
activities
運動内容。
manual
マニュアルで追加された運動か否か。
activity
運動項目。
group
運動カテゴリ。
duration
時間(秒)。
distance
距離(メートル)。
calories
消費カロリー。
steps
歩数。歩き、走りなど、歩数に対応した運動のオブジェクトにのみ含まれる。
caloriesIdle
1日の総消費カロリー。
lastUpdate
データの最終更新日時。

セグメントとは…?

プログラムの実行結果
プログラムの実行結果

テキストだけだとピンときませんよね…?「セグメント」とは、上記図の区切りのことです。図では上から「自転車(移動)」「ラーメン店(場所)」「自転車(移動)」となっていますよね?この「移動」「場所」「移動」が、それぞれ1まとまりのデータとして、segments内に配列形式で含まれているというわけです。

「移動」はmove、「場所」はplaceとして、typeプロパティに格納されています。青文字コメントで「セグメントの種類」と付けている部分です。そして、それぞれのセグメント内の運動データが、activities内に、格納されています。

サンプルプログラム

それでは、1週間分のアクティビティデータを取得してみましょう。取得するためのサンプルプログラムが、下記の通りです。$request_url$access_tokenは自身の環境に合わせて調整して下さいね!分単位の、時間ごとのデータなので、とても大きなデータとなることにご注意下さい。

PHP

<?php

	// 設定項目
	$request_url = 'https://api.moves-app.com/api/1.1/user/activities/daily?from=20150710&to=20150717' ;	// リクエストURL
	$access_token = '' ;	// アクセストークン

	// リクエストURLにアクセストークンを結合
	$is_param = explode( '?' , $request_url ) ;
	$request_url .= ( ( isset( $is_param[1] ) && !empty( $is_param[1] ) ) ? '&' : '?' ) . 'access_token=' . $access_token ;
   
	// JSONデータを取得する
	$curl = curl_init() ;
	curl_setopt( $curl , CURLOPT_URL , $request_url ) ;
	curl_setopt( $curl , CURLOPT_HEADER, 1 ) ; 
	curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false ) ;								// 証明書の検証を行わない
	curl_setopt( $curl , CURLOPT_RETURNTRANSFER , true ) ;								// curl_execの結果を文字列で返す
	curl_setopt( $curl , CURLOPT_TIMEOUT , 5 ) ;										// タイムアウトの秒数
	$res1 = curl_exec( $curl ) ;
	$res2 = curl_getinfo( $curl ) ;
	curl_close( $curl ) ;

	// 取得したデータ
	$json = substr( $res1, $res2['header_size'] ) ;										// 取得したデータ(JSONなど)
	$header = substr( $res1, 0, $res2['header_size'] ) ;								// レスポンスヘッダー (検証に利用したい場合にどうぞ)

	// オブジェクトに変換する
	$obj = json_decode( $json ) ;

	// HTML用
	$html = '' ;

	// エラー判定
	if( !$obj )
	{
		$html .= '<p>データを取得できませんでした…。</p>' ;
	}
	else
	{
		// HTML
		$html .= '<h2>実行結果</h2>' ;
		$html .= '<p>下記の内容で取得しました。</p>' ;

		// ループ
		foreach( $obj as $segments )
		{
			// 1日ごとのアクティビティを解析
			$html .= '<h3>' . $segments->date . '</h3>' ;

			// 内容がなければスキップ
			if( !isset( $segments->segments ) || empty( $segments->segments ) )
			{
				continue ;
			}

			// セグメントごとの処理
			foreach( $segments->segments as $item )
			{
				// 各データ
				$segment = $item->type ;	// セグメントの種類
				$start = date( 'H:i' , strtotime( $item->startTime ) ) ;	// 開始時間
				$end = date( 'H:i' , strtotime( $item->endTime ) ) ;	// 終了時間

				// 各時間ごとのアクティビティを解析
				$html .= '<h4>' . $segment . ' (' . $start . '〜' . $end . ')</h4>' ;

				// 内容がなければスキップ
				if( !isset( $item->activities ) || empty( $item->activities ) )
				{
					continue ;
				}

				// データを確認
				foreach( $item->activities as $activity )
				{
					// 各データの整理
					$value = $activity->activity ;	// 運動項目
					$category = $activity->group ;	// 運動カテゴリ
					$duration = $activity->duration ;	// 時間(秒)
					$distance = $activity->distance ;	// 距離(メートル)
					$cal = ( isset($activity->calories) ) ? $activity->calories : '-' ;	// カロリー(kcal)
					$steps = ( isset($activity->steps) ) ? $activity->steps : '-' ;	// 歩数

					// 出力
					$html .= '<dl>' ;
					$html .= 	'<dt>項目</dt>' ;
					$html .= 		'<dd>' . $value . '</dd>' ;
					$html .= 	'<dt>カテゴリ</dt>' ;
					$html .= 		'<dd>' . $category . '</dd>' ;
					$html .= 	'<dt>時間 (秒数)</dt>' ;
					$html .= 		'<dd>' . $duration . '</dd>' ;
					$html .= 	'<dt>距離 (メートル)</dt>' ;
					$html .= 		'<dd>' . $distance . '</dd>' ;
					$html .= 	'<dt>カロリー</dt>' ;
					$html .= 		'<dd>' . $cal . '</dd>' ;
					$html .= 	'<dt>歩数</dt>' ;
					$html .= 		'<dd>' . $steps . '</dd>' ;
					$html .= '</dl>' ;
				}
			}
		}
	}

	// 取得したデータ
	$html .= '<h2>取得したデータ</h2>' ;
	$html .= '<p>下記のデータを取得できました。</p>' ;
	$html .= 	'<h3>JSON</h3>' ;
	$html .= 	'<p><textarea rows="8">' . $json . '</textarea></p>' ;
	$html .= 	'<h3>レスポンスヘッダー</h3>' ;
	$html .= 	'<p><textarea rows="8">' . $header . '</textarea></p>' ;

?>

<?php
	// ブラウザに[$html]を出力 (HTMLのヘッダーとフッターを付けましょう)
	echo $html ;
?>

このコードの動作を確認する

滞在記録(プレイス)の取得 [Places]

前章では「アクティビティデータ」を取得しました。今度は運動データではなく、「場所」のデータを取得してみましょう。Movesに記録された「ユーザーが滞在した場所」のデータを取得できるのが、この章で紹介するPlaces APIです。

リクエスト方法

Activitiesのデータを取得するためには、それぞれの指定されたURLに、GETメソッドでリクエストを送ります。全てのリクエストのパラメータにはaccess_tokenのプロパティ名で、アクセストークンを付与して下さい。アプリのパーミッションで「location」を指定している必要があります。

GET https://api.moves-app.com/api/1.1/user/places/daily/{取得期間}

fromtopastDaysといったクエリを付ける場合は、スラッシュ(/)を除いて下さい。

GET https://api.moves-app.com/api/1.1/user/places/daily?pastDays=3

データを取得する期間の調整

どの期間のアクティビティデータを取得するかを、URLの組み立て方によって調整することができます。これらは「サマリーデータ」の時と全く一緒です。

YYYYMMDD
1日分の指定。
例: 20170611
YYYY-Www
1週間分。年と、週番号を指定する。
例: 2017W23
YYYYMM
1ヶ月分。年と、月を指定する。
例: 201706
from={YYYYMM}&to={YYYYMM}
fromtoパラメータにそれぞれ日付(YYYYMMDD)を指定することで、細かく期間を調整することができる。最大31日間まで指定可。
例: from=20170604&to=20170609
pastDays={日数}
pastDaysパラメータに日数を示す数値を指定することで、現在から過去〜日間というように期間を指定できる。最大31日間まで指定可。
例: pastDays=30

取得できるJSON

リクエストによって取得できるJSONデータを見てみましょう。このように、指定した期間に滞在した場所のリストがsegments内に配列形式で格納されます。場所の緯度・経度も取得できるので、Google Maps APIなどを使えば、地図を描写することが可能ですねー。

JSON

[{"date":"20150710","segments":[{"type":"place","startTime":"20150710T100922+0900","endTime":"20150710T112200+0900","place":{"id":355539107,"name":"こんにゃくパーク","type":"foursquare","foursquareId":"53646d5f498ec5bdccd0383e","foursquareCategoryIds":["4bf58dd8d48988d182941735"],"location":{"lat":36.24355424343968,"lon":138.9202213353453}},"lastUpdate":"20150725T051145Z"},{"type":"place","startTime":"20150710T122915+0900","endTime":"20150710T131545+0900","place":{"id":355563805,"name":"神津牧場","type":"foursquare","foursquareId":"4be63f82bcef2d7f6b0705e5","foursquareCategoryIds":["4bf58dd8d48988d15b941735"],"location":{"lat":36.24814611072865,"lon":138.6206111609586}},"lastUpdate":"20150725T051254Z"},{"type":"place","startTime":"20150710T141135+0900","endTime":"20150710T143518+0900","place":{"id":355563805,"name":"神津牧場","type":"foursquare","foursquareId":"4be63f82bcef2d7f6b0705e5","foursquareCategoryIds":["4bf58dd8d48988d15b941735"],"location":{"lat":36.24814611072865,"lon":138.6206111609586}},"lastUpdate":"20150725T051324Z"},{"type":"place","startTime":"20150710T150028+0900","endTime":"20150710T155402+0900","place":{"id":355594583,"name":"荒船風穴","type":"user","location":{"lat":36.2496513813,"lon":138.620968059}},"lastUpdate":"20150725T051324Z"},{"type":"place","startTime":"20150710T160309+0900","endTime":"20150710T160910+0900","place":{"id":361746992,"name":"荒船風穴 (Arafune Cold Storage)","type":"foursquare","foursquareId":"505d65ffe4b08ab5c26f0370","foursquareCategoryIds":["4bf58dd8d48988d1f6931735"],"location":{"lat":36.24651334627292,"lon":138.6328259560423}},"lastUpdate":"20150725T051608Z"},{"type":"place","startTime":"20150710T165230+0900","endTime":"20150710T171455+0900","place":{"id":355602943,"name":"道の駅しもにた","type":"foursquare","foursquareId":"4bcbb916cc8cd13a6404c0cf","foursquareCategoryIds":["4d954b16a243a5684b65b473"],"location":{"lat":36.22361611262539,"lon":138.8019293546677}},"lastUpdate":"20150725T051335Z"},{"type":"place","startTime":"20150710T171904+0900","endTime":"20150710T172532+0900","place":{"id":355644762,"type":"unknown","location":{"lat":36.2243178077,"lon":138.8036278976}},"lastUpdate":"20150710T105117Z"},{"type":"place","startTime":"20150710T174309+0900","endTime":"20150710T185730+0900","place":{"id":355644753,"name":"上里SA (上り)","type":"foursquare","foursquareId":"4b5a3595f964a52060b428e3","foursquareCategoryIds":["4d954b16a243a5684b65b473"],"location":{"lat":36.25601421492158,"lon":139.1202914714813}},"lastUpdate":"20150725T051343Z"}],"lastUpdate":"20150725T051608Z"},{"date":"20150711","segments":[{"type":"place","startTime":"20150711T190956+0900","endTime":"20150711T192252+0900","place":{"id":222245585,"name":"ライフ 竹の塚店","type":"foursquare","foursquareId":"4cfdf586c6cca35d2c8e9932","foursquareCategoryIds":["52f2ab2ebcbc57f1066b8b46"],"location":{"lat":35.80157491216828,"lon":139.7832282698249}},"lastUpdate":"20150725T051655Z"}],"lastUpdate":"20150725T051655Z"}]

各プロパティの解説

date
日付。
segments
セグメント。
type
セグメントの種類。
startTime
セグメントの開始時間。
endTime
セグメントの終了時間。
place
場所の内容。
id
場所ID。
name
場所名。
place->type
場所タイプ。
foursquareId
場所データがfoursquareと関連付けられている場合、foursquare IDが含まれる。
foursquareCategoryIds
場所データがfoursquareと関連付けられている場合、foursquare上の場所カテゴリが含まれる。
location
場所の座標情報。
lat
緯度。
lon
経度。
lastUpdate
データの最終更新日時。

Foursquareとの連動

Movesでは場所名を、foursquareと連動して登録することができます。その場合、foursquare上の場所IDも記録されるため、foursquareのAPIと連携すれば、写真やクチコミなど、さらに詳しい情報と関連付けることが可能です。例えば、サンプルのfoursquare IDの51824568498ea1d79f1fcdf2を利用して、foursquareのパーマリンクを、次の通り組み立てることができます。

https://ja.foursquare.com/v/51824568498ea1d79f1fcdf2

場所タイプの種類

JSONデータ内ではgroupに格納される、運動カテゴリの種類は下記の通りです。運動項目の種類については、この記事内の「運動項目のデータを取得する」をご参考下さい!

unknown
名称が未登録状態。
home
「自宅」に設定している。
school
「学校」に設定している。
work
「勤務地」に設定している。
user
マニュアルで名称を登録している。
foursquare
foursquareに関連付けて名称を登録している。

サンプルプログラム

それでは、1日分の滞在記録データを取得してみましょう。取得するためのサンプルプログラムが、下記の通りです。$request_url$access_tokenは自身の環境に合わせて調整して下さいね!

PHP

<?php

	// 設定項目
	$request_url = 'https://api.moves-app.com/api/1.1/user/places/daily?from=20150710&to=20150711' ;	// リクエストURL
	$access_token = '' ;	// アクセストークン

	// リクエストURLにアクセストークンを結合
	$is_param = explode( '?' , $request_url ) ;
	$request_url .= ( ( isset( $is_param[1] ) && !empty( $is_param[1] ) ) ? '&' : '?' ) . 'access_token=' . $access_token ;
   
	// JSONデータを取得する
	$curl = curl_init() ;
	curl_setopt( $curl , CURLOPT_URL , $request_url ) ;
	curl_setopt( $curl , CURLOPT_HEADER, 1 ) ; 
	curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false ) ;								// 証明書の検証を行わない
	curl_setopt( $curl , CURLOPT_RETURNTRANSFER , true ) ;								// curl_execの結果を文字列で返す
	curl_setopt( $curl , CURLOPT_TIMEOUT , 5 ) ;										// タイムアウトの秒数
	$res1 = curl_exec( $curl ) ;
	$res2 = curl_getinfo( $curl ) ;
	curl_close( $curl ) ;

	// 取得したデータ
	$json = substr( $res1, $res2['header_size'] ) ;										// 取得したデータ(JSONなど)
	$header = substr( $res1, 0, $res2['header_size'] ) ;								// レスポンスヘッダー (検証に利用したい場合にどうぞ)

	// オブジェクトに変換する
	$obj = json_decode( $json ) ;

	// HTML用
	$html = '' ;

	// エラー判定
	if( !$obj )
	{
		$html .= '<p>データを取得できませんでした…。</p>' ;
	}
	else
	{
		// HTML
		$html .= '<h2>実行結果</h2>' ;
		$html .= '<p>下記の内容で取得しました。</p>' ;

		// ループ
		foreach( $obj as $item )
		{
			// 1日ごとの滞在記録を解析
			$html .= '<h3>' . $item->date . '</h3>' ;

			// 内容がなければスキップ
			if( !isset( $item->segments ) || empty( $item->segments ) )
			{
				continue ;
			}

			// セグメントごとの処理
			foreach( $item->segments as $segment )
			{
				// 各データ
				$start = date( 'H:i', strtotime( $segment->startTime ) ) ;	// 開始時間
				$end = date( 'H:i' , strtotime( $segment->endTime ) ) ;	// 終了時間
				$name = ( isset($segment->place->name) && !empty($segment->place->name) ) ? $segment->place->name : '不明' ;	// 場所名
				$type = $segment->place->type ;	// 場所タイプ
				$lat = $segment->place->location->lat ;	// 緯度
				$lon = $segment->place->location->lon ;	// 経度

				// 出力
				$html .= '<h4>' . $start . '〜' . $end . '</h4>' ;
				$html .= '<dl>' ;
				$html .= 	'<dt>名前</dt>' ;
				$html .= 		'<dd>' . $name . '</dd>' ;
				$html .= 	'<dt>場所タイプ</dt>' ;
				$html .= 		'<dd>' . $type . '</dd>' ;
				$html .= 	'<dt>緯度</dt>' ;
				$html .= 		'<dd>' . $lat . '</dd>' ;
				$html .= 	'<dt>経度</dt>' ;
				$html .= 		'<dd>' . $lon . '</dd>' ;
				$html .= '</dl>' ;
			}
		}
	}

	// 取得したデータ
	$html .= '<h2>取得したデータ</h2>' ;
	$html .= '<p>下記のデータを取得できました。</p>' ;
	$html .= 	'<h3>JSON</h3>' ;
	$html .= 	'<p><textarea rows="8">' . $json . '</textarea></p>' ;
	$html .= 	'<h3>レスポンスヘッダー</h3>' ;
	$html .= 	'<p><textarea rows="8">' . $header . '</textarea></p>' ;

?>

<?php
	// ブラウザに[$html]を出力 (HTMLのヘッダーとフッターを付けましょう)
	echo $html ;
?>

このコードの動作を確認する

ストーリーラインの取得 [Storyline]

これまで、「サマリー(概要)」「アクティビティ(運動)」「プレイス(場所)」と、取得してきました。続いてこの章では、それらを総合した「ストーリーライン」の取得方法を紹介します。

リクエスト方法

Storylineのデータを取得するためには、それぞれの指定されたURLに、GETメソッドでリクエストを送ります。全てのリクエストのパラメータにはaccess_tokenのプロパティ名で、アクセストークンを付与して下さい。アプリのパーミッションで「activity」「location」の両方を指定している必要があります。

GET https://api.moves-app.com/api/1.1/user/storyline/daily/{取得期間}

fromtopastDaysといったクエリを付ける場合は、スラッシュ(/)を除いて下さい。

GET https://api.moves-app.com/api/1.1/user/storyline/daily?pastDays=3

データを取得する期間の調整

どの期間のストーリーラインを取得するかを、URLの組み立て方によって調整することが可能です。これらは「サマリーデータ」「アクティビティデータ」「プレイスデータ」の時と一緒ですが、取得できる日数は最大7日間となっています。

YYYYMMDD
1日分の指定。
例: 20170611
YYYY-Www
1週間分。年と、週番号を指定する。
例: 2017W23
YYYYMM
1ヶ月分。年と、月を指定する。
例: 201706
from={YYYYMM}&to={YYYYMM}
fromtoパラメータにそれぞれ日付(YYYYMMDD)を指定することで、細かく期間を調整することができる。最大7日間まで指定可。
例: from=20170604&to=20170609
pastDays={日数}
pastDaysパラメータに日数を示す数値を指定することで、現在から過去〜日間というように期間を指定できる。最大7日間まで指定可。
例: pastDays=30

「トラックポイント」を取得する

MovesのTrackpointとは
MovesのTrackpointとは

Storylineでは「トラックポイント」を取得することができます。このトラックポイントとは「移動した際に通った全ての座標(緯度・経度)」です。それらの座標を全て繋ぎ合わせることによって、図のように地図上にラインを作成したりすることができます。

トラックポイントをJSONデータに含めるには、下記のパラメータをリクエストURLに追加します。膨大なデータ量になるのでご注意下さい。

trackPoints=true

取得できるJSON

リクエストによって取得できるJSONデータを見てみましょう。1日分のデータです。Storylineは、「サマリー」「アクティビティ」「プレイス」を全て混ぜ合わせたJSONデータになっています。オプションで「トラックポイント」を有効にした場合、それに加えてactivitiesの中にtrackPointsが追加されます。

JSON

[{"date":"20150711","summary":[{"activity":"walking","group":"walking","duration":3205.0,"distance":3996.0,"steps":5466,"calories":209}],"segments":[{"type":"move","startTime":"20150711T183611+0900","endTime":"20150711T190956+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150711T183611+0900","endTime":"20150711T190956+0900","duration":2025.0,"distance":2458.0,"steps":3516,"calories":129,"trackPoints":[{"lat":35.7987,"lon":139.79452,"time":"20150711T183611+0900"},{"lat":35.800980749,"lon":139.7943227239,"time":"20150711T184005+0900"},{"lat":35.8011546505,"lon":139.7939920851,"time":"20150711T184028+0900"},{"lat":35.8014115435,"lon":139.7937359989,"time":"20150711T184049+0900"},{"lat":35.8017328318,"lon":139.7935131589,"time":"20150711T184110+0900"},{"lat":35.8022552014,"lon":139.7935119402,"time":"20150711T184200+0900"},{"lat":35.8025383969,"lon":139.7935493314,"time":"20150711T184225+0900"},{"lat":35.8033896605,"lon":139.7937819428,"time":"20150711T184322+0900"},{"lat":35.803950501,"lon":139.7936569782,"time":"20150711T184416+0900"},{"lat":35.8039791249,"lon":139.7935374063,"time":"20150711T184432+0900"},{"lat":35.8051213522,"lon":139.7914918337,"time":"20150711T184722+0900"},{"lat":35.8049887791,"lon":139.7911257844,"time":"20150711T184815+0900"},{"lat":35.8049807537,"lon":139.7910868472,"time":"20150711T184835+0900"},{"lat":35.8051030482,"lon":139.791098721,"time":"20150711T184850+0900"},{"lat":35.805291206,"lon":139.7908852905,"time":"20150711T184922+0900"},{"lat":35.8054006931,"lon":139.7906369438,"time":"20150711T184944+0900"},{"lat":35.8054816687,"lon":139.7904204541,"time":"20150711T185002+0900"},{"lat":35.8060109675,"lon":139.7886341438,"time":"20150711T185204+0900"},{"lat":35.8062117341,"lon":139.7884770345,"time":"20150711T185221+0900"},{"lat":35.8063863287,"lon":139.7881072377,"time":"20150711T185257+0900"},{"lat":35.8064105831,"lon":139.7880351199,"time":"20150711T185314+0900"},{"lat":35.8066378805,"lon":139.7872978836,"time":"20150711T185428+0900"},{"lat":35.8066710787,"lon":139.7869368249,"time":"20150711T185519+0900"},{"lat":35.8067430774,"lon":139.7868150675,"time":"20150711T185542+0900"},{"lat":35.8067443147,"lon":139.7865464479,"time":"20150711T185602+0900"},{"lat":35.806732787,"lon":139.7862313539,"time":"20150711T185620+0900"},{"lat":35.8068139013,"lon":139.7851336276,"time":"20150711T185751+0900"},{"lat":35.806856723,"lon":139.7846579458,"time":"20150711T185823+0900"},{"lat":35.8067131272,"lon":139.784364789,"time":"20150711T185921+0900"},{"lat":35.806676179,"lon":139.7845065262,"time":"20150711T185938+0900"},{"lat":35.8066505538,"lon":139.7844426546,"time":"20150711T185959+0900"},{"lat":35.8066505421,"lon":139.7844426255,"time":"20150711T190000+0900"},{"lat":35.8066465013,"lon":139.7844325537,"time":"20150711T190003+0900"},{"lat":35.8066314344,"lon":139.7842243666,"time":"20150711T190026+0900"},{"lat":35.8064713791,"lon":139.7841221346,"time":"20150711T190047+0900"},{"lat":35.8053805715,"lon":139.783490976,"time":"20150711T190245+0900"},{"lat":35.803143258,"lon":139.7834092248,"time":"20150711T190613+0900"},{"lat":35.8028202601,"lon":139.7833567173,"time":"20150711T190636+0900"},{"lat":35.80247794,"lon":139.7833148071,"time":"20150711T190658+0900"},{"lat":35.8020345246,"lon":139.7832582898,"time":"20150711T190735+0900"},{"lat":35.8019106972,"lon":139.7832108154,"time":"20150711T190755+0900"},{"lat":35.8018125047,"lon":139.7832538826,"time":"20150711T190817+0900"},{"lat":35.801700419,"lon":139.7833064587,"time":"20150711T190841+0900"},{"lat":35.8015990604,"lon":139.7833166716,"time":"20150711T190910+0900"},{"lat":35.8015996969,"lon":139.7833289927,"time":"20150711T190927+0900"},{"lat":35.801550366,"lon":139.7832721626,"time":"20150711T190956+0900"}]}],"lastUpdate":"20150711T113318Z"},{"type":"place","startTime":"20150711T190956+0900","endTime":"20150711T192252+0900","place":{"id":222245585,"name":"ライフ 竹の塚店","type":"foursquare","foursquareId":"4cfdf586c6cca35d2c8e9932","foursquareCategoryIds":["52f2ab2ebcbc57f1066b8b46"],"location":{"lat":35.80157491216828,"lon":139.7832282698249}},"activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150711T191222+0900","endTime":"20150711T191522+0900","duration":180.0,"distance":146.0,"steps":195,"calories":8,"trackPoints":[]}],"lastUpdate":"20150725T051655Z"},{"type":"move","startTime":"20150711T192252+0900","endTime":"20150711T193932+0900","activities":[{"activity":"walking","group":"walking","manual":false,"startTime":"20150711T192252+0900","endTime":"20150711T193932+0900","duration":1000.0,"distance":1392.0,"steps":1755,"calories":73,"trackPoints":[{"lat":35.801550366,"lon":139.7832721626,"time":"20150711T192252+0900"},{"lat":35.8020550217,"lon":139.7870076725,"time":"20150711T192613+0900"},{"lat":35.8020479874,"lon":139.7873872509,"time":"20150711T192629+0900"},{"lat":35.8020017686,"lon":139.7879134816,"time":"20150711T192652+0900"},{"lat":35.801987199,"lon":139.7883591739,"time":"20150711T192712+0900"},{"lat":35.8019998649,"lon":139.7885662912,"time":"20150711T192728+0900"},{"lat":35.8019880532,"lon":139.7888241369,"time":"20150711T192751+0900"},{"lat":35.8018642964,"lon":139.7894152853,"time":"20150711T192826+0900"},{"lat":35.8017935848,"lon":139.7897419085,"time":"20150711T192849+0900"},{"lat":35.8016742794,"lon":139.7899923536,"time":"20150711T192912+0900"},{"lat":35.8016077235,"lon":139.7902008762,"time":"20150711T192933+0900"},{"lat":35.8015291963,"lon":139.7903882969,"time":"20150711T192956+0900"},{"lat":35.8015466089,"lon":139.7906610516,"time":"20150711T193012+0900"},{"lat":35.8013312615,"lon":139.7904826433,"time":"20150711T193040+0900"},{"lat":35.8010250223,"lon":139.7901991355,"time":"20150711T193103+0900"},{"lat":35.8007254217,"lon":139.7900192869,"time":"20150711T193126+0900"},{"lat":35.8005984387,"lon":139.7899847296,"time":"20150711T193147+0900"},{"lat":35.8006210483,"lon":139.7900826878,"time":"20150711T193207+0900"},{"lat":35.8006210483,"lon":139.7900826878,"time":"20150711T193233+0900"},{"lat":35.8006211232,"lon":139.7900828602,"time":"20150711T193256+0900"},{"lat":35.8006502952,"lon":139.7901112769,"time":"20150711T193333+0900"},{"lat":35.8005817842,"lon":139.7903742172,"time":"20150711T193352+0900"},{"lat":35.8004262449,"lon":139.7908203505,"time":"20150711T193415+0900"},{"lat":35.8001951949,"lon":139.7914707288,"time":"20150711T193453+0900"},{"lat":35.7999481197,"lon":139.7921122599,"time":"20150711T193527+0900"},{"lat":35.7998218811,"lon":139.7924756214,"time":"20150711T193552+0900"},{"lat":35.7997128541,"lon":139.7927791019,"time":"20150711T193625+0900"},{"lat":35.7995385947,"lon":139.7928370979,"time":"20150711T193648+0900"},{"lat":35.7993995428,"lon":139.792806902,"time":"20150711T193711+0900"},{"lat":35.7992734926,"lon":139.7929404896,"time":"20150711T193732+0900"},{"lat":35.7992651665,"lon":139.7933234742,"time":"20150711T193753+0900"},{"lat":35.7992279822,"lon":139.7938138157,"time":"20150711T193819+0900"},{"lat":35.7991473787,"lon":139.7942151937,"time":"20150711T193840+0900"},{"lat":35.7988676656,"lon":139.7944631992,"time":"20150711T193907+0900"},{"lat":35.7987,"lon":139.79452,"time":"20150711T193932+0900"}]}],"lastUpdate":"20150711T113318Z"}],"caloriesIdle":1509,"lastUpdate":"20150725T051655Z"}]

このStoryline特有のオブジェクトであるtrackPointsの各プロパティについて説明します。その他のプロパティについては、各エンドポイントの項目で確認して下さい。

lat
緯度。
lon
経度。
time
その座標にいた時刻。

サンプルプログラム

それでは、1日分のストーリーラインデータを取得してみましょう。取得するためのサンプルプログラムが、下記の通りです。トラックポイントは数秒ごとに記録されるので、膨大な量になるのが分かると思います。

PHP

<?php

	// 設定項目
	$request_url = 'https://api.moves-app.com/api/1.1/user/storyline/daily?from=20150710&to=20150711&trackPoints=true' ;	// リクエストURL
	$access_token = '' ;	// アクセストークン

	// リクエストURLにアクセストークンを結合
	$is_param = explode( '?' , $request_url ) ;
	$request_url .= ( ( isset( $is_param[1] ) && !empty( $is_param[1] ) ) ? '&' : '?' ) . 'access_token=' . $access_token ;
   
	// JSONデータを取得する
	$curl = curl_init() ;
	curl_setopt( $curl , CURLOPT_URL , $request_url ) ;
	curl_setopt( $curl , CURLOPT_HEADER, 1 ) ; 
	curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false ) ;								// 証明書の検証を行わない
	curl_setopt( $curl , CURLOPT_RETURNTRANSFER , true ) ;								// curl_execの結果を文字列で返す
	curl_setopt( $curl , CURLOPT_TIMEOUT , 5 ) ;										// タイムアウトの秒数
	$res1 = curl_exec( $curl ) ;
	$res2 = curl_getinfo( $curl ) ;
	curl_close( $curl ) ;

	// 取得したデータ
	$json = substr( $res1, $res2['header_size'] ) ;										// 取得したデータ(JSONなど)
	$header = substr( $res1, 0, $res2['header_size'] ) ;								// レスポンスヘッダー (検証に利用したい場合にどうぞ)

	// オブジェクトに変換する
	$obj = json_decode( $json ) ;

	// HTML用
	$html = '' ;

	// エラー判定
	if( !$obj )
	{
		$html .= '<p>データを取得できませんでした…。</p>' ;
	}
	else
	{
		// HTML
		$html .= '<h2>実行結果</h2>' ;
		$html .= '<p>下記の内容で取得しました。</p>' ;

		// ループ
		foreach( $obj as $segments )
		{
			// 1日ごとのストーリーラインを解析
			$html .= '<h3>' . $segments->date . '</h3>' ;

			foreach( $segments->segments as $item )
			{
				// 滞在場所の開始時間と終了時間
				$start = date( 'H:i' , strtotime( $item->startTime ) ) ;
				$end = date( 'H:i' , strtotime( $item->endTime ) ) ;

				// 時間ごとの記録
				$html .= '<h4>' . $start . '〜' . $end . '</h4>' ;

				// 場所の場合
				if( $item->type == 'place' )
				{
					//場所名・場所タイプ・緯度・経度
					$name = ( isset($item->place->name) && !empty($item->place->name) ) ? $item->place->name : '不明' ;	// 場所名
					$type = $item->place->type ;	// 場所タイプ
					$lat = $item->place->location->lat ;	// 緯度
					$lon = $item->place->location->lon ;	// 経度

					// 出力
					$html .= '<dl>' ;
					$html .= 	'<dt>名前</dt>' ;
					$html .= 		'<dd>' . $name . '</dd>' ;
					$html .= 	'<dt>場所タイプ</dt>' ;
					$html .= 		'<dd>' . $type . '</dd>' ;
					$html .= 	'<dt>緯度</dt>' ;
					$html .= 		'<dd>' . $lat . '</dd>' ;
					$html .= 	'<dt>経度</dt>' ;
					$html .= 		'<dd>' . $lon . '</dd>' ;
					$html .= '</dl>' ;
				}

				// 運動の場合
				elseif( $item->type == 'move' || $item->type == 'off' )
				{
					// 運動内容の解析
					foreach( $item->activities as $activity )
					{
						//運動項目・カテゴリ・時間(秒)・距離(メートル)・カロリー(kcal)・歩数
						$value = $activity->activity ;	// 運動項目
						$category = $activity->group ;	// 運動カテゴリ
						$duration = $activity->duration ;	// 時間(秒)
						$distance = $activity->distance ;	// 距離(メートル)
						$cal = ( isset($activity->calories) ) ? $activity->calories : '-' ;	// カロリー(kcal)
						$steps = ( isset($activity->steps) ) ? $activity->steps : '-' ;	// 歩数

						// トラックポイントを取得してる場合
						$tracks = '' ;

						if( isset( $activity->trackPoints ) )
						{
							// 個々のトラックポイントを取得
							foreach( $activity->trackPoints as $points )
							{
								//緯度・経度・時間(ついでに整形)
								$lat = $points->lat ;
								$lon = $points->lon ;
								$time = date( 'H:i:s' , strtotime($points->time) ) ;

								//変数[$traks]に格納
								$tracks .= '<li>' . $time . ' … ' . $lat . ',' . $lon . '</li>';
							}
						}

						// 出力
						$html .= '<dl>' ;
						$html .= 	'<dt>項目</dt>' ;
						$html .= 		'<dd>' . $value . '</dd>' ;
						$html .= 	'<dt>カテゴリ</dt>' ;
						$html .= 		'<dd>' . $category . '</dd>' ;
						$html .= 	'<dt>時間 (秒数)</dt>' ;
						$html .= 		'<dd>' . $duration . '</dd>' ;
						$html .= 	'<dt>距離 (メートル)</dt>' ;
						$html .= 		'<dd>' . $distance . '</dd>' ;
						$html .= 	'<dt>カロリー</dt>' ;
						$html .= 		'<dd>' . $cal . '</dd>' ;
						$html .= 	'<dt>歩数</dt>' ;
						$html .= 		'<dd>' . $steps . '</dd>' ;

						// トラックポイントがある場合
						if( $tracks )
						{
							$html .= 	'<dt>トラックポイント</dt>' ;
							$html .= 		'<dd><ul>' . $tracks . '</ul></dd>' ;
						}

						$html .= '</dl>' ;
					}
				}
			}
		}
	}

	// 取得したデータ
	$html .= '<h2>取得したデータ</h2>' ;
	$html .= '<p>下記のデータを取得できました。</p>' ;
	$html .= 	'<h3>JSON</h3>' ;
	$html .= 	'<p><textarea rows="8">' . $json . '</textarea></p>' ;
	$html .= 	'<h3>レスポンスヘッダー</h3>' ;
	$html .= 	'<p><textarea rows="8">' . $header . '</textarea></p>' ;

?>

<?php
	// ブラウザに[$html]を出力 (HTMLのヘッダーとフッターを付けましょう)
	echo $html ;
?>

このコードの動作を確認する

項目データの取得 [Activity list]

Movesで設定することができる運動の種類は50項目以上にもなります。これらの運動項目の種類が現在どれだけあるのかを、APIで取得することができます。webサービスを運営している人にとっては、新しく追加された運動項目について把握できるので、便利ですよね。

リクエスト方法

下記のURLにアクセスすることで、運動項目リストを取得することができます。なお、このリクエストには「アクセストークン」は必要ないため、URLアドレスにアクセスすれば、すぐに取得することができます。

GET https://api.moves-app.com/api/1.1/activities

取得できるJSON

このAPIでは、下記のJSONデータを取得できます。50以上の運動項目のデータが配列形式で含まれています。groupは、運動カテゴリに所属している運動項目データにだけ、含まれています。

JSON

[{"activity":"aerobics","geo":false,"place":true,"color":"bc4fff","units":"duration,calories"},{"activity":"badminton","geo":false,"place":true,"color":"11d1cb","units":"duration,calories"},{"activity":"baseball","geo":false,"place":true,"color":"fa7070","units":"duration,calories"},{"activity":"basketball","geo":false,"place":true,"color":"fc6f0a","units":"duration,calories"},{"activity":"beach_volleyball","geo":false,"place":true,"color":"ffb938","units":"duration,calories"},{"activity":"bodypump","geo":false,"place":true,"color":"d1416c","units":"duration,calories"},{"activity":"bowling","geo":false,"place":true,"color":"d68b00","units":"duration,calories"}]

各プロパティの解説

activity
運動の項目。
group
運動カテゴリ。運動カテゴリに所属してないので存在しない場合は含まれない。
geo
トラックポイントの記録に対応しているか。
place
場所内の運動として記録されるか。
color
イメージカラー。
units
記録されるデータ。

公式ドキュメントの確認

運動項目リスト
運動項目リスト

これらのデータは、APIを経由して取得しなくても、公式ドキュメントのページで確認することができます。プログラムに組み込んで何かに利用することがない限り、確認するだけならこちらのページを見た方が早いでしょう。

サンプルプログラム

下記が、運動項目の一覧を取得するサンプルプログラムです。

PHP

<?php

	// 設定項目
	$request_url = 'https://api.moves-app.com/api/1.1/activities' ;	// リクエストURL

	// JSONデータを取得する
	$curl = curl_init() ;
	curl_setopt( $curl , CURLOPT_URL , $request_url ) ;
	curl_setopt( $curl , CURLOPT_HEADER, 1 ) ; 
	curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false ) ;								// 証明書の検証を行わない
	curl_setopt( $curl , CURLOPT_RETURNTRANSFER , true ) ;								// curl_execの結果を文字列で返す
	curl_setopt( $curl , CURLOPT_TIMEOUT , 5 ) ;										// タイムアウトの秒数
	$res1 = curl_exec( $curl ) ;
	$res2 = curl_getinfo( $curl ) ;
	curl_close( $curl ) ;

	// 取得したデータ
	$json = substr( $res1, $res2['header_size'] ) ;										// 取得したデータ(JSONなど)
	$header = substr( $res1, 0, $res2['header_size'] ) ;								// レスポンスヘッダー (検証に利用したい場合にどうぞ)

	// オブジェクトに変換する
	$obj = json_decode( $json ) ;

	// HTML用
	$html = '' ;

	// エラー判定
	if( !$obj )
	{
		$html .= '<p>データを取得できませんでした…。</p>' ;
	}
	else
	{
		// HTML
		$html .= '<h2>実行結果</h2>' ;
		$html .= '<p>下記の内容で取得しました。</p>' ;

		foreach( $obj as $item )
		{
				// 各データの整理
				$activity = $item->activity ;	// 運動項目
				$geo = ( $item->geo ) ? 'true' : 'false' ;	// 位置が関係するか
				$place = ( $item->place ) ? 'true' : 'false' ;	// 場所が関係するか
				$color = $item->color ;	// 色
				$units = $item->units ;	// 含む項目

				// 出力
				$html .= '<dl>' ;
				$html .= 	'<dt>項目</dt>' ;
				$html .= 		'<dd>' . $activity . '</dd>' ;

				// グループ
				if( isset( $item->group ) && !empty( $item->group ) )
				{
					$html .= 	'<dt>グループ</dt>' ;
					$html .= 		'<dd>' . $item->group . '</dd>' ;
				}

				$html .= 	'<dt>位置情報</dt>' ;
				$html .= 		'<dd>' . $geo . '</dd>' ;
				$html .= 	'<dt>場所情報</dt>' ;
				$html .= 		'<dd>' . $place . '</dd>' ;
				$html .= 	'<dt>色</dt>' ;
				$html .= 		'<dd>' . $color . '</dd>' ;
				$html .= 		'<dd><div style="min-height:1em;background:#' . $color . '"></div></dd>' ;
				$html .= 	'<dt>データ</dt>' ;
				$html .= 		'<dd>' . $units . '</dd>' ;
				$html .= '</dl>' ;
		}
	}

	// 取得したデータ
	$html .= '<h2>取得したデータ</h2>' ;
	$html .= '<p>下記のデータを取得できました。</p>' ;
	$html .= 	'<h3>JSON</h3>' ;
	$html .= 	'<p><textarea rows="8">' . $json . '</textarea></p>' ;
	$html .= 	'<h3>レスポンスヘッダー</h3>' ;
	$html .= 	'<p><textarea rows="8">' . $header . '</textarea></p>' ;

?>

<?php
	// ブラウザに[$html]を出力 (HTMLのヘッダーとフッターを付けましょう)
	echo $html ;
?>

このコードの動作を確認する

リアルタイムAPI [Notifications]

Movesでデータが変更されたタイミングで、自分のプログラムにリクエストを送ってもらえるNotificationsについて、説明します。

リアルタイムAPIとは

Moves APIを利用したwebサービスでは、ユーザーのデータを定期的に取得することが多くなると思います。cronを利用して、一定時間ごとにMovesにAPIリクエストを送るのもいいですが、ユーザーが増えてくると、更新がないのにリクエストを送る「空リクエスト」も増えてきちゃいますよね…。それに、過去のデータにも変更がある可能性を考えて、毎回ユーザーの全日数のデータにアクセスするのは大変です。

そんな時に便利な機能があります。Movesの「Notifications」という機能を利用すれば、「ユーザーのMovesデータが更新されたタイミング」で、任意のURLにお知らせを送ってくれます。Web Hookのようなものですねー。この章では、この「Notifications」の使い方を解説します。公式ドキュメントは下記のページにあります。

登録する方法

Notification URLの登録
Notification URLの登録

使い方はとても簡単です。まずは、お知らせを受け取るためのURL(〜.phpなど)を登録します。「アプリケーションの登録」の項で開いた、Developmentタブの画面に、「Notification URL」の入力フォームがあるので、そこにURLを入力して下さい。これだけで、登録は完了です。あなたのアプリを認証しているユーザーの更新通知が、登録したURLに届くようになります。

通知の受け取り方法

ユーザーのデータが更新されると、下記のJSONデータが登録したURLに送られてきます。storylineUpdates内に、更新内容が配列形式で含まれる形です。startTimeendTimeを利用すれば、過去のデータ修正にも簡単に対応できちゃいます。ユーザーIDは、アプリ認証の際に取得できます。

JSON

{
	"userId": 123456789,
	"storylineUpdates": [
		{
			"reason": "DataUpload",
			"startTime": "20121212T072747Z",
			"endTime": "20121212T093247Z",
			"lastSegmentType": "place",
			"lastSegmentStartTime": "20121212T082747Z"
		},
		{
			"reason": "ActivityUpdate",
			"startTime": "20121212T072747Z",
			"endTime": "20121212T073247Z"
		},
		{
			"reason": "PlaceUpdate",
			"startTime": "20121212T082747Z",
			"endTime": "20121212T093247Z"
		},
		{
			"reason": "PlaceRename",
			"placeId": 123456
		}
	]
}

取得できるJSON

各プロパティの説明

userId
ユーザーID。
reason
更新内容。
startTime
セグメントの開始時間。
endTime
セグメントの終了時間。
placeId
場所ID。

「更新内容」について

reasonに含まれる更新内容には、下記の種類が存在します。この更新内容に併せて、プログラムの処理を条件分けするような使い方になりますねー。

DataUpload
ストーリーラインのデータに更新があった。
ActivityUpdate
アクティビティが追加(削除)された。
PlaceUpdate
滞在場所(プレイス)が追加(削除)された。
PlaceRename
滞在場所(プレイス)の名前を変更した。

データの読み取り方法について

ここで少し戸惑ってしまうのですが、このお知らせ(JSON形式のデータ)は通常のリクエスト($_POST["..."]など)のように取得することはできません。「読み込み専用のストリーム」にアクセスして読み込む必要があります。具体的には、次のサンプルプログラムのように取得して下さい。

このプログラムを設置したURLを「Notification URL」に登録すれば、このプログラムがお知らせを受け取り、同一フォルダ内のmemo.txtに、JSON形式の「お知らせの内容」を書き込みます。Movesを少し動かしてから、memo.txtの内容を確認してみて下さい!

PHP

<?php

	// 読み込み専用のストリームにアクセスし、生データを取得
	$json = @file_get_contents( 'php://input' ) ;
 
	// JSONデータをオブジェクト形式に変換
	$obj = json_decode( $json ) ;
 
	// 確認用に[memo.txt]にデータを記録
	@file_put_contents( './memo.txt' , $json ) ;

読み込み専用ストリームのphp://inputに関しては、下記の公式ドキュメントを参考にして下さい。

アクセストークンのリフレッシュ

この章では、アクセストークンの有効期限切れの対策である、リフレッシュトークンの利用方法を説明します。

アクセストークンの有効期限

Moves APIのアクセストークンには、180日間の有効期限があります。そのため、例えばMovesから定期的にデータを取得するプログラムを作成していても、180日後にはアクセストークンが無効になることで、プログラムが機能しなくなってしまいます。

もう1回ユーザーがアプリ認証をすればいいですけど、PINコードの入力なんて面倒ですよね…。これらを防ぐ方法として、「リフレッシュトークン」という機能が提供されています。簡単に言えば、「アクセストークンを新しく更新し、有効期限をリセットする」機能です。

リクエスト方法

リフレッシュするためには、下記のURLにPOSTメソッドでリクエストする必要があります。

POST https://api.moves-app.com/oauth/v1/access_token

パラメータの説明

また、リフレッシュトークンを行なう際は、リクエストURLに下記のパラメータを付与します。アプリ認証の際にアクセストークンと一緒に取得した「リフレッシュトークン」は、ここで利用することになります。

grant_type
refresh_tokenという文字列を指定する。
refresh_token
リフレッシュトークンの値を指定する。
client_id
クライアントID。
client_secret
クライアントシークレット。
scope
パーミッションを変更する場合に指定。

サンプルプログラム

$client_id$client_secret、そしてアプリ認証の時にアクセストークンと一緒に取得していた「リフレッシュトークン」の値を$refresh_tokenにセットしてから、起動して下さい。リフレッシュをすると、現在のアクセストークン、リフレッシュトークンは無効になるのでご注意下さい。

PHP

<?php

	// 設定
	$client_id = '' ;				// クライアントID
	$client_secret = '' ;			// クライアントシークレット
	$refresh_token = '' ;			// リフレッシュトークン
//	$scope = 'activity location' ;	// 権限を変更する場合に指定する

	// リクエスト用のコンテキストを作成
	$context = array(
		'http' => array(
			'method' => 'POST' ,
			'content' => http_build_query( array(
				'grant_type' => 'refresh_token' ,
				"refresh_token" => $refresh_token ,
				'client_id' => $client_id ,
				'client_secret' => $client_secret ,
			) ) ,
		) ,
	) ;

	// スコープが指定されている場合
	if( isset($scope) && !empty($scope) )
	{
		$context['http']['content']['scope'] = $scope ;
	}

	// CURLを使ってリクエスト
	$curl = curl_init() ;

	// オプションのセット
	curl_setopt( $curl , CURLOPT_URL , 'https://api.moves-app.com/oauth/v1/access_token' ) ;
	curl_setopt( $curl , CURLOPT_HEADER, 1 ) ; 
	curl_setopt( $curl , CURLOPT_CUSTOMREQUEST , $context['http']['method'] ) ;			// メソッド
	curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false ) ;								// 証明書の検証を行わない
	curl_setopt( $curl , CURLOPT_RETURNTRANSFER , true ) ;								// curl_execの結果を文字列で返す
	curl_setopt( $curl , CURLOPT_POSTFIELDS , $context['http']['content'] ) ;			// リクエストボディ
	curl_setopt( $curl , CURLOPT_TIMEOUT , 5 ) ;										// タイムアウトの秒数

	// 実行
	$res1 = curl_exec( $curl ) ;
	$res2 = curl_getinfo( $curl ) ;

	// 終了
	curl_close( $curl ) ;

	// 取得したデータ
	$json = substr( $res1, $res2['header_size'] ) ;										// 取得したデータ(JSONなど)
	$header = substr( $res1, 0, $res2['header_size'] ) ;								// レスポンスヘッダー (検証に利用したい場合にどうぞ)

	// オブジェクトに変換
	$obj = json_decode( $json ) ;

	// HTML用
	$html = '' ;

	// エラー判定
	if( !isset($obj->access_token) || !isset($obj->refresh_token) )
	{
		$html .= '<p>トークンを取得できませんでした…。</p>' ;
	}
	else
	{
		// トークン
		$access_token = $obj->access_token ;
		$refresh_token = $obj->refresh_token ;

		// 出力
		$html .= '<dl>' ;
		$html .= 	'<dt>新しいアクセストークン</dt>' ;
		$html .= 		'<dd>' . $access_token . '</dd>' ;
		$html .= 	'<dt>新しいリフレッシュトークン</dt>' ;
		$html .= 		'<dd>' . $refresh_token . '</dd>' ;
		$html .= '</dl>' ;
	}

	// 取得したデータ
	$html .= '<h2>取得したデータ</h2>' ;
	$html .= '<p>下記のデータを取得できました。</p>' ;
	$html .= 	'<h3>JSON</h3>' ;
	$html .= 	'<p><textarea rows="8">' . $json . '</textarea></p>' ;
	$html .= 	'<h3>レスポンスヘッダー</h3>' ;
	$html .= 	'<p><textarea rows="8">' . $header . '</textarea></p>' ;

?>

<?php
	// ブラウザに[$html]を出力 (HTMLのヘッダーとフッターを付けましょう)
	echo $html ;
?>

レートリミット

Moves APIのレートリミットについて説明します。

概要

Moves APIのレートリミットは、2015年9月現在、下記表のように設定されています。

1分あたり
60回
1時間あたり
2,000回

レスポンスヘッダーの内容

通常の使用範囲内であれば、制限を超えることはないと思いますが、現在どれくらいの使用回数が残っているかを調べるには、レスポンスヘッダーの内容を確認・解析します。レスポンスヘッダーの取得方法は様々ですが、例えば、file_get_contents()でリクエストをした後には、自動で$http_response_headerに配列形式で格納されます。

Array
(
	[0] => HTTP/1.1 200 OK
	[1] => Server: nginx
	[2] => Date: Sat, 28 Jun 2014 19:19:32 GMT
	[3] => Content-Type: application/json; charset=utf-8
	[4] => Content-Length: 362
	[5] => Connection: close
	[6] => X-RateLimit-HourRemaining: 1997 
	[7] => Last-Modified: Thu, 26 Jun 2014 15:21:06 GMT
	[8] => Etag: W/"af1cf4b5a9c4d6f8ab5661ef8bea9f29"
	[9] => X-RateLimit-HourLimit: 2000 
	[10] => X-RateLimit-MinuteRemaining: 59 
	[11] => X-RateLimit-MinuteLimit: 60 
)

配列のキー番号、6、9、10、11番にあたる部分をそれぞれ確認すれば、残り使用回数を把握できるというわけですねー。面倒ですが、プログラムにこの数値を組み込むには、例えば下記のように文字列を切り離して数値を得る必要があります。

X-RateLimit-HourRemaining
1時間あたりの残り使用回数。
X-RateLimit-HourLimit
1時間あたりの使用回数上限。
X-RateLimit-MinuteRemaining
1分あたりの残り使用回数。
X-RateLimit-MinuteLimit
1分あたりの使用回数上限。

APIを使ったアイデア

Moves APIを使って、どんなサービスができるのか。色々と考えたものを掲載していきます。これからAPIを利用してサービスなどを作成しようと思っている方のヒントになれば幸いです!

ブログに運動記録を表示

主に運動系のライフログを書いている方は、ブログのサイドバーなどに「今月の運動記録」のような形で、Movesのデータを表示してみてはいかがでしょうか?Moves APIを利用すれば、簡単にできちゃいます。サンプルは今月の、私(あらゆ)の運動記録を表示しています。「ランニング」「サイクリング」をほとんどしていないので、ちょっとかっこ悪いですがご了承下さい(笑)。

PHP

<?php

	// 設定項目
	$request_url = 'https://api.moves-app.com/api/1.1/user/summary/daily/' . date( 'Ym' ) ;	// リクエストURL
	$access_token = '' ;	// アクセストークン

	// リクエストURLにアクセストークンを結合
	$is_param = explode( '?' , $request_url ) ;
	$request_url .= ( ( isset( $is_param[1] ) && !empty( $is_param[1] ) ) ? '&' : '?' ) . 'access_token=' . $access_token ;
   
	// JSONデータを取得する
	$curl = curl_init() ;
	curl_setopt( $curl , CURLOPT_URL , $request_url ) ;
	curl_setopt( $curl , CURLOPT_HEADER, 1 ) ; 
	curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false ) ;								// 証明書の検証を行わない
	curl_setopt( $curl , CURLOPT_RETURNTRANSFER , true ) ;								// curl_execの結果を文字列で返す
	curl_setopt( $curl , CURLOPT_TIMEOUT , 5 ) ;										// タイムアウトの秒数
	$res1 = curl_exec( $curl ) ;
	$res2 = curl_getinfo( $curl ) ;
	curl_close( $curl ) ;

	// 取得したデータ
	$json = substr( $res1, $res2['header_size'] ) ;										// 取得したデータ(JSONなど)
	$header = substr( $res1, 0, $res2['header_size'] ) ;								// レスポンスヘッダー (検証に利用したい場合にどうぞ)

	// オブジェクトに変換する
	$obj = json_decode( $json ) ;

	// 記録用配列の初期値
	$data = array(
		'walking' => array(
			'label' => 'ウォーキング' ,
			'duration' => 0 ,
			'distance' => 0 ,
			'steps' => 0 ,
		) ,
		'running' => array(
			'label' => 'ランニング' ,
			'duration' => 0 ,
			'distance' => 0 ,
			'steps' => 0 ,
		) ,
		'cycling' => array(
			'label' => 'サイクリング' ,
			'duration' => 0 ,
			'distance' => 0 ,
		) ,
	) ;

	// HTML用
	$html = '' ;

	// エラー判定
	if( !$obj )
	{
		$html .= '<p>データを取得できませんでした…。</p>' ;
	}
	else
	{
		// 日ごとの解析
		foreach( $obj as $summary )
		{
			// 内容がなければスキップ
			if( !isset($summary->summary) || empty($summary->summary) )
			{
				continue ;
			}

			// サマリーの解析
			foreach( $summary->summary as $item )
			{
				// 運動カテゴリ
				$group = $item->group ;

				// 歩き、走り、自転車のみ記録
				if( $group == 'transport' )
				{
					continue ;
				}

				// 時間(秒)・距離(メートル)・歩数を合計していく
				$data[ $group ]['duration'] += $item->duration ;
				$data[ $group ]['distance'] += $item->distance ;

				// 歩数がある場合
				if( isset($item->steps) )
				{
					$data[ $group ]['steps'] += $item->steps ;
				}
			}
		}

		// HTMLを作成
		$html .= '<h2>今月(' . date( 'n' ) . '月)の運動記録</h2>' ;

		// 運動項目ごとのデータを出力
		foreach( $data as $item )
		{
			$html .= 	'<h3>' . $item['label'] . '</h3>' ;
			$html .= 	'<dl>' ;
			$html .= 		'<dt>合計時間</dt>' ;
			$html .= 			'<dd>' . $item['duration'] . '秒</dd>' ;
			$html .= 		'<dt>合計距離</dt>' ;
			$html .= 			'<dd>' . $item['distance'] . 'メートル</dd>' ;

			// 歩数がある場合
			if( isset($item['steps']) && !empty($item['steps']) )
			{
				$html .= 		'<dt>合計歩数</dt>' ;
				$html .= 			'<dd>' . $item['steps'] . '歩</dd>' ;
			}

			$html .= 	'</dl>' ;
		}
	}

?>

<?php
	// ブラウザに[$html]を出力 (HTMLのヘッダーとフッターを付けましょう)
	echo $html ;
?>

このコードの動作を確認する

行動記録をGoogle Mapsに描写

StorylineのトラックポイントとGoogle Map APIを組み合わせれば、行動の軌跡をGoogle Maps上にラインで描写することが可能です。自分がどこに行ったのかが分かって、面白いですよー。サンプルデモは、私が2015年7月10日に群馬県をドライブした日のデータです。「神津牧場」で迷子になった様子が分かって面白いです(笑)。

PHP

<?php

	// 設定項目
	$request_url = 'https://api.moves-app.com/api/v1/user/storyline/daily/20150710?trackPoints=true' ;	// リクエストURL
	$access_token = '' ;	// アクセストークン

	// リクエストURLにアクセストークンを結合
	$is_param = explode( '?' , $request_url ) ;
	$request_url .= ( ( isset( $is_param[1] ) && !empty( $is_param[1] ) ) ? '&' : '?' ) . 'access_token=' . $access_token ;
   
	// JSONデータを取得する
	$curl = curl_init() ;
	curl_setopt( $curl , CURLOPT_URL , $request_url ) ;
	curl_setopt( $curl , CURLOPT_HEADER, 1 ) ; 
	curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false ) ;								// 証明書の検証を行わない
	curl_setopt( $curl , CURLOPT_RETURNTRANSFER , true ) ;								// curl_execの結果を文字列で返す
	curl_setopt( $curl , CURLOPT_TIMEOUT , 5 ) ;										// タイムアウトの秒数
	$res1 = curl_exec( $curl ) ;
	$res2 = curl_getinfo( $curl ) ;
	curl_close( $curl ) ;

	// 取得したデータ
	$json = substr( $res1, $res2['header_size'] ) ;										// 取得したデータ(JSONなど)
	$header = substr( $res1, 0, $res2['header_size'] ) ;								// レスポンスヘッダー (検証に利用したい場合にどうぞ)

	// オブジェクトに変換する
	$obj = json_decode( $json ) ;

	// 出力用の変数
	$html = '' ;	// HTML用
	$script = '' ;	// JavaScript用

	// エラー判定
	if( !$obj )
	{
		$html .= '<p>データを取得できませんでした…。</p>' ;
	}
	else
	{
		// 配列
		$points = array() ;

		// 地図キャンパス
		$html .= '<h2>行動地図</h2>' ;
		$html .= '<div style="height:0; width:100%; margin:0; padding-bottom:75%; position:relative; top:0; left:0;">' ;
		$html .= '<div id="map" style="width:100%; height:100%; margin:0; padding:0; position:absolute; top:0; left:0;"></div>' ;
		$html .= '</div>' ;

		// 全てのトラックポイントを取得していく
		foreach( $obj[0]->segments as $segments )
		{
			if( isset( $segments->activities ) )
			{
				foreach( $segments->activities as $activities )
				{
					if( isset( $activities->trackPoints ) )
					{
						foreach( $activities->trackPoints as $trackpoints )
						{
							$points[] = array( 'lat' => $trackpoints->lat , 'lng' => $trackpoints->lon ) ;
						}
					}
				}
			}
		}

		// 位置座標の整理
		$script .= 	'var latlngs = ' . json_encode( $points ) . ' ;' ;
		$script .= 	'var coords = [] ;' ;
		$script .= 	'for( var i=0 , l=latlngs.length ; l > i ; coords.push( new google.maps.LatLng( latlngs[i].lat, latlngs[i].lng ) ) , i++ ){}' ;

		// 地図の出力
		$script .= 	'var map = new google.maps.Map( document.getElementById("map") , { zoom: 10 , mapTypeId: google.maps.MapTypeId.ROADMAP , center: new google.maps.LatLng( ' . $trackpoints->lat . ' , ' . $trackpoints->lon . ' ) } ) ;' ;

		// ポリラインの出力
		$script .= 	'new google.maps.Polyline( { map: map , path: coords , strokeWeight: 5 , strokeColor: "#f00" , strokeOpacity: 0.75 , } ) ;' ;
	}

?>

<?php
	// ブラウザに[$html]を出力 (HTMLのヘッダーとフッターを付けましょう)
	echo $html ;
?>

このコードの動作を確認する

リアルタイム地図

私が真っ先に考えたのが「リアルタイム地図」です。Movesのデータから最新の座標を受け取り、Google Mapsにマーカーを付けて表示するというもの。ユーザーのみんなに、現在自分がいる場所を公開することができます。下記がMovesに記録されている最新の位置情報を取得するサンプルプログラムです。一見、複雑ですが、やっていることは実にシンプルで、「最新の位置座標1つを取り出す」というだけなんです。旅行中だけ限定で公開するなどすれば、配信と同じような楽しみを提供できそうです。

PHP

<?php

	// 設定項目
	$request_url = 'https://api.moves-app.com/api/v1/user/storyline/daily/' . date( 'Ymd' ) . '?trackPoints=true' ;	// リクエストURL
	$access_token = '' ;	// アクセストークン
	$skip_home = 1 ;		// 1=ホームに滞在している時の位置情報を避ける、0=避けない
	$skip_work = 1 ;		// 1=職場に滞在している時の位置情報を避ける、0=避けない
	$skip_school = 1 ;		// 1=学校に滞在している時の位置情報を避ける、0=避けない

	// リクエストURLにアクセストークンを結合
	$is_param = explode( '?' , $request_url ) ;
	$request_url .= ( ( isset( $is_param[1] ) && !empty( $is_param[1] ) ) ? '&' : '?' ) . 'access_token=' . $access_token ;
   
	// JSONデータを取得する
	$curl = curl_init() ;
	curl_setopt( $curl , CURLOPT_URL , $request_url ) ;
	curl_setopt( $curl , CURLOPT_HEADER, 1 ) ; 
	curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false ) ;								// 証明書の検証を行わない
	curl_setopt( $curl , CURLOPT_RETURNTRANSFER , true ) ;								// curl_execの結果を文字列で返す
	curl_setopt( $curl , CURLOPT_TIMEOUT , 5 ) ;										// タイムアウトの秒数
	$res1 = curl_exec( $curl ) ;
	$res2 = curl_getinfo( $curl ) ;
	curl_close( $curl ) ;

	// 取得したデータ
	$json = substr( $res1, $res2['header_size'] ) ;										// 取得したデータ(JSONなど)
	$header = substr( $res1, 0, $res2['header_size'] ) ;								// レスポンスヘッダー (検証に利用したい場合にどうぞ)

	// オブジェクトではなく、配列に変換する
	$array = json_decode( $json , 1 ) ;

	// 出力用の変数
	$html = '' ;	// HTML用

	// エラー判定
	if( !$array )
	{
		$html .= '<h2>実行結果</h2>' ;
		$html .= '<p>データを取得できませんでした…。</p>' ;
	}
	else
	{
		// 見出し
		$html .= '<h2>リアルタイム地図</h2>' ;

		// データがある場合のみ解析処理
		if( isset($array[0]['segments']) && !empty($array[0]['segments']) )
		{
			// ストーリーラインの配列を[昔→今]から[今→昔]に並び替え
			krsort( $array[0]['segments'] ) ;

			// 全てのトラックポイントを取得していく
			foreach( $array[0]['segments'] as $item )
			{
				// 最終時刻の記録
				if( isset($item['endTime']) && !empty($item['endTime']) )
				{
					// 時刻を記録
					$time = $item['endTime'] ;
				}

				// 最新のセグメントが[場所]の場合
				if( $item['type'] == 'place')
				{
					// 自宅、会社、学校の場合はスキップ (有効設定の場合のみ)
					if( ( $item['place']['type'] == 'home' && $skip_home ) || ( $item['place']['type'] == 'work' && $skip_work ) || ( $item['place']['type'] == 'school' && $skip_school ) )
					{
						continue ;
					}

					// 場所の緯度・経度を配列[$geo]に格納
					$geo = array( $item['place']['location']['lat'] , $item['place']['location']['lon'] ) ;
				}

				// 最新のセグメントが[運動]の場合
				elseif( $item['type'] == 'move' || $item['type'] == 'off' )
				{
					// アクティビティの存在を確認
					if( isset( $item['activities'][0] ) )
					{
						// アクティビティの配列を[昔→今]から[今→昔]にする
						krsort( $item['activities'] ) ;

						// トラックポイントの解析
						foreach( $item['activities'] as $activities )
						{
							// トラックポイントの存在を確認
							if( isset( $activities['trackPoints'][0]['lat']) && isset( $activities['trackPoints'][0]['lon']) )
							{
								// トラックポイントの配列を[昔→今]から[今→昔]にする
								krsort( $activities['trackPoints'] ) ;

								// 解析
								foreach( $activities['trackPoints'] as $trackpoints )
								{
									// 最新の緯度・経度を配列[$geo]に格納
									if( isset( $trackpoints['lat'] ) && isset( $trackpoints['lon'] ) )
									{
										$geo = array( $trackpoints['lat'] , $trackpoints['lon'] ) ;
										break ;
									}
								}
							}

							// 最新の緯度・経度が取得できた時点でループ終了
							if( isset( $geo ) )
							{
								break ;
							}
						}
					}

					// 最新の緯度・経度が取得できた時点でループ終了
					if( isset($geo) )
					{
						break ;
					}
				}
			}
		}

		// 位置情報がない場合
		if( !isset( $geo ) || empty( $geo ) || !isset( $time ) || empty( $time ) )
		{
			$html .= '<p>今日はまだ、行動していないみたいです…。</p>' ;
		}

		// 位置情報がある場合
		else
		{
			// 緯度・経度を利用して、Google Static Mapsで地図を表示
			$html .= '<p>' . date( 'Y年n月j日のH時i分' , strtotime( $time ) ) . 'に、下記の位置にいました。</p>' ;
			$html .= '<p><img class="_img" src="http://maps.googleapis.com/maps/api/staticmap?size=640x480&markers=color:red%7C' . $geo[0] . ',' . $geo[1] . '&sensor=false"></p>' ;
		}
	}

?>

<?php
	// ブラウザに[$html]を出力 (HTMLのヘッダーとフッターを付けましょう)
	echo $html ;
?>

このコードの動作を確認する

画像地図について

このように、Movesに記録された最新の場所が、Google Mapsの地図で表示されます。ちなみに、Google Mapsを画像形式で出力できる「Google Static Maps API」の仕様に関しては、下記の公式ドキュメントをご参考下さい!

場所を知らせる地図の効用

例えば、私が大好きな、「猿回しのさくらちゃん」のご主人と猿は、全国各地を回って芸を披露しています。そういった、常に移動をする職業の人がホームページを持ち、このリアルタイム地図を利用してファンに自分の場所を教える、という使い方があってもいいんじゃないでしょうか。

これを応用して、複数人のリアルタイムな位置情報を取得し、ネットでの鬼ごっこ、かくれんぼゲームイベントを行なうのも面白いかもしれません。参加者全員の位置を、地図にマーカーで表示できるので、ツイキャスやニコニコなどの生放送と併せて配信すれば、リスナーも楽しめますよね。

ダウンロード

「すぐにAPIを試したい」という人のために、この記事で紹介してきたサンプルプログラムを配布しています。よろしかったら動作の確認や、カスタマイズの下地としてご利用下さい。解説用になるべく短く書きたいため、エラー判定は必要最低限になっています。

ファイル一覧

SYNCER00055
moves-oauth.php Download
summary.php Download
activities.php Download
places.php Download
storyline.php Download
activity-list.php Download
refresh-token.php Download
moves-idea-01.php Download
moves-idea-02.php Download
moves-idea-03.php Download

ファイル名をクリックすると内容を確認できます。「Download Zip」をクリックするとファイル一式をダウンロードできます。

Download Zip