Ошибки авторизации Google Fit (с ошибками 5005, 5000 и 5015) в WatchFace, WatchConfig и сопутствующем приложении

Я ищу несколько свежих идей об ужасной ошибке 5005: «Код состояния означает, что при попытке получить токен OAuth произошла неизвестная ошибка». когда мой Watch Face пытается подключить Google API, созданный с помощью различных API для фитнеса. Все это работает в моем локальном тестировании И когда я загружаю и запускаю свою RELEASE (бета) версию. Однако, когда мой первый тестер попробовал это, он получает этот код ошибки при попытке подключить API.

ОБНОВЛЕНИЕ 2: Я теперь отследил, что происходит, поэтому я собираюсь перечислить мой окончательный рабочий код здесь и затем рассказать в ответе о том, что я обнаружил.

Есть 3 разных случая, когда я подключаюсь к Google API: Watch Face (таймер рефери:https://play.google.com/store/apps/details?id=com.pipperpublishing.soccerrefpro), связанный Watch Config и сопутствующее приложение на мобильном телефоне (телефон).

Смотреть лицо:

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

Обратите внимание, что я не прошу разрешения WRITE для HISTORY_API. Когда я позже попытаюсь вставить данные о пригодности SPEED и LOCATION в магазине Google Fit, я использую этот код:

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, хотя в действительности я не ссылаюсь на HISTORY_API (или любой фитнес-API) в Config. Тем не менее, пользователь должен зайти в Watch COnfig, чтобы включить мои настройки (KEY_FITNESS_? ниже), который контролирует чтение данных датчика в циферблате.

В заключение,мобильный

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)

Ваш ответ на вопрос