如何在 php 中使用 Google Fit api 获取步数?

Posted

技术标签:

【中文标题】如何在 php 中使用 Google Fit api 获取步数?【英文标题】:How to get steps count with Google Fit api in php ? 【发布时间】:2015-06-26 20:35:54 【问题描述】:

我在使用 Google Api Php ClientGoogle Fit 时遇到问题。

我想得到我一天完成的步数总和

我找到了a response,但它不起作用(看要点)。

我的php代码:

// Retrive oauth data
$clientData = json_decode(file_get_contents("../Devbook-87e2bafd84e6.json")); 
$client_email = $clientData->client_email;
$private_key = $clientData->private_key;
$scopes = array(Google_Service_Fitness::FITNESS_ACTIVITY_READ);
$credentials = new Google_Auth_AssertionCredentials(
     $client_email,
     $scopes,
     $private_key
);

$client = new Google_Client();
$client->setState('offline');
$client->setRedirectUri('urn:ietf:wg:oauth:2.0:oob');  // Used in hybrid flows
$client->setAssertionCredentials($credentials);
if ($client->getAuth()->isAccessTokenExpired()) 
     $client->getAuth()->refreshTokenWithAssertion();


$fitness_service = new Google_Service_Fitness($client);

$dataSources = $fitness_service->users_dataSources;
$dataSets = $fitness_service->users_dataSources_datasets;

$listDataSources = $dataSources->listUsersDataSources("me");

$timezone = "GMT+0100";
$today = date("Y-m-d");
$endTime = strtotime($today.' 00:00:00 '.$timezone);
$startTime = strtotime('-1 day', $endTime);

while($listDataSources->valid()) 
     $dataSourceItem = $listDataSources->next();
     if ($dataSourceItem['dataType']['name'] == "com.google.step_count.delta") 
            $dataStreamId = $dataSourceItem['dataStreamId'];
            $listDatasets = $dataSets->get("me", $dataStreamId, $startTime.'000000000'.'-'.$endTime.'000000000');

            $step_count = 0;
            while($listDatasets->valid()) 
                $dataSet = $listDatasets->next();
                $dataSetValues = $dataSet['value'];

                if ($dataSetValues && is_array($dataSetValues)) 
                   foreach($dataSetValues as $dataSetValue) 
                       $step_count += $dataSetValue['intVal'];
                   
                
            
            print("STEP: ".$step_count."<br />");
     ;
 

这里的问题是它没有进入第一个while循环:$listDataSources-&gt;valid() 返回总是false

我的问题:为什么它返回 false ?我怎样才能获得步骤?

我尝试使用 Oauth Playground (https://www.googleapis.com/fitness/v1/users/me/dataSources/derived:com.google.step_count.delta:com.google.android.gms:estimated_steps) 检索数据,但没有获得任何数据。

我明白了:


    "dataType": 
         "field": [
               "name": "steps", 
               "format": "integer"
         ], 
         "name": "com.google.step_count.delta"
    , 
    "application": 
         "packageName": "com.google.android.gms", 
         "version": ""
    , 
    "dataStreamId": "derived:com.google.step_count.delta:com.google.android.gms:estimated_steps", 
    "type": "derived", 
    "dataStreamName": "estimated_steps"

【问题讨论】:

【参考方案1】:

首先要做的是:您使用的设备上是否有任何数据?我犯了这个错误:尝试从根本没有 Google Fit 数据的帐户获取数据。请不要重复我的错误。

我使用了 与您相同的示例,它对我有用。唯一的区别是我对客户端 API 进行了硬编码,如下所示:

$APIKey = '1231231231231231231231231231123123';
$client_id = '12312312312-dkoasodiajsdaosdjh12h1kjakdahs.apps.googleusercontent.com';
$client_secret = '123123123-1231231-123123123';
$redirect_uri = 'http://localhost/fit/code.php';

您的凭据可能存在问题。 你开始你的会议了吗?在上面的代码后添加session_start()

下面的代码对我有用。适应它,我希望它对你有帮助。

<?php
/*
 * This code is an adaptation of Google API URL Shortener example from Google PHP API github.
 * This was modified to work with Google Fit.
 * This example will count steps from a logged in user.
 */

// I created an Autoloader to load Google API classes
require_once(__DIR__ . '/Autoloader.php');

$APIKey = '1231231231231231231231231231123123';
$client_id = '12312312312-dkoasodiajsdaosdjh12h1kjakdahs.apps.googleusercontent.com';
$client_secret = '123123123-1231231-123123123';
$redirect_uri = 'http://localhost/fit/code.php';

//This template is nothing but some html. You can find it on github Google API example. 
include_once "templates/base.php";

//Start your session.
session_start();

$client = new Google_Client();
$client->setApplicationName('google-fit');
$client->setAccessType('online');
$client->setApprovalPrompt("auto");
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setRedirectUri($redirect_uri);

$client->addScope(Google_Service_Fitness::FITNESS_ACTIVITY_READ);
$service = new Google_Service_Fitness($client);

/************************************************
If we're logging out we just need to clear our
local access token in this case
 ************************************************/
if (isset($_REQUEST['logout'])) 
    unset($_SESSION['access_token']);

/************************************************
If we have a code back from the OAuth 2.0 flow,
we need to exchange that with the authenticate()
function. We store the resultant access token
bundle in the session, and redirect to ourself.
 ************************************************/
if (isset($_GET['code'])) 
    $client->authenticate($_GET['code']);
    $_SESSION['access_token'] = $client->getAccessToken();
    $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
    header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
    echo "EXCHANGE";

/************************************************
If we have an access token, we can make
requests, else we generate an authentication URL.
 ************************************************/
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) 
    $client->setAccessToken($_SESSION['access_token']);
    echo "GOT IT";
    echo "<pre>";

    // Same code as yours
    $dataSources = $service->users_dataSources;
    $dataSets = $service->users_dataSources_datasets;

    $listDataSources = $dataSources->listUsersDataSources("me");

    $timezone = "GMT+0100";
    $today = date("Y-m-d");
    $endTime = strtotime($today.' 00:00:00 '.$timezone);
    $startTime = strtotime('-1 day', $endTime);

    while($listDataSources->valid()) 
        $dataSourceItem = $listDataSources->next();
        if ($dataSourceItem['dataType']['name'] == "com.google.step_count.delta") 
            $dataStreamId = $dataSourceItem['dataStreamId'];
            $listDatasets = $dataSets->get("me", $dataStreamId, $startTime.'000000000'.'-'.$endTime.'000000000');

            $step_count = 0;
            while($listDatasets->valid()) 
                $dataSet = $listDatasets->next();
                $dataSetValues = $dataSet['value'];

                if ($dataSetValues && is_array($dataSetValues)) 
                    foreach($dataSetValues as $dataSetValue) 
                        $step_count += $dataSetValue['intVal'];
                    
                
            
            print("STEP: ".$step_count."<br />");
        ;
    
    echo "</pre>";
 else 
    $authUrl = $client->createAuthUrl();


/************************************************
If we're signed in and have a request to shorten
a URL, then we create a new URL object, set the
unshortened URL, and call the 'insert' method on
the 'url' resource. Note that we re-store the
access_token bundle, just in case anything
changed during the request - the main thing that
might happen here is the access token itself is
refreshed if the application has offline access.
 ************************************************/
if ($client->getAccessToken() && isset($_GET['url'])) 
    $_SESSION['access_token'] = $client->getAccessToken();


//Dumb example. You don't have to use the code below.
echo pageHeader("User Query - URL Shortener");
if (strpos($client_id, "googleusercontent") == false) 
    echo missingClientSecretsWarning();
    exit;

?>
<div class="box">
    <div class="request">
        <?php
        if (isset($authUrl)) 
            echo "<a class='login' href='" . $authUrl . "'>Connect Me!</a>";
         else 
            echo <<<END
    <form id="url" method="GET" action="$_SERVER['PHP_SELF']">
      <input name="url" class="url" type="text">
      <input type="submit" value="Shorten">
    </form>
    <a class='logout' href='?logout'>Logout</a>
END;
        
        ?>
    </div>

    <div class="shortened">
        <?php
        if (isset($short)) 
            var_dump($short);
        
        ?>
    </div>
</div>

【讨论】:

【参考方案2】:

感谢代码,但有错误:

有几个地方调用了 next() 方法,它会跳过循环中的第一项

需要检查项目是否为对象的地方

下面是我的功能。一些要点:

我获取当前和前一天的步数,并将其存储在会话中。我还有一些其他的会话设置。

-$GooglefitCode 全局设置在来自 OAuth 的重定向中,使用 'code' 参数。这里的代码在一个名为 pull.php 的脚本中,回调 URL 是 pull_googlefit.php,它只是将代码存储到 $Googlefit 全局中,并且 PHP 是否包含 pull.php。

如果像之前的代码一样传递 OAuth 代码,我不会执行 header() 重定向。我认为他们这样做是为了从显示的 URL 中删除代码/状态参数。我只是在其他地方使用 javascript 擦除 URL。

请参阅有关在代码中获取步数的评论。谷歌陌生,如果你想匹配他们的应用程序,请使用“estimated_steps”。 "merge_step_deltas" 获取实际步数。

    session_start();
    require 'vendor/autoload.php';
    
    /***************************************************************
    Google Fit Setup
    ****************************************************************/
    $GooglefitClientId = '...';
    $GooglefitClientSecret = '...';
    $GooglefitCallbackURL = '...';
    
    /***************************************************************
    Google Fit Initialization
    ****************************************************************/
    
    if (!isset($_SESSION['googlefit']['pull_retrieved'])) $_SESSION['googlefit']['pull_retrieved'] = 0;
    if (!isset($_SESSION['googlefit']['pull_errors'])) $_SESSION['googlefit']['pull_errors'] = array();
    if (!isset($_SESSION['googlefit']['pull_data'])) $_SESSION['googlefit']['pull_data'] = array();
    if (!$_SESSION['googlefit']['pull_retrieved'] && !$_SESSION['googlefit']['pull_errors'])
    
      GooglefitGet();
    
    
    function GoogleFitGet()
    
      global $GooglefitClientId, $GooglefitClientSecret, $GooglefitCallbackURL, $GooglefitCode;
      // $GooglefitCode is set in pull_googlefit.php, which is the redirect and just includes this file.
      $_SESSION['googlefit']['pull_retrieved'] = 0;
      $_SESSION['googlefit']['pull_errors'] = array();
      $_SESSION['googlefit']['pull_data'] = array();
    
      $client = new Google_Client();
      $client->setApplicationName('google-fit');
      $client->setAccessType('online');
      $client->setApprovalPrompt("auto");
      $client->setClientId($GooglefitClientId);
      $client->setClientSecret($GooglefitClientSecret);
      $client->setRedirectUri($GooglefitCallbackURL);
    
      $client->addScope(Google_Service_Fitness::FITNESS_ACTIVITY_READ);
      $service = new Google_Service_Fitness($client);
      if (isset($GooglefitCode) && ($GooglefitCode != "")) // from pull_googlefit.php
      
          $client->authenticate($GooglefitCode);
          $_SESSION['googlefit']['access_token'] = $client->getAccessToken();
      
      // If we have an access token, we can make requests, else we generate an authentication URL.
      if (isset($_SESSION['googlefit']['access_token']) && $_SESSION['googlefit']['access_token']) 
      
        // There should be a try/catch in here for errors!
        $client->setAccessToken($_SESSION['googlefit']['access_token']);
        $data_sources = $service->users_dataSources;
        $data_sets = $service->users_dataSources_datasets;
        $list_data_sources = $data_sources->listUsersDataSources("me");
        $_SESSION['googlefit']['pull_retrieved'] = 1;
        $_SESSION['googlefit']['pull_errors'] = array();
        date_default_timezone_set('America/New_York');
        $timezone = "";
    
        $ymd = date("Y-m-d");
        $day = "$ymd 00:00:00 $timezone";
        $today_st = strtotime($day);
        $day = "$ymd 23:59:59 $timezone";
        $today_et = strtotime($day);
        $yesterday_st = strtotime("-1 day", $today_st);
        $yesterday_et = strtotime("-1 day", $today_et);
        $ranges = array();
        $ranges[1] = $today_st.'000000000'.'-'.$today_et.'000000000';
        $ranges[0] = $yesterday_st.'000000000'.'-'.$yesterday_et.'000000000';
        $any_list_data_sources = 0;
        while($list_data_sources->valid()) 
        
          if (!$any_list_data_sources)
          
            $any_list_data_sources = 1;
            $data_source_item = $list_data_sources->current();
          
          else
          
            $data_source_item = $list_data_sources->next();
          
          if (!is_object($data_source_item)) continue;
          /* Google strangeness:
              This returns actual steps taken:
                if ($data_source_item['dataStreamName'] != 'merge_step_deltas') continue;
              It is the total from See Source Data on Google Fit app which shows each data point.
              I know because I have added up some tests, including 223 data point day.
              Instead, the Fit app does some additional processing on top of the steps. 
              It estimates steps based on the activity when none are recorded.
              This is the number that it shows you on the app.
          */
          if ($data_source_item['dataStreamName'] != 'estimated_steps') continue; 
          if ($data_source_item['dataType']['name'] == "com.google.step_count.delta") 
          
            $data_stream_id = $data_source_item['dataStreamId'];
            for ($days=0;$days<2;$days++) 
            
              $list_data_sets = $data_sets->get("me", $data_stream_id, $ranges[$days]);
              $step_count = 0;
              $any_list_data_sets = 0;
              while($list_data_sets->valid()) 
              
                if (!$any_list_data_sets) 
                
                   $data_set = $list_data_sets->current();
                   $any_list_data_sets = 1;
                
                else
                                             
                  $data_set = $list_data_sets->next();
                
                if (!is_object($data_set) || !$data_set) continue;
                $data_set_values = $data_set['value'];
                if ($data_set_values && is_array($data_set_values)) 
                
                  foreach($data_set_values as $data_set_value) 
                  
                    $step_count += $data_set_value['intVal'];
                  
                
              
              $str = ($days==0)?"steps_yesterday":"steps_today";
              $_SESSION['googlefit']['pull_data']['steps'][$days]['value'] = $step_count;
            
          
        
       
      else 
      
        $authUrl = $client->createAuthUrl();
        header("Location: $authUrl");
        exit;
      
    

【讨论】:

以上是关于如何在 php 中使用 Google Fit api 获取步数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Android模拟器中安装Google Fit应用?

求助,华为AP 2030DN-S 怎么从fit转换为fat

无线AP的Fat模式和Fit模式有什么区别?

华为Fat AP基本调试以及升级Fit

Google Fit 应用程序如何在不耗尽电池电量的情况下一直测量步数?

商用无线AP FAT模式设置方法