الوصول إلى Google APIs

عندما تريد إجراء طلب إلى إحدى واجهات برمجة التطبيقات في حزمة تطوير برامج (SDK) متوافقة مع "خدمات Google Play"، مثل "تسجيل الدخول بحساب Google" أو أدوات تعلُّم الآلة، عليك أولاً إنشاء مثيل لكائن عميل واجهة برمجة التطبيقات. وتدير هذه العناصر الاتصال بخدمات Google Play تلقائيًا. عندما يكون الاتصال متاحًا، يُنفذ كل كائن عميل واجهة برمجة التطبيقات الطلبات بالترتيب. بخلاف ذلك، يضع كائن العميل الطلبات في قائمة الانتظار. ما لم تشير الوثائق إلى خلاف ذلك، تكون كائنات العميل منخفضة التكلفة، ولا بأس في إنشاء عملاء جدد لواجهة برمجة تطبيقات في كل مرة تريد فيها استدعاء طرق واجهة برمجة التطبيقات.

يوضّح هذا الدليل كيفية إجراء طلبات بيانات من واجهة برمجة التطبيقات على أيّ من حِزم تطوير البرامج (SDK) المتوافقة مع "خدمات Google Play"، بما في ذلك كيفية الوصول إلى الخدمات التي لا تتطلب إذنًا وتلك التي تتطلّب تفويضًا.

البدء

للبدء، عليك إضافة الأدوات والتبعيات اللازمة في مشروع تطبيقك، كما هو موضّح في الدليل حول كيفية إعداد خدمات Google Play.

الوصول عندما لا يكون التفويض مطلوبًا

للوصول إلى خدمة لا تتطلب تفويضًا من واجهة برمجة التطبيقات، يمكنك الحصول على مثيل لكائن عميل الخدمة، مع تمرير Context الحالي أو Activity الحالي. قبل تنفيذ أي طلبات بيانات من واجهة برمجة التطبيقات، يُطلب من المستخدمين ترقية خدمات 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.

ينفذ المثال التالي قراءة الخطوات اليومية للمستخدم باستخدام واجهة برمجة تطبيقات Google 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;
}

التحقّق من توفّر واجهة برمجة التطبيقات

قبل تمكين ميزة في تطبيقك تعتمد على واجهة برمجة تطبيقات خدمات Google Play، يجب تضمين التحقق من مدى توفر واجهة برمجة التطبيقات على الجهاز. لإجراء ذلك، يُرجى الاتصال بـ 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."));
}