גישה ל-Google APIs

כשרוצים לבצע קריאה לאחד מממשקי ה-API בערכת SDK שמופעלת על ידי Google Play Services, כמו 'כניסה באמצעות חשבון Google' או ML Kit, צריך קודם יוצרים מופע של אובייקט לקוח API. האובייקטים האלה מנהלים אותם באופן אוטומטי החיבור אל Google Play Services. כשהחיבור זמין, כל API אובייקט הלקוח מבצע בקשות לפי הסדר. אחרת, תורי אובייקט הלקוח הבקשות. אלא אם התיעוד מצביע על כך, אובייקטים של לקוח הם זולים לבנות, זה בסדר ליצור לקוחות API חדשים בכל פעם שתרצו להפעיל שיטות API.

במדריך הזה מוסבר איך לבצע קריאות ל-API לכל אחת מערכות ה-SDK שמופעלות על ידי Google Play Services, כולל איך לגשת לשירותים שלא נדרשות הרשאה ו הרשאה.

שנתחיל?

כדי להתחיל, הוסיפו את הכלים ואת יחסי התלות הנדרשים לפרויקט האפליקציה, שמתוארת במדריך להגדרה של Google Play שירותים שונים.

גישה כשלא נדרשת הרשאה

כדי לגשת לשירות שלא דורש הרשאה בממשק API, מקבלים מופע של אובייקט הלקוח של השירות, ומעבירים Context או הנוכחי Activity לפני הרצת קריאות ל-API, המשתמשים יתבקשו לשדרג את Google Play השירותים שלנו, אם יש צורך.

לדוגמה, כדי לקבל את המיקום הידוע האחרון של המכשיר באמצעות המיקום המשולב ספק ל-Android, מוסיפים את הלוגיקה שמוצגת בקטע הקוד הבא:

Kotlin

// Code required for requesting location permissions omitted for brevity.
val client = LocationServices.getFusedLocationProviderClient(this)

// Get the last known location. In some rare situations, this can be null.
client.lastLocation.addOnSuccessListener { location : Location? ->
    location?.let {
        // Logic to handle location object.
    }
}

Java

// Code required for requesting location permissions omitted for brevity.
FusedLocationProviderClient client =
        LocationServices.getFusedLocationProviderClient(this);

// Get the last known location. In some rare situations, this can be null.
client.getLastLocation()
        .addOnSuccessListener(this, location -> {
            if (location != null) {
                // Logic to handle location object.
            }
        });

גישה כשנדרשת הרשאה

כדי לגשת לשירות שמחייב הרשאת משתמש, מבצעים את הפעולות הבאות שלבים:

  1. מזינים את המשתמש לחשבון.
  2. מבקשים הרשאת גישה להיקפי ההרשאות שנדרשים לשירות.
  3. מקבלים מופע של אובייקט הלקוח של השירות ומעבירים אותו GoogleSignInAccount נוסף לאובייקט Context או Activity לאובייקט.

הדוגמה הבאה מממשת את קריאת השלבים היומיים של המשתמש באמצעות ממשק API של Fit. כדי לראות הטמעה דומה בהקשר של פרויקט מלא, להציג את הפעילות העיקרית של BasicHistoryApiKotlin ב-GitHub.

Kotlin

class FitFragment : Fragment() {
    private val fitnessOptions: FitnessOptions by lazy {
        FitnessOptions.builder()
            .addDataType(DataType.TYPE_STEP_COUNT_CUMULATIVE)
            .addDataType(DataType.TYPE_STEP_COUNT_DELTA)
            .build()
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        fitSignIn()
    }

    /*
     * Checks whether the user is signed in. If so, executes the specified
     * function. If the user is not signed in, initiates the sign-in flow,
     * specifying the function to execute after the user signs in.
     */
    private fun fitSignIn() {
        if (oAuthPermissionsApproved()) {
            readDailySteps()
        } else {
            GoogleSignIn.requestPermissions(
                this,
                SIGN_IN_REQUEST_CODE,
                getGoogleAccount(),
                fitnessOptions
            )
        }
    }

    private fun oAuthPermissionsApproved() =
        GoogleSignIn.hasPermissions(getGoogleAccount(), fitnessOptions)

    /*
     * Gets a Google account for use in creating the fitness client. This is
     * achieved by either using the last signed-in account, or if necessary,
     * prompting the user to sign in. It's better to use the
     * getAccountForExtension() method instead of the getLastSignedInAccount()
     * method because the latter can return null if there has been no sign in
     * before.
     */
    private fun getGoogleAccount(): GoogleSignInAccount =
        GoogleSignIn.getAccountForExtension(requireContext(), fitnessOptions)

    /*
     * Handles the callback from the OAuth sign in flow, executing the function
     * after sign-in is complete.
     */
    override fun onActivityResult(
            requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when (resultCode) {
            RESULT_OK -> {
                readDailySteps()
            }
            else -> {
                // Handle error.
            }
        }
    }

    /*
     * Reads the current daily step total.
     */
    private fun readDailySteps() {
        Fitness.getHistoryClient(requireContext(), getGoogleAccount())
            .readDailyTotal(DataType.TYPE_STEP_COUNT_DELTA)
            .addOnSuccessListener { dataSet ->
                val total = when {
                    dataSet.isEmpty -> 0
                    else -> dataSet.dataPoints.first()
                            .getValue(Field.FIELD_STEPS).asInt()
                }

                Log.i(TAG, "Total steps: $total")
            }
            .addOnFailureListener { e ->
                Log.w(TAG, "There was a problem getting the step count.", e)
            }
    }

    companion object {
        const val SIGN_IN_REQUEST_CODE = 1001
    }
}

Java

public class FitFragment extends Fragment {
    private final FitnessOptions fitnessOptions = FitnessOptions.builder()
            .addDataType(DataType.TYPE_STEP_COUNT_CUMULATIVE)
            .addDataType(DataType.TYPE_STEP_COUNT_DELTA)
            .build();

    @Override
    public void onViewCreated(
            @NotNull View view, @Nullable Bundle savedInstanceState) {
        fitSignIn();
    }

    /*
     * Checks whether the user is signed in. If so, executes the specified
     * function. If the user is not signed in, initiates the sign-in flow,
     * specifying the function to execute after the user signs in.
     */
    private void fitSignIn() {
        if (oAuthPermissionsApproved()) {
            readDailySteps();
        } else {
            GoogleSignIn.requestPermissions(this, SIGN_IN_REQUEST_CODE,
                    getGoogleAccount(), fitnessOptions);
        }
    }

    private boolean oAuthPermissionsApproved() {
        return GoogleSignIn.hasPermissions(getGoogleAccount(), fitnessOptions);
    }

    /*
     * Gets a Google account for use in creating the fitness client. This is
     * achieved by either using the last signed-in account, or if necessary,
     * prompting the user to sign in. It's better to use the
     * getAccountForExtension() method instead of the getLastSignedInAccount()
     * method because the latter can return null if there has been no sign in
     * before.
     */
    private GoogleSignInAccount getGoogleAccount() {
        return GoogleSignIn.getAccountForExtension(
                requireContext(), fitnessOptions);
    }

    /*
     * Handles the callback from the OAuth sign in flow, executing the function
     * after sign-in is complete.
     */
    @Override
    public void onActivityResult(
            int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            readDailySteps();
        } else {
            // Handle error.
        }
    }

    /*
     * Reads the current daily step total.
     */
    private void readDailySteps() {
        AtomicInteger total = new AtomicInteger();
        Fitness.getHistoryClient(requireContext(), getGoogleAccount())
                .readDailyTotal(DataType.TYPE_STEP_COUNT_DELTA)
                .addOnSuccessListener(dataSet -> {
                    if (!dataSet.isEmpty())
                        total.set(Integer.parseInt(dataSet.getDataPoints()
                                .get(0).getValue(FIELD_STEPS).toString()));
                        Log.i(TAG, "Total steps: $total");
                })
                .addOnFailureListener(e -> {
                    Log.w(TAG, "There was a problem getting the step count.", e);
                });
    }

    private static final int SIGN_IN_REQUEST_CODE = 1001;
}

בדיקת הזמינות של ה-API

לפני שמפעילים באפליקציה תכונה שתלויה ב-Google Play Services API, צריך לכלול בדיקה של זמינות ה-API במכשיר. כדי לעשות את זה, קוראים לפונקציה checkApiAvailability().

קטע הקוד הבא מדגים איך בודקים את הזמינות של ספק מיקום משולב

Kotlin

fun getLastLocationIfApiAvailable(context: Context?): Task<Location>? {
    val client = getFusedLocationProviderClient(context)
    return GoogleApiAvailability.getInstance()
        .checkApiAvailability(client)
        .onSuccessTask { _ -> client.lastLocation }
        .addOnFailureListener { _ -> Log.d(TAG, "Location unavailable.")}
}

Java

public Task<Location> getLastLocationIfApiAvailable(Context context) {
    FusedLocationProviderClient client =
            getFusedLocationProviderClient(context);
    return GoogleApiAvailability.getInstance()
            .checkApiAvailability(client)
            .onSuccessTask(unused -> client.getLastLocation())
            .addOnFailureListener(e -> Log.d(TAG, "Location unavailable."));
}