Truy cập API của Google

Khi muốn thực hiện lệnh gọi đến một trong các API trong SDK sử dụng Dịch vụ Google Play (chẳng hạn như tính năng Đăng nhập bằng Google hoặc Bộ công cụ học máy), trước tiên, bạn cần tạo một thực thể của đối tượng ứng dụng API. Các đối tượng này tự động quản lý kết nối với Dịch vụ Google Play. Khi có kết nối, mỗi đối tượng ứng dụng API sẽ thực thi các yêu cầu theo thứ tự. Nếu không, đối tượng ứng dụng sẽ đưa các yêu cầu vào hàng đợi. Trừ phi tài liệu có quy định khác, việc xây dựng các đối tượng ứng dụng khách rất rẻ; bạn có thể tạo các ứng dụng API mới mỗi khi muốn gọi các phương thức API.

Hướng dẫn này trình bày cách thực hiện lệnh gọi API cho bất kỳ SDK nào do Dịch vụ Google Play cung cấp, bao gồm cả cách truy cập vào các dịch vụ không yêu cầu cấp quyền và các dịch vụ yêu cầu cấp phép.

Bắt đầu

Để bắt đầu, hãy thêm các công cụ và phần phụ thuộc cần thiết vào dự án ứng dụng, như mô tả trong hướng dẫn về cách thiết lập Dịch vụ Google Play.

Truy cập khi không cần được cho phép

Để truy cập vào một dịch vụ không yêu cầu uỷ quyền API, hãy lấy một thực thể của đối tượng ứng dụng khách của dịch vụ đó, truyền đối tượng đó vào Context hiện tại hoặc Activity hiện tại. Trước khi thực thi bất kỳ lệnh gọi API nào, người dùng sẽ được nhắc nâng cấp Dịch vụ Google Play nếu cần.

Ví dụ: để lấy thông tin vị trí đã biết gần đây nhất của thiết bị bằng Trình cung cấp vị trí kết hợp cho Android, hãy thêm logic được hiển thị trong đoạn mã sau đây:

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

Truy cập khi cần được uỷ quyền

Để truy cập vào một dịch vụ yêu cầu người dùng cho phép, hãy hoàn tất các bước sau:

  1. Đăng nhập người dùng.
  2. Yêu cầu cấp quyền truy cập vào các phạm vi mà dịch vụ yêu cầu.
  3. Lấy một thực thể của đối tượng ứng dụng của dịch vụ, truyền đối tượng đó vào đối tượng GoogleSignInAccount của người dùng ngoài đối tượng Context hoặc Activity.

Ví dụ sau đây triển khai việc đọc số bước hằng ngày của một người dùng bằng API Google Fit. Để xem cách triển khai tương tự trong bối cảnh của một dự án đầy đủ, hãy xem hoạt động chính của ứng dụng BasicLịch sửApiKotlin trên 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;
}

Kiểm tra xem API có sẵn hay không

Trước khi bật một tính năng trong ứng dụng phụ thuộc vào API của Dịch vụ Google Play, hãy kiểm tra tình trạng sẵn có của API trên thiết bị. Để thực hiện việc này, hãy gọi checkApiAvailability().

Đoạn mã sau đây minh hoạ cách kiểm tra phạm vi cung cấp của trình cung cấp vị trí kết hợp.

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."));
}