WatchFace,WatchConfig和配套应用中的Google Fit授权错误(包含5005,5000和5015错误)

时间:2016-07-07 20:55:46

标签: android google-play-services google-oauth google-fit google-fit-sdk

我正在寻找关于可怕的5005错误的一些新想法:"状态代码表示在尝试获取OAuth令牌时发生了未知错误。"当我的Watch Face尝试连接使用各种Fitness API构建的Google API时。这一切都适用于我的本地测试和下载并运行我的RELEASE(beta)版本。但是,当我的第一个测试人员试用它时,他在尝试连接API时会收到错误代码。

UPDATE2:我现在已经找到了正在发生的事情,所以我要在这里列出我最后的工作代码,然后在答案中谈谈我发现的内容。

我连接到Google API有3种不同的场合:Watch Face(裁判计时器:https://play.google.com/store/apps/details?id=com.pipperpublishing.soccerrefpro),相关的Watch Config以及Mobile(手机)上的配套应用。

观看脸部

    private GoogleApiClient buildGoogleClient() {
        final GoogleApiClient googleApiClient;
        final GoogleApiClient.Builder googleApiClientBuilder = new GoogleApiClient.Builder(RefWatchFaceService.this);

        //Common components of the GoogleClient
        googleApiClientBuilder
                .addApi(Wearable.API)
                .addApi(Fitness.SESSIONS_API)    //set Session for each period)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .useDefaultAccount();

        if (RefWatchUtil.isRefWatchPro()) {
            googleApiClientBuilder
                    .addApi(Fitness.RECORDING_API)  //records low power information
                    .addApiIfAvailable(Fitness.HISTORY_API
                        ,new Scope(Scopes.FITNESS_ACTIVITY_READ)
                        ,new Scope(Scopes.FITNESS_LOCATION_READ)
                    )
                    .addApiIfAvailable(Fitness.SENSORS_API
                        ,new Scope(Scopes.FITNESS_ACTIVITY_READ)
                        ,new Scope(Scopes.FITNESS_LOCATION_READ)
                    )
                    ;
        }
        googleApiClient = googleApiClientBuilder.build();
        return googleApiClient;
    }

请注意,我并未要求HISTORY_API获得WRITE权限。当我稍后尝试在Google Fit商店中插入SPEED和LOCATION健身数据时,我使用此代码:

private void insertFitnessDataSetBatch(final DataSet batchDataSet) {
    final long batchStartTimeMillis = batchDataSet.getDataPoints().get(0).getTimestamp(TimeUnit.MILLISECONDS);
    final long batchEndTimeMillis;
    long tempEndTimeMillis = batchDataSet.getDataPoints().get(batchDataSet.getDataPoints().size()-1).getTimestamp(TimeUnit.MILLISECONDS);
    //It's possible that this is called with one data point, in which case the Fitness insert will choke on same start and end time
    if (tempEndTimeMillis > batchStartTimeMillis) {
        batchEndTimeMillis = tempEndTimeMillis;
    } else {
        batchEndTimeMillis = batchStartTimeMillis + 1;
    }


    try {
        Fitness.HistoryApi.insertData(mGoogleApiClient, batchDataSet)
                .setResultCallback(new ResultCallback<Status>() {
                    @Override
                    public void onResult(@NonNull Status status) {
                        //Sometimes there is an error but the data was inserted anyway
                        readInsertedFitnessData(batchStartTimeMillis, batchEndTimeMillis, batchDataSet.getDataType());
                        if (!status.isSuccess()) {
                            Log.d(TAG, String.format("Inserting data type %s returned status Code %d (%s)",
                                    batchDataSet.getDataType().getName(), status.getStatusCode(), status.getStatusMessage()));
                        }
                    }
                });
    } catch (RuntimeException e) {
        Log.e(TAG, String.format("There was a runtime exception inserting the data set batch for type %s: %s",
                batchDataSet.getDataType().getName(), e.getLocalizedMessage()));
    }

}

请记住这个回读代码,因为我会在我的回答中引用结果。

观看配置 这里的区别在于Watch Config扩展了FragmentActivity:

private GoogleApiClient buildGoogleClient() {
    final GoogleApiClient googleApiClient;
    final GoogleApiClient.Builder googleApiClientBuilder = new GoogleApiClient.Builder(this);

    //Common components of the GoogleClient
    googleApiClientBuilder
            .addApi(Wearable.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .useDefaultAccount();

    if (RefWatchUtil.isRefWatchPro()) {
        googleApiClientBuilder
                .addApiIfAvailable(Fitness.HISTORY_API
                ,new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE)
                ,new Scope(Scopes.FITNESS_LOCATION_READ_WRITE)
                );
    }
    googleApiClient = googleApiClientBuilder.build();
    return googleApiClient;
}

请注意,我要求READ_WRITE范围,但实际上我并没有在Config中引用HISTORY_API(或任何Fitness Api)。但是,用户必须进入Watch COnfig打开我的设置(下面为KEY_FITNESS_?),该设置控制在Watch Face中读取传感器数据。

最后, 移动

private GoogleApiClient buildGoogleClient() {
    final GoogleApiClient.Builder googleApiClientBuilder;
    googleApiClientBuilder = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApiIfAvailable(Wearable.API); //just in case you are using this without a Wear device
    if (RefWatchUtil.isRefWatchPro()) {
        googleApiClientBuilder
            //.addApiIfAvailable(Fitness.SESSIONS_API)
            .addApiIfAvailable(Fitness.HISTORY_API,    //to read Location and other data per game
                    new Scope(Scopes.FITNESS_ACTIVITY_READ),
                    new Scope(Scopes.FITNESS_LOCATION_READ))
            .useDefaultAccount();
    }
    return googleApiClientBuilder.build();
}

2 个答案:

答案 0 :(得分:1)

我终于得到了谷歌关于useDefaultAccount如何在幕后工作的答案,这会影响上面写的/正在阅读的Fit帐号。这是我提出的问题:

我真的需要回答以下问题,这个问题一直困扰着我的测试。我正在使用Wear表面上的Fitness Apis。我使用&#34; useDefaultAccount&#34;在Google客户端构建器中。但在这种情况下哪个帐户是默认帐户? - 用于下载应用程序的帐户(在这种情况下,从您的开发计算机安装应用程序时使用的帐户) - 它是null / unset - 当您连接时,它是您选择随播应用的帐户。 - 它是在Google健身中选择的当前帐户 - 您无法在Wear faces / apps

中使用useDefaultAccount

Google的回答(感谢Gustavo Moura): 以下是我对逻辑的理解(它没有很好的记录,我们打算在不久的将来清理它): 1.如果有配套应用并且用户已登录Fit并在那里选择了一个帐户,我们会将该帐户同步到Wear设备并使用它。 2.如果没有配套应用(或用户没有登录),但用户已安装并启用了Google健身,并选择了适合的帐户,我们会同步帐户到Wear设备并使用它。 3.如果没有配套应用程序且没有Google Fit,但Wear设备有另一个具有类似行为的内置应用程序(如摩托罗拉手表上的Moto Body),我们将使用该应用程序中的帐户。 4.如果以上都不是真的,那么即使没有帐户,仍然有一些API可以工作(如步数计数器记录和查询)。这一特殊之处在于,在此模式下访问的任何数据都只是手表的本地数据,并且永远不会同步到任何其他设备或服务器。

答案 1 :(得分:0)

以下是我使用上述代码进行测试的结果。首先,我进入了Google帐户页面,确保我的应用程序已从已连接的应用程序中撤销。

如果我启动移动应用程序,我会被要求:

  • 用于Soccer Referee Pro的Google帐户
  • 允许该应用查看位置和活动历史记录
  • 授予“读取日历”权限(在别处使用) 最后当我想显示一个字段覆盖图时:
  • 授予访问权限精确位置权限

然而,在我的测试中我故意没有进入移动应用。相反,当我启动Watch Face时:   - 我被要求授予Access Fine Location权限(我启动Config Activity意图处理此检查/授权)

然后我进入Watch Config设置周期长度并打开我的Fitness系列标志。 Watch Config从不要求任何权限,使用READ_WRITE权限静默成功

当我在表盘上完成数据收集时,我得到以下输出:

? D/RefWatchFace:: Listener registered for data Type com.google.speed
? D/RefWatchFace:: Listener registered for data Type com.google.location.sample
? D/RefWatchFace:: Detected -1 Activity datapoints; inserting 10 (including created ones)
? D/RefWatchFace::  inserting final 10 activity segments (including created ones)
? D/RefWatchFace:: Detected 10 Speed datapoints; inserting in 1 batches
? D/RefWatchFace::  inserting final 10 Speed points (including created ones)
? D/RefWatchFace:: Detected 16 Location datapoints; inserting in 1 batches
? D/RefWatchFace::  inserting final 16 Location points (including created ones)
? D/RefWatchFace:: Checking inserted fitness data for com.google.activity.segment in this batch time 1468440718000-1468441013000
? D/RefWatchFace:: Successfully inserted Session Wed, Jul 13; 1:11PM: Period 1
? D/RefWatchFace:: Checking inserted fitness data for com.google.speed in this batch time 1468440716000-1468440734000
? D/RefWatchFace:: Checking inserted fitness data for com.google.location.sample in this batch time 1468440709575-1468440750000
? D/RefWatchFace:: After insert; read-back found 9 data points for data type com.google.activity.segment
? D/RefWatchFace:: After insert; read-back found 10 data points for data type com.google.speed
? D/RefWatchFace:: After insert; read-back found 16 data points for data type com.google.location.sample

换句话说,我没有被要求授予WRITE权限,但无论如何它都写了。

在我的第二次测试中,我删除了Watch Config应用中的WRITE权限,并重新启用了Watch Face。现在所有插入返回5005(未知错误)状态代码,但实际插入了位置数据(不是速度或活动数据)。

在我的第三次测试中,我将WRITE权限移至Watch Face Google Api代码。在这种情况下,.connect会立即失败并出现5005错误。

结论:在我看来,这里至少有一个安全漏洞,以及不一致的行为和磨损方面的完全无益的错误。