You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android原生Java应用获取Google Fit授权令牌并传输至后端以获取用户数据的实现方法

Great question—this workflow is totally feasible, and it’s actually the recommended approach for integrating Google Fit with a backend service. Let’s break down exactly how to implement it, step by step.

Is This Workflow Feasible?

Absolutely. Google Fit’s OAuth 2.0 framework is designed to support this exact use case: your Android app handles the user-facing permission flow, obtains a secure authorization code (or short-lived access token), and sends it to your backend. Your backend can then exchange this code for long-term access/refresh tokens to fetch historical fitness data via the Google Fit REST API.

Step 1: Pre-Configuration in Google Cloud Console

First, you’ll need to set up your project and credentials to authenticate with Google’s services:

  • Create a new project (or use an existing one) and enable the Google Fitness API in the API Library.
  • Set up OAuth 2.0 credentials:
    • Create an Android client ID: Enter your app’s package name and SHA-1 fingerprint (you can grab this from Android Studio or via the keytool command). This verifies your app’s identity to Google.
    • Create a Web application client ID: This is critical for your backend—you’ll use it to exchange authorization codes for access/refresh tokens. Save the client ID and client secret securely (never expose the secret in your Android app!).
  • Define the OAuth scopes you need (e.g., https://www.googleapis.com/auth/fitness.activity.read for activity data, https://www.googleapis.com/auth/fitness.body.read for body metrics). Make sure these scopes are listed on your OAuth consent screen, and fill out all required consent details (app name, privacy policy link) since users will see this during authorization.
Step 2: Android App Implementation (Java)

2.1 Add Dependencies

In your app-level build.gradle (module level), add the required Google Play Services libraries:

dependencies {
    implementation 'com.google.android.gms:play-services-fitness:21.0.1'
    implementation 'com.google.android.gms:play-services-auth:20.7.0'
}

2.2 Request Runtime Permissions

For Android 10 (API 29+) and above, permissions like ACTIVITY_RECOGNITION and ACCESS_FINE_LOCATION (if you need location-based fitness data) require dynamic requests. First, add them to your AndroidManifest.xml:

<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Then, check and request these permissions before starting the Fit authorization flow:

private static final int REQUEST_PERMISSIONS = 1001;

private boolean hasRequiredPermissions() {
    return ContextCompat.checkSelfPermission(this, Manifest.permission.ACTIVITY_RECOGNITION) == PackageManager.PERMISSION_GRANTED
            && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}

private void requestMissingPermissions() {
    ActivityCompat.requestPermissions(this,
            new String[]{Manifest.permission.ACTIVITY_RECOGNITION, Manifest.permission.ACCESS_FINE_LOCATION},
            REQUEST_PERMISSIONS);
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_PERMISSIONS) {
        if (hasRequiredPermissions()) {
            startFitAuthorizationFlow();
        } else {
            Toast.makeText(this, "Permissions are required to access Google Fit data", Toast.LENGTH_SHORT).show();
        }
    }
}

2.3 Initiate Google Fit Authorization

Configure the Google Sign-In client with your required scopes, then trigger the authorization flow:

private GoogleSignInClient mSignInClient;
private static final int REQUEST_SIGN_IN = 1002;
private static final String YOUR_WEB_CLIENT_ID = "your-web-client-id-from-cloud-console";

private void initSignInClient() {
    List<String> fitScopes = Arrays.asList(
            Scopes.FITNESS_ACTIVITY_READ,
            Scopes.FITNESS_BODY_READ
            // Add other scopes as needed
    );

    GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestScopes(new Scope(Scopes.FITNESS_ACTIVITY_READ))
            .requestScopes(new Scope(Scopes.FITNESS_BODY_READ))
            .requestServerAuthCode(YOUR_WEB_CLIENT_ID) // Critical for backend token exchange
            .build();

    mSignInClient = GoogleSignIn.getClient(this, gso);
}

private void startFitAuthorizationFlow() {
    Intent signInIntent = mSignInClient.getSignInIntent();
    startActivityForResult(signInIntent, REQUEST_SIGN_IN);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_SIGN_IN) {
        Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
        handleSignInResponse(task);
    }
}

private void handleSignInResponse(Task<GoogleSignInAccount> completedTask) {
    try {
        GoogleSignInAccount account = completedTask.getResult(ApiException.class);
        String authCode = account.getServerAuthCode(); // This is the code to send to your backend

        // Send the auth code to your backend via an API call (use Retrofit, OkHttp, etc.)
        sendAuthCodeToBackend(authCode);

    } catch (ApiException e) {
        Log.w("FitAuth", "Sign-in failed", e);
        Toast.makeText(this, "Google Fit authorization failed. Please try again.", Toast.LENGTH_SHORT).show();
    }
}

// Example: Send auth code to backend with OkHttp
private void sendAuthCodeToBackend(String authCode) {
    OkHttpClient client = new OkHttpClient();
    RequestBody body = new FormBody.Builder()
            .add("auth_code", authCode)
            .build();
    Request request = new Request.Builder()
            .url("https://your-backend-domain.com/api/exchange-fit-token")
            .post(body)
            .build();

    client.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(@NonNull Call call, @NonNull IOException e) {
            Log.e("BackendCall", "Failed to send auth code", e);
        }

        @Override
        public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
            runOnUiThread(() -> {
                if (response.isSuccessful()) {
                    Toast.makeText(MainActivity.this, "Authorization successful!", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(MainActivity.this, "Backend failed to process authorization", Toast.LENGTH_SHORT).show();
                }
            });
        }
    });
}
Step 3: Backend Implementation

Your backend will handle token exchange and Fit API calls. Here’s a high-level breakdown (using Java as an example):

3.1 Exchange Authorization Code for Tokens

Use Google’s OAuth token endpoint to swap the auth code for access/refresh tokens:

private static final String WEB_CLIENT_ID = "your-web-client-id";
private static final String WEB_CLIENT_SECRET = "your-web-client-secret";

public FitTokens exchangeAuthCodeForTokens(String authCode) throws IOException {
    OkHttpClient client = new OkHttpClient();
    RequestBody body = new FormBody.Builder()
            .add("code", authCode)
            .add("client_id", WEB_CLIENT_ID)
            .add("client_secret", WEB_CLIENT_SECRET)
            .add("redirect_uri", "") // Leave empty for server auth code flow
            .add("grant_type", "authorization_code")
            .build();

    Request request = new Request.Builder()
            .url("https://oauth2.googleapis.com/token")
            .post(body)
            .build();

    try (Response response = client.newCall(request).execute()) {
        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
        // Parse response into a POJO (access_token, refresh_token, expires_in)
        return new Gson().fromJson(response.body().string(), FitTokens.class);
    }
}

// Store these tokens securely linked to the user's account (e.g., encrypted database)

3.2 Fetch Historical Fit Data

Use the access token to call the Google Fit REST API. For example, to get daily step counts:

public String getDailyStepCounts(String accessToken, long startTimeMillis, long endTimeMillis) throws IOException {
    OkHttpClient client = new OkHttpClient();
    String aggregateRequest = "{\n" +
            "  \"aggregateBy\": [\n" +
            "    {\n" +
            "      \"dataTypeName\": \"com.google.step_count.delta\",\n" +
            "      \"dataSourceId\": \"derived:com.google.step_count.delta:com.google.android.gms:estimated_steps\"\n" +
            "    }\n" +
            "  ],\n" +
            "  \"bucketByTime\": { \"durationMillis\": 86400000 },\n" +
            "  \"startTimeMillis\": " + startTimeMillis + ",\n" +
            "  \"endTimeMillis\": " + endTimeMillis + "\n" +
            "}";

    Request request = new Request.Builder()
            .url("https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate")
            .addHeader("Authorization", "Bearer " + accessToken)
            .post(RequestBody.create(MediaType.parse("application/json"), aggregateRequest))
            .build();

    try (Response response = client.newCall(request).execute()) {
        if (!response.isSuccessful()) throw new IOException("Fit API call failed");
        return response.body().string();
    }
}

3.3 Refresh Expired Access Tokens

Access tokens expire after ~1 hour. Use the refresh token to get a new one:

public FitTokens refreshAccessToken(String refreshToken) throws IOException {
    OkHttpClient client = new OkHttpClient();
    RequestBody body = new FormBody.Builder()
            .add("refresh_token", refreshToken)
            .add("client_id", WEB_CLIENT_ID)
            .add("client_secret", WEB_CLIENT_SECRET)
            .add("grant_type", "refresh_token")
            .build();

    Request request = new Request.Builder()
            .url("https://oauth2.googleapis.com/token")
            .post(body)
            .build();

    try (Response response = client.newCall(request).execute()) {
        if (!response.isSuccessful()) throw new IOException("Token refresh failed");
        return new Gson().fromJson(response.body().string(), FitTokens.class);
    }
}
Key Best Practices
  • Security: Never hardcode your web client secret in the Android app—keep it strictly on the backend. Using the server auth code flow (instead of getting an access token directly on mobile) avoids exposing sensitive tokens to the client side.
  • Scope Minimalism: Only request the scopes you actually need. Users are more likely to grant access if you don’t ask for unnecessary permissions.
  • Error Handling: Handle cases where users revoke access, tokens expire, or network calls fail. Your backend should detect invalid token errors and trigger a refresh or prompt the user to re-authorize if needed.
  • Privacy Compliance: Follow Google’s API Terms of Service and applicable laws (like GDPR) when handling user fitness data—be transparent about what data you’re collecting and why.

内容的提问来源于stack exchange,提问作者Cosmin Ionuț Cîrlea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 17:08:11