دسترسی به APIهای Google با GoogleApiClient (منسوخ شده)

می‌توانید از شی GoogleApiClient ("Google API Client") برای دسترسی به APIهای Google ارائه شده در کتابخانه خدمات Google Play (مانند Google Sign-In، Games و Drive) استفاده کنید. Google API Client یک نقطه ورودی مشترک به خدمات Google Play ارائه می دهد و اتصال شبکه بین دستگاه کاربر و هر سرویس Google را مدیریت می کند.

با این حال، رابط کاربری جدیدتر GoogleApi و پیاده‌سازی‌های آن آسان‌تر برای استفاده هستند و راه ارجح برای دسترسی به API‌های خدمات Play هستند. دسترسی به APIهای Google را ببینید.

این راهنما نشان می دهد که چگونه می توانید:

  • اتصال خود به خدمات Google Play را به صورت خودکار مدیریت کنید.
  • تماس‌های API همزمان و ناهمزمان را با هر یک از سرویس‌های Google Play انجام دهید.
  • در موارد نادری که این امر ضروری است، اتصال خود به خدمات Google Play را به صورت دستی مدیریت کنید. برای کسب اطلاعات بیشتر، به اتصالات مدیریت شده دستی مراجعه کنید.
شکل 1: تصویری که نشان می‌دهد چگونه Google API Client یک رابط برای اتصال و برقراری تماس با هر یک از سرویس‌های موجود Google Play مانند Google Play Games و Google Drive فراهم می‌کند.

برای شروع، ابتدا باید کتابخانه خدمات Google Play (نسخه 15 یا بالاتر) را برای Android SDK خود نصب کنید. اگر قبلاً این کار را انجام نداده‌اید، دستورالعمل‌های موجود در «راه‌اندازی Google Play Services SDK» را دنبال کنید.

یک اتصال مدیریت شده خودکار را شروع کنید

پس از اینکه پروژه شما به کتابخانه خدمات Google Play مرتبط شد، یک نمونه از GoogleApiClient با استفاده از APIهای GoogleApiClient.Builder در روش onCreate() فعالیت خود ایجاد کنید. کلاس GoogleApiClient.Builder روش هایی را ارائه می دهد که به شما امکان می دهد API های Google را که می خواهید استفاده کنید و دامنه های OAuth 2.0 مورد نظر خود را مشخص کنید. در اینجا یک نمونه کد است که یک نمونه GoogleApiClient ایجاد می کند که با سرویس Google Drive متصل می شود:

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
    .enableAutoManage(this /* FragmentActivity */,
                      this /* OnConnectionFailedListener */)
    .addApi(Drive.API)
    .addScope(Drive.SCOPE_FILE)
    .build();

می‌توانید با افزودن فراخوان‌های اضافی به addApi() و addScope() چند API و چندین دامنه به یک GoogleApiClient اضافه کنید.

مهم: اگر Wearable API را به همراه سایر APIها به GoogleApiClient اضافه می‌کنید، ممکن است در دستگاه‌هایی که برنامه Wear OS را نصب نکرده‌اند، با خطاهای اتصال کلاینت مواجه شوید. برای جلوگیری از خطاهای اتصال، متد addApiIfAvailable() را فراخوانی کنید و از Wearable API عبور دهید تا به مشتری شما اجازه دهید تا API گم شده را به خوبی مدیریت کند. برای اطلاعات بیشتر، به دسترسی به Wearable API مراجعه کنید.

برای شروع یک اتصال مدیریت شده به طور خودکار، باید یک پیاده سازی برای رابط OnConnectionFailedListener تعیین کنید تا خطاهای اتصال غیرقابل حل را دریافت کنید. هنگامی که نمونه GoogleApiClient مدیریت خودکار شما تلاش می‌کند به APIهای Google متصل شود، به‌طور خودکار رابط کاربری را نمایش می‌دهد تا هرگونه نقص اتصال قابل حل را برطرف کند (مثلاً اگر خدمات Google Play نیاز به به‌روزرسانی داشته باشد). اگر خطایی رخ دهد که قابل حل نباشد، یک تماس با onConnectionFailed() دریافت خواهید کرد.

همچنین اگر برنامه شما نیاز دارد بداند که اتصال مدیریت شده به طور خودکار چه زمانی برقرار شده یا به حالت تعلیق درآمده است، می‌توانید یک پیاده‌سازی اختیاری برای رابط ConnectionCallbacks تعیین کنید. به عنوان مثال، اگر برنامه شما برای نوشتن داده‌ها در Google API تماس می‌گیرد، آن‌ها باید تنها پس از فراخوانی متد onConnected() فراخوانی شوند.

در اینجا یک نمونه فعالیت است که واسط های پاسخ به تماس را پیاده سازی کرده و آنها را به Google API Client اضافه می کند:

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import gms.drive.*;
import android.support.v4.app.FragmentActivity;

public class MyActivity extends FragmentActivity
        implements OnConnectionFailedListener {
    private GoogleApiClient mGoogleApiClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Create a GoogleApiClient instance
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this /* FragmentActivity */,
                                  this /* OnConnectionFailedListener */)
                .addApi(Drive.API)
                .addScope(Drive.SCOPE_FILE)
                .build();

        // ...
    }

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        // An unresolvable error has occurred and a connection to Google APIs
        // could not be established. Display an error message, or handle
        // the failure silently

        // ...
    }
}

نمونه GoogleApiClient شما به طور خودکار پس از فراخوانی فعالیت شما onStart() متصل می شود و پس از تماس onStop() قطع می شود. برنامه شما می‌تواند بلافاصله پس از ساخت GoogleApiClient ، بدون منتظر ماندن برای تکمیل اتصال، درخواست‌های خواندن را برای APIهای Google ارسال کند.

با Google Services ارتباط برقرار کنید

پس از اتصال، مشتری شما می‌تواند با استفاده از APIهای مخصوص سرویسی که برنامه شما برای آنها مجاز است، تماس‌های خواندن و نوشتن برقرار کند، همانطور که توسط APIها و محدوده‌هایی که به نمونه GoogleApiClient خود اضافه کرده‌اید مشخص شده‌اند.

توجه: قبل از برقراری تماس با سرویس‌های خاص Google، ممکن است لازم باشد ابتدا برنامه خود را در کنسول برنامه‌نویس Google ثبت کنید. برای دستورالعمل‌ها، به راهنمای شروع مناسب برای API که استفاده می‌کنید، مانند Google Drive یا Google Sign-In مراجعه کنید.

هنگامی که درخواست خواندن یا نوشتن را با استفاده از GoogleApiClient انجام می دهید، سرویس گیرنده API یک شی PendingResult برمی گرداند که نشان دهنده درخواست است. این بلافاصله قبل از تحویل درخواست به سرویس Google که برنامه شما با آن تماس می‌گیرد، اتفاق می‌افتد.

به عنوان مثال، در اینجا یک درخواست برای خواندن یک فایل از Google Drive است که یک شی PendingResult ارائه می دهد:

Query query = new Query.Builder()
        .addFilter(Filters.eq(SearchableField.TITLE, filename));
PendingResult<DriveApi.MetadataBufferResult> result = Drive.DriveApi.query(mGoogleApiClient, query);

پس از اینکه برنامه شما دارای یک شی PendingResult شد، برنامه شما می‌تواند تعیین کند که آیا درخواست به عنوان تماس ناهمزمان یا همزمان انجام می‌شود.

نکته: برنامه شما می‌تواند درخواست‌های خواندن را در حالی که به خدمات Google Play متصل نیست، در نوبت قرار دهد. برای مثال، برنامه شما می‌تواند روش‌هایی را برای خواندن یک فایل از Google Drive فراخوانی کند، صرفنظر از اینکه نمونه GoogleApiClient شما هنوز متصل است یا خیر. پس از برقراری ارتباط، درخواست‌های خواندن در صف اجرا می‌شوند. اگر برنامه شما با سرویس‌های Google Play با روش‌های نوشتن تماس بگیرد در حالی که Google API Client متصل نیست، درخواست‌های نوشتن خطا ایجاد می‌کنند.

استفاده از تماس های ناهمزمان

برای ناهمزمان کردن درخواست، setResultCallback() را در PendingResult فراخوانی کنید و یک پیاده سازی از رابط ResultCallback ارائه دهید. به عنوان مثال، این درخواست به صورت ناهمزمان اجرا شده است:

private void loadFile(String filename) {
    // Create a query for a specific filename in Drive.
    Query query = new Query.Builder()
            .addFilter(Filters.eq(SearchableField.TITLE, filename))
            .build();
    // Invoke the query asynchronously with a callback method
    Drive.DriveApi.query(mGoogleApiClient, query)
            .setResultCallback(new ResultCallback<DriveApi.MetadataBufferResult>() {
        @Override
        public void onResult(DriveApi.MetadataBufferResult result) {
            // Success! Handle the query result.
            // ...
        }
    });
}

هنگامی که برنامه شما یک شی Result در پاسخ به تماس onResult() دریافت می کند، به عنوان نمونه ای از زیر کلاس مناسب که توسط API مورد استفاده شما مشخص شده است، مانند DriveApi.MetadataBufferResult ، تحویل داده می شود.

استفاده از تماس های همزمان

اگر می‌خواهید کد شما با یک ترتیب کاملاً تعریف شده اجرا شود، شاید به این دلیل که نتیجه یک فراخوانی به عنوان آرگومان دیگری مورد نیاز است، می‌توانید با فراخوانی await() در PendingResult درخواست خود را همزمان کنید. این موضوع رشته را مسدود می کند و پس از تکمیل درخواست، شی Result برمی گرداند. این شی به عنوان نمونه ای از زیر کلاس مناسب که توسط API مورد استفاده شما مشخص شده است، برای مثال DriveApi.MetadataBufferResult تحویل داده می شود.

از آنجایی که فراخوانی await() تا رسیدن به نتیجه، رشته را مسدود می‌کند، برنامه شما هرگز نباید درخواست‌های همزمان به APIهای Google در رشته UI ارسال کند. برنامه شما می تواند با استفاده از یک شی AsyncTask یک رشته جدید ایجاد کند و از آن رشته برای ایجاد درخواست همزمان استفاده کند.

مثال زیر نحوه درخواست فایل به Google Drive را به صورت تماس همزمان نشان می دهد:

private void loadFile(String filename) {
    new GetFileTask().execute(filename);
}

private class GetFileTask extends AsyncTask<String, Void, Void> {
    protected void doInBackground(String filename) {
        Query query = new Query.Builder()
                .addFilter(Filters.eq(SearchableField.TITLE, filename))
                .build();
        // Invoke the query synchronously
        DriveApi.MetadataBufferResult result =
                Drive.DriveApi.query(mGoogleApiClient, query).await();

        // Continue doing other stuff synchronously
        // ...
    }
}

به Wearable API دسترسی پیدا کنید

Wearable API یک کانال ارتباطی برای برنامه‌هایی که روی دستگاه‌های دستی و پوشیدنی اجرا می‌شوند، فراهم می‌کند. API شامل مجموعه‌ای از اشیاء داده‌ای است که سیستم می‌تواند ارسال و همگام‌سازی کند، و شنوندگانی که برنامه‌های شما را از رویدادهای مهم با استفاده از یک لایه داده مطلع می‌کنند. Wearable API در دستگاه‌های دارای Android نسخه 4.3 (سطح API 18) یا بالاتر، زمانی که دستگاه پوشیدنی متصل است و برنامه همراه Wear OS روی دستگاه نصب شده است، در دسترس است.

استفاده از Wearable API به تنهایی

اگر برنامه شما از Wearable API استفاده می کند اما از سایر API های Google استفاده نمی کند، می توانید با فراخوانی متد addApi() این API را اضافه کنید. مثال زیر نحوه اضافه کردن Wearable API را به نمونه GoogleApiClient خود نشان می دهد:

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
    .enableAutoManage(this /* FragmentActivity */,
                      this /* OnConnectionFailedListener */)
    .addApi(Wearable.API)
    .build();

در شرایطی که Wearable API در دسترس نیست، درخواست‌های اتصال که شامل Wearable API هستند با کد خطای API_UNAVAILABLE ناموفق می‌شوند.

مثال زیر نشان می دهد که چگونه می توان تشخیص داد که آیا Wearable API موجود است یا خیر:

// Connection failed listener method for a client that only
// requests access to the Wearable API
@Override
public void onConnectionFailed(ConnectionResult result) {
    if (result.getErrorCode() == ConnectionResult.API_UNAVAILABLE) {
        // The Wearable API is unavailable
    }
    // ...
}

استفاده از Wearable API با سایر APIهای Google

اگر برنامه شما از Wearable API علاوه بر سایر API های Google استفاده می کند، متد addApiIfAvailable() را فراخوانی کنید و برای بررسی در دسترس بودن آن Wearable API را ارسال کنید. می‌توانید از این بررسی برای کمک به برنامه‌تان برای رسیدگی به مواردی که API در دسترس نیست، استفاده کنید.

مثال زیر نحوه دسترسی به Wearable API همراه با Drive API را نشان می دهد:

// Create a GoogleApiClient instance
mGoogleApiClient = new GoogleApiClient.Builder(this)
        .enableAutoManage(this /* FragmentActivity */,
                          this /* OnConnectionFailedListener */)
        .addApi(Drive.API)
        .addApiIfAvailable(Wearable.API)
        .addScope(Drive.SCOPE_FILE)
        .build();

در مثال بالا، GoogleApiClient می‌تواند بدون اتصال به Wearable API با موفقیت به Google Drive متصل شود، اگر در دسترس نباشد. پس از اتصال نمونه GoogleApiClient خود، قبل از برقراری تماس‌های API مطمئن شوید که Wearable API در دسترس است:

boolean wearAvailable = mGoogleApiClient.hasConnectedApi(Wearable.API);

نادیده گرفتن خطاهای اتصال API

اگر با addApi() تماس بگیرید و GoogleApiClient نتواند با موفقیت به آن API متصل شود، کل عملیات اتصال برای آن کلاینت با شکست مواجه می‌شود و پاسخ تماس onConnectionFailed() را راه‌اندازی می‌کند.

با استفاده از addApiIfAvailable() می توانید یک شکست اتصال API را ثبت کنید تا نادیده گرفته شود. اگر یک API اضافه شده با addApiIfAvailable() به دلیل خطای غیرقابل بازیابی (مانند API_UNAVAILABLE برای Wear) متصل نشود، آن API از GoogleApiClient شما حذف می‌شود و کلاینت به اتصال به APIهای دیگر ادامه می‌دهد. با این حال، اگر هر یک از اتصال API با یک خطای قابل بازیابی (مانند هدف قطعنامه رضایت OAuth) با شکست مواجه شود، عملیات اتصال کلاینت با شکست مواجه می شود. هنگام استفاده از یک اتصال مدیریت شده به طور خودکار، GoogleApiClient تلاش می کند تا در صورت امکان چنین خطاهایی را برطرف کند. هنگام استفاده از یک اتصال مدیریت شده دستی، یک ConnectionResult حاوی یک هدف رزولوشن به پاسخ تماس onConnectionFailed() تحویل داده می شود. خرابی‌های اتصال API تنها در صورتی نادیده گرفته می‌شوند که هیچ قطعنامه‌ای برای خرابی وجود نداشته باشد و API با addApiIfAvailable() اضافه شده باشد. برای آشنایی با نحوه اجرای مدیریت شکست اتصال دستی، به رسیدگی به خرابی های اتصال مراجعه کنید.

از آنجایی که APIهای اضافه شده با addApiIfAvailable() ممکن است همیشه در نمونه GoogleApiClient متصل وجود نداشته باشند، باید با افزودن چک با استفاده از hasConnectedApi() از تماس‌های این APIها محافظت کنید. برای اینکه بفهمید چرا یک API خاص در زمانی که کل عملیات اتصال برای کلاینت موفقیت آمیز بود، متصل نشد، getConnectionResult() را فراخوانی کنید و کد خطا را از شی ConnectionResult دریافت کنید. اگر سرویس گیرنده شما با یک API تماس بگیرد زمانی که به مشتری متصل نیست، تماس با کد وضعیت API_NOT_AVAILABLE انجام نمی شود.

اگر API که از طریق addApiIfAvailable() اضافه می کنید به یک یا چند محدوده نیاز دارد، به جای استفاده از متد addScope addApiIfAvailable() addScope() خود اضافه کنید. اگر اتصال API قبل از دریافت رضایت OAuth از کار بیفتد، ممکن است دامنه‌های اضافه‌شده با این رویکرد درخواست نشود، در حالی که دامنه‌هایی که با addScope() اضافه می‌شوند همیشه درخواست می‌شوند.

اتصالات مدیریت شده به صورت دستی

اکثر این راهنما به شما نشان می دهد که چگونه از روش enableAutoManage برای شروع یک اتصال مدیریت شده خودکار با خطاهای حل شده خودکار استفاده کنید. تقریباً در همه موارد، این بهترین و ساده‌ترین راه برای اتصال به Google API از برنامه Android شما است. با این حال، شرایطی وجود دارد که می‌خواهید از یک اتصال مدیریت شده دستی به Google API در برنامه خود استفاده کنید:

  • برای دسترسی به APIهای Google خارج از یک فعالیت یا حفظ کنترل اتصال API
  • برای سفارشی کردن رسیدگی و حل خطای اتصال

این بخش نمونه هایی از این موارد و سایر موارد استفاده پیشرفته را ارائه می دهد.

یک اتصال مدیریت شده دستی را شروع کنید

برای راه‌اندازی یک اتصال مدیریت‌شده دستی به GoogleApiClient ، باید یک پیاده‌سازی برای رابط‌های پاسخ به تماس، ConnectionCallbacks و OnConnectionFailedListener مشخص کنید. هنگامی که اتصال به سرویس‌های Google Play موفقیت آمیز، شکست یا تعلیق می‌شود، این واسط‌ها در پاسخ به روش ناهمزمان connect() تماس دریافت می‌کنند.

    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addApi(Drive.API)
            .addScope(Drive.SCOPE_FILE)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build()

هنگام مدیریت یک اتصال به صورت دستی، باید متدهای connect() و disconnect() در نقاط مناسب در چرخه عمر برنامه خود فراخوانی کنید. در زمینه فعالیت، بهترین روش فراخوانی connect() در متد onStart() اکتیویتی و disconnect() در متد onStop() اکتیویتی است. متدهای connect() و disconnect() به طور خودکار هنگام استفاده از یک اتصال مدیریت شده خودکار فراخوانی می شوند.

اگر از GoogleApiClient برای اتصال به APIهایی که نیاز به احراز هویت دارند، مانند Google Drive یا Google Play Games استفاده می‌کنید، احتمال زیادی وجود دارد که اولین تلاش شما برای اتصال ناموفق باشد و برنامه شما با خطای onConnectionFailed() با خطای SIGN_IN_REQUIRED تماس بگیرد.

رفع خرابی های اتصال

هنگامی که برنامه شما تماسی با پاسخ تماس onConnectionFailed() دریافت می کند، باید hasResolution() در شی ConnectionResult ارائه شده فراخوانی کنید. اگر مقدار true را برگرداند، برنامه شما می‌تواند با فراخوانی startResolutionForResult() در شی ConnectionResult از کاربر درخواست کند که برای رفع خطا اقدام فوری انجام دهد. متد startResolutionForResult() در این شرایط مانند startActivityForResult() عمل می‌کند و یک اکتیویتی مناسب با زمینه راه‌اندازی می‌کند که به کاربر در رفع خطا کمک می‌کند (مانند فعالیتی که به کاربر در انتخاب حساب کمک می‌کند).

اگر hasResolution() false برگرداند، برنامه شما باید GoogleApiAvailability.getErrorDialog() را فراخوانی کند و کد خطا را به این روش ارسال کند. این یک Dialog ارائه شده توسط سرویس‌های Google Play را برمی‌گرداند که متناسب با خطا است. گفتگو ممکن است به سادگی پیامی را ارائه دهد که خطا را توضیح می دهد، یا همچنین ممکن است اقدامی برای راه اندازی فعالیتی ارائه دهد که می تواند خطا را برطرف کند (مانند زمانی که کاربر نیاز به نصب نسخه جدیدتری از خدمات Google Play دارد).

برای مثال، متد callback onConnectionFailed() شما اکنون باید به شکل زیر باشد:

public class MyActivity extends Activity
        implements ConnectionCallbacks, OnConnectionFailedListener {

    // Request code to use when launching the resolution activity
    private static final int REQUEST_RESOLVE_ERROR = 1001;
    // Unique tag for the error dialog fragment
    private static final String DIALOG_ERROR = "dialog_error";
    // Bool to track whether the app is already resolving an error
    private boolean mResolvingError = false;

    // ...

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        if (mResolvingError) {
            // Already attempting to resolve an error.
            return;
        } else if (result.hasResolution()) {
            try {
                mResolvingError = true;
                result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
            } catch (SendIntentException e) {
                // There was an error with the resolution intent. Try again.
                mGoogleApiClient.connect();
            }
        } else {
            // Show dialog using GoogleApiAvailability.getErrorDialog()
            showErrorDialog(result.getErrorCode());
            mResolvingError = true;
        }
    }

    // The rest of this code is all about building the error dialog

    /* Creates a dialog for an error message */
    private void showErrorDialog(int errorCode) {
        // Create a fragment for the error dialog
        ErrorDialogFragment dialogFragment = new ErrorDialogFragment();
        // Pass the error that should be displayed
        Bundle args = new Bundle();
        args.putInt(DIALOG_ERROR, errorCode);
        dialogFragment.setArguments(args);
        dialogFragment.show(getSupportFragmentManager(), "errordialog");
    }

    /* Called from ErrorDialogFragment when the dialog is dismissed. */
    public void onDialogDismissed() {
        mResolvingError = false;
    }

    /* A fragment to display an error dialog */
    public static class ErrorDialogFragment extends DialogFragment {
        public ErrorDialogFragment() { }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            // Get the error code and retrieve the appropriate dialog
            int errorCode = this.getArguments().getInt(DIALOG_ERROR);
            return GoogleApiAvailability.getInstance().getErrorDialog(
                    this.getActivity(), errorCode, REQUEST_RESOLVE_ERROR);
        }

        @Override
        public void onDismiss(DialogInterface dialog) {
            ((MyActivity) getActivity()).onDialogDismissed();
        }
    }
}

پس از اینکه کاربر گفتگوی ارائه شده توسط startResolutionForResult() را تکمیل کرد یا پیام ارائه شده توسط GoogleApiAvailability.getErrorDialog() را رد کرد، فعالیت شما پاسخ تماس onActivityResult() را با کد نتیجه RESULT_OK دریافت می کند. سپس برنامه شما می تواند دوباره connect() فراخوانی کند. به عنوان مثال:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_RESOLVE_ERROR) {
        mResolvingError = false;
        if (resultCode == RESULT_OK) {
            // Make sure the app is not already connected or attempting to connect
            if (!mGoogleApiClient.isConnecting() &&
                    !mGoogleApiClient.isConnected()) {
                mGoogleApiClient.connect();
            }
        }
    }
}

در کد بالا، احتمالا متوجه بولی، mResolvingError اید. این حالت برنامه را در حالی که کاربر در حال رفع خطا است پیگیری می کند تا از تلاش های مکرر برای رفع همان خطا جلوگیری کند. به عنوان مثال، در حالی که گفتگوی انتخابگر حساب برای کمک به کاربر برای رفع خطای SIGN_IN_REQUIRED نمایش داده می شود، کاربر ممکن است صفحه را بچرخاند. این اکتیویتی شما را دوباره ایجاد می‌کند و باعث می‌شود متد onStart() دوباره فراخوانی شود، که سپس دوباره connect() فراخوانی می‌کند. این منجر به فراخوانی دیگری برای startResolutionForResult() می شود که یک گفتگوی انتخابگر حساب دیگر در مقابل یکی از موجود ایجاد می کند.

این بولی تنها در صورتی به هدف مورد نظر خود عمل می کند که در تمام نمونه های فعالیت ادامه داشته باشد. بخش بعدی توضیح می‌دهد که چگونه می‌توانید وضعیت رسیدگی به خطای برنامه خود را با وجود سایر اقدامات یا رویدادهایی که در دستگاه رخ می‌دهد، حفظ کنید.

حفظ حالت در حین رفع خطا

برای جلوگیری از اجرای کد در onConnectionFailed() در حالی که تلاش قبلی برای حل یک خطا در حال انجام است، باید یک Boolean حفظ کنید که ردیابی کند آیا برنامه شما قبلاً در حال تلاش برای حل یک خطا است یا خیر.

همانطور که در مثال کد بالا نشان داده شده است، برنامه شما باید هر بار که startResolutionForResult() فراخوانی می‌کند یا کادر گفتگوی GoogleApiAvailability.getErrorDialog() را نمایش می‌دهد، یک Boolean را روی true تنظیم کند. سپس، هنگامی که برنامه شما RESULT_OK در پاسخ به تماس onActivityResult() دریافت کرد، boolean را روی false تنظیم کنید.

برای ردیابی بولی در طول راه اندازی مجدد فعالیت (مانند زمانی که کاربر صفحه را می چرخاند)، با استفاده از onSaveInstanceState() بولی را در داده های نمونه ذخیره شده فعالیت ذخیره کنید:

private static final String STATE_RESOLVING_ERROR = "resolving_error";

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putBoolean(STATE_RESOLVING_ERROR, mResolvingError);
}

سپس حالت ذخیره شده را در طول onCreate() بازیابی کنید:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // ...
    mResolvingError = savedInstanceState != null
            && savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false);
}

اکنون آماده اجرای ایمن برنامه خود و اتصال دستی به خدمات Google Play هستید.

،

می‌توانید از شی GoogleApiClient ("Google API Client") برای دسترسی به APIهای Google ارائه شده در کتابخانه خدمات Google Play (مانند Google Sign-In، Games و Drive) استفاده کنید. Google API Client یک نقطه ورودی مشترک به خدمات Google Play ارائه می دهد و اتصال شبکه بین دستگاه کاربر و هر سرویس Google را مدیریت می کند.

با این حال، رابط کاربری جدیدتر GoogleApi و پیاده‌سازی‌های آن آسان‌تر برای استفاده هستند و راه ارجح برای دسترسی به API‌های خدمات Play هستند. دسترسی به APIهای Google را ببینید.

این راهنما نشان می دهد که چگونه می توانید:

  • اتصال خود به خدمات Google Play را به صورت خودکار مدیریت کنید.
  • تماس‌های API همزمان و ناهمزمان را با هر یک از سرویس‌های Google Play انجام دهید.
  • در موارد نادری که این امر ضروری است، اتصال خود به خدمات Google Play را به صورت دستی مدیریت کنید. برای کسب اطلاعات بیشتر، به اتصالات مدیریت شده دستی مراجعه کنید.
شکل 1: تصویری که نشان می‌دهد چگونه Google API Client یک رابط برای اتصال و برقراری تماس با هر یک از سرویس‌های موجود Google Play مانند Google Play Games و Google Drive فراهم می‌کند.

برای شروع، ابتدا باید کتابخانه خدمات Google Play (نسخه 15 یا بالاتر) را برای Android SDK خود نصب کنید. اگر قبلاً این کار را انجام نداده‌اید، دستورالعمل‌های موجود در «راه‌اندازی Google Play Services SDK» را دنبال کنید.

یک اتصال مدیریت شده خودکار را شروع کنید

پس از اینکه پروژه شما به کتابخانه خدمات Google Play مرتبط شد، یک نمونه از GoogleApiClient با استفاده از APIهای GoogleApiClient.Builder در روش onCreate() فعالیت خود ایجاد کنید. کلاس GoogleApiClient.Builder روش هایی را ارائه می دهد که به شما امکان می دهد API های Google را که می خواهید استفاده کنید و دامنه های OAuth 2.0 مورد نظر خود را مشخص کنید. در اینجا یک نمونه کد است که یک نمونه GoogleApiClient ایجاد می کند که با سرویس Google Drive متصل می شود:

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
    .enableAutoManage(this /* FragmentActivity */,
                      this /* OnConnectionFailedListener */)
    .addApi(Drive.API)
    .addScope(Drive.SCOPE_FILE)
    .build();

می‌توانید با افزودن فراخوان‌های اضافی به addApi() و addScope() چند API و چندین دامنه به یک GoogleApiClient اضافه کنید.

مهم: اگر Wearable API را به همراه سایر APIها به GoogleApiClient اضافه می‌کنید، ممکن است در دستگاه‌هایی که برنامه Wear OS را نصب نکرده‌اند، با خطاهای اتصال کلاینت مواجه شوید. برای جلوگیری از خطاهای اتصال، متد addApiIfAvailable() را فراخوانی کنید و از Wearable API عبور دهید تا به مشتری شما اجازه دهید تا API گم شده را به خوبی مدیریت کند. برای اطلاعات بیشتر، به دسترسی به Wearable API مراجعه کنید.

برای شروع یک اتصال مدیریت شده به طور خودکار، باید یک پیاده سازی برای رابط OnConnectionFailedListener تعیین کنید تا خطاهای اتصال غیرقابل حل را دریافت کنید. هنگامی که نمونه GoogleApiClient مدیریت خودکار شما تلاش می‌کند به APIهای Google متصل شود، به‌طور خودکار رابط کاربری را نمایش می‌دهد تا هرگونه نقص اتصال قابل حل را برطرف کند (مثلاً اگر خدمات Google Play نیاز به به‌روزرسانی داشته باشد). اگر خطایی رخ دهد که قابل حل نباشد، یک تماس با onConnectionFailed() دریافت خواهید کرد.

همچنین اگر برنامه شما نیاز دارد بداند که اتصال مدیریت شده به طور خودکار چه زمانی برقرار شده یا به حالت تعلیق درآمده است، می‌توانید یک پیاده‌سازی اختیاری برای رابط ConnectionCallbacks تعیین کنید. به عنوان مثال، اگر برنامه شما برای نوشتن داده‌ها در Google API تماس می‌گیرد، آن‌ها باید تنها پس از فراخوانی متد onConnected() فراخوانی شوند.

در اینجا یک نمونه فعالیت است که واسط های پاسخ به تماس را پیاده سازی کرده و آنها را به Google API Client اضافه می کند:

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import gms.drive.*;
import android.support.v4.app.FragmentActivity;

public class MyActivity extends FragmentActivity
        implements OnConnectionFailedListener {
    private GoogleApiClient mGoogleApiClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Create a GoogleApiClient instance
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this /* FragmentActivity */,
                                  this /* OnConnectionFailedListener */)
                .addApi(Drive.API)
                .addScope(Drive.SCOPE_FILE)
                .build();

        // ...
    }

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        // An unresolvable error has occurred and a connection to Google APIs
        // could not be established. Display an error message, or handle
        // the failure silently

        // ...
    }
}

نمونه GoogleApiClient شما به طور خودکار پس از فراخوانی فعالیت شما onStart() متصل می شود و پس از تماس onStop() قطع می شود. برنامه شما می‌تواند بلافاصله پس از ساخت GoogleApiClient ، بدون منتظر ماندن برای تکمیل اتصال، درخواست‌های خواندن را برای APIهای Google ارسال کند.

با Google Services ارتباط برقرار کنید

پس از اتصال، مشتری شما می‌تواند با استفاده از APIهای مخصوص سرویسی که برنامه شما برای آنها مجاز است، تماس‌های خواندن و نوشتن برقرار کند، همانطور که توسط APIها و محدوده‌هایی که به نمونه GoogleApiClient خود اضافه کرده‌اید مشخص شده‌اند.

توجه: قبل از برقراری تماس با سرویس‌های خاص Google، ممکن است لازم باشد ابتدا برنامه خود را در کنسول برنامه‌نویس Google ثبت کنید. برای دستورالعمل‌ها، به راهنمای شروع مناسب برای API که استفاده می‌کنید، مانند Google Drive یا Google Sign-In مراجعه کنید.

هنگامی که درخواست خواندن یا نوشتن را با استفاده از GoogleApiClient انجام می دهید، سرویس گیرنده API یک شی PendingResult برمی گرداند که نشان دهنده درخواست است. این بلافاصله قبل از تحویل درخواست به سرویس Google که برنامه شما با آن تماس می‌گیرد، اتفاق می‌افتد.

به عنوان مثال، در اینجا یک درخواست برای خواندن یک فایل از Google Drive است که یک شی PendingResult ارائه می دهد:

Query query = new Query.Builder()
        .addFilter(Filters.eq(SearchableField.TITLE, filename));
PendingResult<DriveApi.MetadataBufferResult> result = Drive.DriveApi.query(mGoogleApiClient, query);

پس از اینکه برنامه شما دارای یک شی PendingResult شد، برنامه شما می‌تواند تعیین کند که آیا درخواست به عنوان تماس ناهمزمان یا همزمان انجام می‌شود.

نکته: برنامه شما می‌تواند درخواست‌های خواندن را در حالی که به خدمات Google Play متصل نیست، در نوبت قرار دهد. برای مثال، برنامه شما می‌تواند روش‌هایی را برای خواندن یک فایل از Google Drive فراخوانی کند، صرفنظر از اینکه نمونه GoogleApiClient شما هنوز متصل است یا خیر. پس از برقراری ارتباط، درخواست‌های خواندن در صف اجرا می‌شوند. اگر برنامه شما با سرویس‌های Google Play با روش‌های نوشتن تماس بگیرد در حالی که Google API Client متصل نیست، درخواست‌های نوشتن خطا ایجاد می‌کنند.

استفاده از تماس های ناهمزمان

برای ناهمزمان کردن درخواست، setResultCallback() را در PendingResult فراخوانی کنید و یک پیاده سازی از رابط ResultCallback ارائه دهید. به عنوان مثال، این درخواست به صورت ناهمزمان اجرا شده است:

private void loadFile(String filename) {
    // Create a query for a specific filename in Drive.
    Query query = new Query.Builder()
            .addFilter(Filters.eq(SearchableField.TITLE, filename))
            .build();
    // Invoke the query asynchronously with a callback method
    Drive.DriveApi.query(mGoogleApiClient, query)
            .setResultCallback(new ResultCallback<DriveApi.MetadataBufferResult>() {
        @Override
        public void onResult(DriveApi.MetadataBufferResult result) {
            // Success! Handle the query result.
            // ...
        }
    });
}

هنگامی که برنامه شما یک شی Result در پاسخ به تماس onResult() دریافت می کند، به عنوان نمونه ای از زیر کلاس مناسب که توسط API مورد استفاده شما مشخص شده است، مانند DriveApi.MetadataBufferResult ، تحویل داده می شود.

استفاده از تماس های همزمان

اگر می‌خواهید کد شما با یک ترتیب کاملاً تعریف شده اجرا شود، شاید به این دلیل که نتیجه یک فراخوانی به عنوان آرگومان دیگری مورد نیاز است، می‌توانید با فراخوانی await() در PendingResult درخواست خود را همزمان کنید. این موضوع رشته را مسدود می کند و پس از تکمیل درخواست، شی Result برمی گرداند. این شی به عنوان نمونه ای از زیر کلاس مناسب که توسط API مورد استفاده شما مشخص شده است، برای مثال DriveApi.MetadataBufferResult تحویل داده می شود.

از آنجایی که فراخوانی await() تا رسیدن به نتیجه، رشته را مسدود می‌کند، برنامه شما هرگز نباید درخواست‌های همزمان به APIهای Google در رشته UI ارسال کند. برنامه شما می تواند با استفاده از یک شی AsyncTask یک رشته جدید ایجاد کند و از آن رشته برای ایجاد درخواست همزمان استفاده کند.

مثال زیر نحوه درخواست فایل به Google Drive را به صورت تماس همزمان نشان می دهد:

private void loadFile(String filename) {
    new GetFileTask().execute(filename);
}

private class GetFileTask extends AsyncTask<String, Void, Void> {
    protected void doInBackground(String filename) {
        Query query = new Query.Builder()
                .addFilter(Filters.eq(SearchableField.TITLE, filename))
                .build();
        // Invoke the query synchronously
        DriveApi.MetadataBufferResult result =
                Drive.DriveApi.query(mGoogleApiClient, query).await();

        // Continue doing other stuff synchronously
        // ...
    }
}

به Wearable API دسترسی پیدا کنید

Wearable API یک کانال ارتباطی برای برنامه‌هایی که روی دستگاه‌های دستی و پوشیدنی اجرا می‌شوند، فراهم می‌کند. API شامل مجموعه‌ای از اشیاء داده‌ای است که سیستم می‌تواند ارسال و همگام‌سازی کند، و شنوندگانی که برنامه‌های شما را از رویدادهای مهم با استفاده از یک لایه داده مطلع می‌کنند. Wearable API در دستگاه‌های دارای Android نسخه 4.3 (سطح API 18) یا بالاتر، زمانی که دستگاه پوشیدنی متصل است و برنامه همراه Wear OS روی دستگاه نصب شده است، در دسترس است.

استفاده از Wearable API به تنهایی

اگر برنامه شما از Wearable API استفاده می کند اما از سایر API های Google استفاده نمی کند، می توانید با فراخوانی متد addApi() این API را اضافه کنید. مثال زیر نحوه اضافه کردن Wearable API را به نمونه GoogleApiClient خود نشان می دهد:

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
    .enableAutoManage(this /* FragmentActivity */,
                      this /* OnConnectionFailedListener */)
    .addApi(Wearable.API)
    .build();

در شرایطی که Wearable API در دسترس نیست، درخواست‌های اتصال که شامل Wearable API هستند با کد خطای API_UNAVAILABLE ناموفق می‌شوند.

مثال زیر نشان می دهد که چگونه می توان تشخیص داد که آیا Wearable API موجود است یا خیر:

// Connection failed listener method for a client that only
// requests access to the Wearable API
@Override
public void onConnectionFailed(ConnectionResult result) {
    if (result.getErrorCode() == ConnectionResult.API_UNAVAILABLE) {
        // The Wearable API is unavailable
    }
    // ...
}

استفاده از Wearable API با سایر APIهای Google

اگر برنامه شما از Wearable API علاوه بر سایر API های Google استفاده می کند، متد addApiIfAvailable() را فراخوانی کنید و برای بررسی در دسترس بودن آن Wearable API را ارسال کنید. می‌توانید از این بررسی برای کمک به برنامه‌تان برای رسیدگی به مواردی که API در دسترس نیست، استفاده کنید.

مثال زیر نحوه دسترسی به Wearable API همراه با Drive API را نشان می دهد:

// Create a GoogleApiClient instance
mGoogleApiClient = new GoogleApiClient.Builder(this)
        .enableAutoManage(this /* FragmentActivity */,
                          this /* OnConnectionFailedListener */)
        .addApi(Drive.API)
        .addApiIfAvailable(Wearable.API)
        .addScope(Drive.SCOPE_FILE)
        .build();

در مثال بالا، GoogleApiClient می‌تواند بدون اتصال به Wearable API با موفقیت به Google Drive متصل شود، اگر در دسترس نباشد. پس از اتصال نمونه GoogleApiClient خود، قبل از برقراری تماس‌های API مطمئن شوید که Wearable API در دسترس است:

boolean wearAvailable = mGoogleApiClient.hasConnectedApi(Wearable.API);

نادیده گرفتن خطاهای اتصال API

اگر با addApi() تماس بگیرید و GoogleApiClient نتواند با موفقیت به آن API متصل شود، کل عملیات اتصال برای آن کلاینت با شکست مواجه می‌شود و پاسخ تماس onConnectionFailed() را راه‌اندازی می‌کند.

با استفاده از addApiIfAvailable() می توانید یک شکست اتصال API را ثبت کنید تا نادیده گرفته شود. اگر یک API اضافه شده با addApiIfAvailable() به دلیل خطای غیرقابل بازیابی (مانند API_UNAVAILABLE برای Wear) متصل نشود، آن API از GoogleApiClient شما حذف می‌شود و کلاینت به اتصال به APIهای دیگر ادامه می‌دهد. با این حال، اگر هر یک از اتصال API با یک خطای قابل بازیابی (مانند هدف قطعنامه رضایت OAuth) با شکست مواجه شود، عملیات اتصال کلاینت با شکست مواجه می شود. هنگام استفاده از یک اتصال مدیریت شده به طور خودکار، GoogleApiClient تلاش می کند تا در صورت امکان چنین خطاهایی را برطرف کند. هنگام استفاده از یک اتصال مدیریت شده دستی، یک ConnectionResult حاوی یک هدف رزولوشن به پاسخ تماس onConnectionFailed() تحویل داده می شود. خرابی‌های اتصال API تنها در صورتی نادیده گرفته می‌شوند که هیچ قطعنامه‌ای برای خرابی وجود نداشته باشد و API با addApiIfAvailable() اضافه شده باشد. برای آشنایی با نحوه اجرای مدیریت شکست اتصال دستی، به رسیدگی به خرابی های اتصال مراجعه کنید.

از آنجایی که APIهای اضافه شده با addApiIfAvailable() ممکن است همیشه در نمونه GoogleApiClient متصل وجود نداشته باشند، باید با افزودن چک با استفاده از hasConnectedApi() از تماس‌های این APIها محافظت کنید. برای اینکه بفهمید چرا یک API خاص در زمانی که کل عملیات اتصال برای کلاینت موفقیت آمیز بود، متصل نشد، getConnectionResult() را فراخوانی کنید و کد خطا را از شی ConnectionResult دریافت کنید. اگر سرویس گیرنده شما با یک API تماس بگیرد زمانی که به مشتری متصل نیست، تماس با کد وضعیت API_NOT_AVAILABLE انجام نمی شود.

اگر API که از طریق addApiIfAvailable() اضافه می کنید به یک یا چند محدوده نیاز دارد، به جای استفاده از متد addScope addApiIfAvailable() addScope() خود اضافه کنید. اگر اتصال API قبل از دریافت رضایت OAuth از کار بیفتد، ممکن است دامنه‌های اضافه‌شده با این رویکرد درخواست نشود، در حالی که دامنه‌هایی که با addScope() اضافه می‌شوند همیشه درخواست می‌شوند.

اتصالات مدیریت شده به صورت دستی

اکثر این راهنما به شما نشان می دهد که چگونه از روش enableAutoManage برای شروع یک اتصال مدیریت شده خودکار با خطاهای حل شده خودکار استفاده کنید. تقریباً در همه موارد، این بهترین و ساده‌ترین راه برای اتصال به Google API از برنامه Android شما است. با این حال، شرایطی وجود دارد که می‌خواهید از یک اتصال مدیریت شده دستی به Google API در برنامه خود استفاده کنید:

  • برای دسترسی به APIهای Google خارج از یک فعالیت یا حفظ کنترل اتصال API
  • برای سفارشی کردن رسیدگی و حل خطای اتصال

این بخش نمونه هایی از این موارد و سایر موارد استفاده پیشرفته را ارائه می دهد.

یک اتصال مدیریت شده دستی را شروع کنید

برای راه‌اندازی یک اتصال مدیریت‌شده دستی به GoogleApiClient ، باید یک پیاده‌سازی برای رابط‌های پاسخ به تماس، ConnectionCallbacks و OnConnectionFailedListener مشخص کنید. هنگامی که اتصال به سرویس‌های Google Play موفقیت آمیز، شکست یا تعلیق می‌شود، این واسط‌ها در پاسخ به روش ناهمزمان connect() تماس دریافت می‌کنند.

    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addApi(Drive.API)
            .addScope(Drive.SCOPE_FILE)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build()

هنگام مدیریت یک اتصال به صورت دستی، باید متدهای connect() و disconnect() در نقاط مناسب در چرخه عمر برنامه خود فراخوانی کنید. در زمینه فعالیت، بهترین روش فراخوانی connect() در متد onStart() اکتیویتی و disconnect() در متد onStop() اکتیویتی است. متدهای connect() و disconnect() به طور خودکار هنگام استفاده از یک اتصال مدیریت شده خودکار فراخوانی می شوند.

اگر از GoogleApiClient برای اتصال به APIهایی که نیاز به احراز هویت دارند، مانند Google Drive یا Google Play Games استفاده می‌کنید، احتمال زیادی وجود دارد که اولین تلاش شما برای اتصال ناموفق باشد و برنامه شما با خطای onConnectionFailed() با خطای SIGN_IN_REQUIRED تماس بگیرد.

رفع خرابی های اتصال

هنگامی که برنامه شما تماسی با پاسخ تماس onConnectionFailed() دریافت می کند، باید hasResolution() در شی ConnectionResult ارائه شده فراخوانی کنید. اگر مقدار true را برگرداند، برنامه شما می‌تواند با فراخوانی startResolutionForResult() در شی ConnectionResult از کاربر درخواست کند که برای رفع خطا اقدام فوری انجام دهد. متد startResolutionForResult() در این شرایط مانند startActivityForResult() عمل می‌کند و یک اکتیویتی مناسب با زمینه راه‌اندازی می‌کند که به کاربر در رفع خطا کمک می‌کند (مانند فعالیتی که به کاربر در انتخاب حساب کمک می‌کند).

اگر hasResolution() false برگرداند، برنامه شما باید GoogleApiAvailability.getErrorDialog() را فراخوانی کند و کد خطا را به این روش ارسال کند. این یک Dialog ارائه شده توسط سرویس‌های Google Play را برمی‌گرداند که متناسب با خطا است. گفتگو ممکن است به سادگی پیامی را ارائه دهد که خطا را توضیح می دهد، یا همچنین ممکن است اقدامی برای راه اندازی فعالیتی ارائه دهد که می تواند خطا را برطرف کند (مانند زمانی که کاربر نیاز به نصب نسخه جدیدتری از خدمات Google Play دارد).

برای مثال، متد callback onConnectionFailed() شما اکنون باید به شکل زیر باشد:

public class MyActivity extends Activity
        implements ConnectionCallbacks, OnConnectionFailedListener {

    // Request code to use when launching the resolution activity
    private static final int REQUEST_RESOLVE_ERROR = 1001;
    // Unique tag for the error dialog fragment
    private static final String DIALOG_ERROR = "dialog_error";
    // Bool to track whether the app is already resolving an error
    private boolean mResolvingError = false;

    // ...

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        if (mResolvingError) {
            // Already attempting to resolve an error.
            return;
        } else if (result.hasResolution()) {
            try {
                mResolvingError = true;
                result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
            } catch (SendIntentException e) {
                // There was an error with the resolution intent. Try again.
                mGoogleApiClient.connect();
            }
        } else {
            // Show dialog using GoogleApiAvailability.getErrorDialog()
            showErrorDialog(result.getErrorCode());
            mResolvingError = true;
        }
    }

    // The rest of this code is all about building the error dialog

    /* Creates a dialog for an error message */
    private void showErrorDialog(int errorCode) {
        // Create a fragment for the error dialog
        ErrorDialogFragment dialogFragment = new ErrorDialogFragment();
        // Pass the error that should be displayed
        Bundle args = new Bundle();
        args.putInt(DIALOG_ERROR, errorCode);
        dialogFragment.setArguments(args);
        dialogFragment.show(getSupportFragmentManager(), "errordialog");
    }

    /* Called from ErrorDialogFragment when the dialog is dismissed. */
    public void onDialogDismissed() {
        mResolvingError = false;
    }

    /* A fragment to display an error dialog */
    public static class ErrorDialogFragment extends DialogFragment {
        public ErrorDialogFragment() { }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            // Get the error code and retrieve the appropriate dialog
            int errorCode = this.getArguments().getInt(DIALOG_ERROR);
            return GoogleApiAvailability.getInstance().getErrorDialog(
                    this.getActivity(), errorCode, REQUEST_RESOLVE_ERROR);
        }

        @Override
        public void onDismiss(DialogInterface dialog) {
            ((MyActivity) getActivity()).onDialogDismissed();
        }
    }
}

پس از اینکه کاربر گفتگوی ارائه شده توسط startResolutionForResult() را تکمیل کرد یا پیام ارائه شده توسط GoogleApiAvailability.getErrorDialog() را رد کرد، فعالیت شما پاسخ تماس onActivityResult() را با کد نتیجه RESULT_OK دریافت می کند. سپس برنامه شما می تواند دوباره connect() فراخوانی کند. به عنوان مثال:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_RESOLVE_ERROR) {
        mResolvingError = false;
        if (resultCode == RESULT_OK) {
            // Make sure the app is not already connected or attempting to connect
            if (!mGoogleApiClient.isConnecting() &&
                    !mGoogleApiClient.isConnected()) {
                mGoogleApiClient.connect();
            }
        }
    }
}

در کد بالا، احتمالا متوجه بولی، mResolvingError اید. این حالت برنامه را در حالی که کاربر در حال رفع خطا است پیگیری می کند تا از تلاش های مکرر برای رفع همان خطا جلوگیری کند. به عنوان مثال، در حالی که گفتگوی انتخابگر حساب برای کمک به کاربر برای رفع خطای SIGN_IN_REQUIRED نمایش داده می شود، کاربر ممکن است صفحه را بچرخاند. این اکتیویتی شما را دوباره ایجاد می‌کند و باعث می‌شود متد onStart() دوباره فراخوانی شود، که سپس دوباره connect() فراخوانی می‌کند. این منجر به فراخوانی دیگری برای startResolutionForResult() می شود که یک گفتگوی انتخابگر حساب دیگر در مقابل یکی از موجود ایجاد می کند.

این بولی تنها در صورتی به هدف مورد نظر خود عمل می کند که در تمام نمونه های فعالیت ادامه داشته باشد. بخش بعدی توضیح می‌دهد که چگونه می‌توانید وضعیت رسیدگی به خطای برنامه خود را با وجود سایر اقدامات یا رویدادهایی که در دستگاه رخ می‌دهد، حفظ کنید.

حفظ حالت در حین رفع خطا

برای جلوگیری از اجرای کد در onConnectionFailed() در حالی که تلاش قبلی برای حل یک خطا در حال انجام است، باید یک Boolean حفظ کنید که ردیابی کند آیا برنامه شما قبلاً در حال تلاش برای حل یک خطا است یا خیر.

همانطور که در مثال کد بالا نشان داده شده است، برنامه شما باید هر بار که startResolutionForResult() فراخوانی می‌کند یا کادر گفتگوی GoogleApiAvailability.getErrorDialog() را نمایش می‌دهد، یک Boolean را روی true تنظیم کند. سپس، هنگامی که برنامه شما RESULT_OK در پاسخ به تماس onActivityResult() دریافت کرد، boolean را روی false تنظیم کنید.

برای ردیابی بولی در طول راه اندازی مجدد فعالیت (مانند زمانی که کاربر صفحه را می چرخاند)، با استفاده از onSaveInstanceState() بولی را در داده های نمونه ذخیره شده فعالیت ذخیره کنید:

private static final String STATE_RESOLVING_ERROR = "resolving_error";

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putBoolean(STATE_RESOLVING_ERROR, mResolvingError);
}

سپس حالت ذخیره شده را در طول onCreate() بازیابی کنید:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // ...
    mResolvingError = savedInstanceState != null
            && savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false);
}

اکنون آماده اجرای ایمن برنامه خود و اتصال دستی به خدمات Google Play هستید.

،

می‌توانید از شی GoogleApiClient ("Google API Client") برای دسترسی به APIهای Google ارائه شده در کتابخانه خدمات Google Play (مانند Google Sign-In، Games و Drive) استفاده کنید. Google API Client یک نقطه ورودی مشترک به خدمات Google Play ارائه می دهد و اتصال شبکه بین دستگاه کاربر و هر سرویس Google را مدیریت می کند.

با این حال، رابط کاربری جدیدتر GoogleApi و پیاده‌سازی‌های آن آسان‌تر برای استفاده هستند و راه ارجح برای دسترسی به API‌های خدمات Play هستند. دسترسی به APIهای Google را ببینید.

این راهنما نشان می دهد که چگونه می توانید:

  • اتصال خود به خدمات Google Play را به صورت خودکار مدیریت کنید.
  • تماس‌های API همزمان و ناهمزمان را با هر یک از سرویس‌های Google Play انجام دهید.
  • در موارد نادری که این امر ضروری است، اتصال خود به خدمات Google Play را به صورت دستی مدیریت کنید. برای کسب اطلاعات بیشتر، به اتصالات مدیریت شده دستی مراجعه کنید.
شکل 1: تصویری که نشان می دهد مشتری Google API چگونه رابط کاربری و برقراری تماس با هر یک از خدمات موجود در Google Play مانند Google Play Games و Google Drive را فراهم می کند.

برای شروع ، ابتدا باید کتابخانه خدمات Google Play (تجدید نظر 15 یا بالاتر) را برای Android SDK خود نصب کنید. اگر قبلاً این کار را نکرده اید ، دستورالعمل های Setup Google Play Services SDK را دنبال کنید.

یک اتصال به طور خودکار مدیریت شده را شروع کنید

پس از پیوند پروژه شما به کتابخانه خدمات Google Play ، نمونه ای از GoogleApiClient با استفاده از API های GoogleApiClient.Builder در روش onCreate() فعالیت خود ایجاد کنید. کلاس GoogleApiClient.Builder روش هایی را ارائه می دهد که به شما امکان می دهد API های Google را که می خواهید استفاده کنید و Scopes OAUTH 2.0 مورد نظر خود را مشخص کنید. در اینجا یک مثال کد وجود دارد که یک نمونه GoogleApiClient ایجاد می کند که با سرویس Google Drive ارتباط برقرار می کند:

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
    .enableAutoManage(this /* FragmentActivity */,
                      this /* OnConnectionFailedListener */)
    .addApi(Drive.API)
    .addScope(Drive.SCOPE_FILE)
    .build();

با افزودن تماس های اضافی به addApi() و addScope() می توانید چندین API و چندین دامنه را به همان GoogleApiClient اضافه کنید.

نکته مهم: اگر در حال اضافه کردن API Wearable به همراه سایر API ها به GoogleApiClient هستید ، ممکن است در دستگاههایی که برنامه OS OS را نصب نمی کنند ، خطاهای اتصال مشتری را وارد کنید. برای جلوگیری از خطاهای اتصال ، با روش addApiIfAvailable() تماس بگیرید و در API Wearable عبور کنید تا به مشتری خود اجازه دهید API مفقود شده را به طرز فجیعی اداره کند. برای اطلاعات بیشتر ، به API پوشیدنی دسترسی پیدا کنید.

برای شروع یک اتصال به طور خودکار مدیریت شده ، باید برای دریافت خطاهای اتصال غیرقابل حل ، یک رابط OnConnectionFailedListener را مشخص کنید. هنگامی که نمونه GoogleApiClient با مدیریت خودکار شما سعی در اتصال به API های Google دارد ، به طور خودکار UI را برای تلاش برای رفع هرگونه خرابی اتصال قابل حل نشان می دهد (به عنوان مثال ، اگر Google Play Services نیاز به به روزرسانی دارد). اگر خطایی رخ دهد که قابل حل نیست ، شما می توانید تماس با onConnectionFailed() دریافت کنید.

همچنین اگر برنامه شما باید بداند اتصال به طور خودکار مدیریت شده یا به حالت تعلیق درآمده است ، می توانید اجرای اختیاری را برای رابط ConnectionCallbacks مشخص کنید. به عنوان مثال اگر برنامه شما برای نوشتن داده ها به Google API تماس می گیرد ، فقط پس از فراخوانی روش onConnected() باید از این موارد استفاده شود.

در اینجا یک فعالیت مثال وجود دارد که رابط های پاسخ به تماس را پیاده سازی می کند و آنها را به مشتری Google API اضافه می کند:

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import gms.drive.*;
import android.support.v4.app.FragmentActivity;

public class MyActivity extends FragmentActivity
        implements OnConnectionFailedListener {
    private GoogleApiClient mGoogleApiClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Create a GoogleApiClient instance
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this /* FragmentActivity */,
                                  this /* OnConnectionFailedListener */)
                .addApi(Drive.API)
                .addScope(Drive.SCOPE_FILE)
                .build();

        // ...
    }

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        // An unresolvable error has occurred and a connection to Google APIs
        // could not be established. Display an error message, or handle
        // the failure silently

        // ...
    }
}

نمونه GoogleApiClient شما پس از تماس با فعالیت شما onStart() به طور خودکار متصل می شود و پس از تماس onStop() قطع می شود. برنامه شما می تواند بلافاصله پس از ساختن GoogleApiClient درخواست های خوانده شده به Google API را شروع کند ، بدون اینکه منتظر تکمیل اتصال باشید.

با Google Services ارتباط برقرار کنید

پس از اتصال ، مشتری شما می تواند با استفاده از API های خاص سرویس که برنامه شما مجاز است ، تماس های خواندن و نوشتن را انجام دهد ، همانطور که توسط API ها و Scopes که به نمونه GoogleApiClient خود اضافه کرده اید ، مشخص شده است.

توجه: قبل از برقراری تماس با خدمات خاص Google ، ممکن است ابتدا نیاز به ثبت برنامه خود در کنسول Google Developer داشته باشید. برای دستورالعمل ، به راهنمای مناسب برای شروع API مورد استفاده خود ، مانند Google Drive یا Google Sign Sign ، مراجعه کنید.

هنگامی که درخواست خواندن یا نوشتن را با استفاده از GoogleApiClient انجام می دهید ، مشتری API یک شیء PendingResult برمی گرداند که نمایانگر درخواست است. این بلافاصله قبل از ارسال درخواست به سرویس Google که برنامه شما با آن تماس می گیرد ، بلافاصله رخ می دهد.

به عنوان مثال ، در اینجا درخواستی برای خواندن پرونده ای از Google Drive وجود دارد که یک شیء PendingResult فراهم می کند:

Query query = new Query.Builder()
        .addFilter(Filters.eq(SearchableField.TITLE, filename));
PendingResult<DriveApi.MetadataBufferResult> result = Drive.DriveApi.query(mGoogleApiClient, query);

بعد از اینکه برنامه شما یک شیء PendingResult است ، برنامه شما می تواند مشخص کند که آیا این درخواست به عنوان یک تماس ناهمزمان یا به عنوان یک تماس همزمان انجام می شود.

نکته: برنامه شما می تواند درخواست های خوانده شده را در حالی که به Google Play Services وصل نشده است ، Enqueue Enqueue کند. به عنوان مثال ، برنامه شما می تواند با روش خواندن پرونده ای از Google Drive صرف نظر از اینکه آیا نمونه GoogleApiClient شما هنوز به هم وصل شده است. پس از برقراری اتصال ، درخواست های خواندن Enqueued اجرا می شود. اگر برنامه شما تماس با Google Play Services Methods می نویسد در حالی که مشتری Google API شما به هم وصل نشده است ، درخواست ها خطایی ایجاد می کنند.

با استفاده از تماس های ناهمزمان

برای ایجاد درخواست ناهمزمان ، با setResultCallback() در PendingResult تماس بگیرید و اجرای رابط ResultCallback ارائه دهید. به عنوان مثال ، درخواست اجرا شده به صورت غیر همزمان:

private void loadFile(String filename) {
    // Create a query for a specific filename in Drive.
    Query query = new Query.Builder()
            .addFilter(Filters.eq(SearchableField.TITLE, filename))
            .build();
    // Invoke the query asynchronously with a callback method
    Drive.DriveApi.query(mGoogleApiClient, query)
            .setResultCallback(new ResultCallback<DriveApi.MetadataBufferResult>() {
        @Override
        public void onResult(DriveApi.MetadataBufferResult result) {
            // Success! Handle the query result.
            // ...
        }
    });
}

هنگامی که برنامه شما در پاسخ به پاسخ onResult() یک شیء Result دریافت می کند ، به عنوان نمونه ای از زیر کلاس مناسب همانطور که توسط API مورد استفاده شما مشخص شده است ، مانند DriveApi.MetadataBufferResult ارائه می شود.

با استفاده از تماس های همزمان

اگر می خواهید کد شما به ترتیب کاملاً مشخصی اجرا شود ، شاید به این دلیل که نتیجه یک تماس به عنوان استدلال برای دیگری لازم است ، می توانید با فراخوانی await() در مورد PendingResult درخواست خود را همزمان کنید. این موضوع را مسدود می کند و پس از اتمام درخواست ، هدف Result را برمی گرداند. این شی به عنوان نمونه ای از زیر کلاس مناسب همانطور که توسط API مورد استفاده شما مشخص شده است ، به عنوان مثال DriveApi.MetadataBufferResult تحویل داده می شود.

از آنجا که فراخوانی await() موضوع را تا رسیدن به نتیجه مسدود می کند ، برنامه شما هرگز نباید درخواست های همزمان را به Google API در موضوع UI ارائه دهد. برنامه شما می تواند با استفاده از یک شیء AsyncTask یک موضوع جدید ایجاد کند و از آن موضوع برای ایجاد درخواست همزمان استفاده کند.

مثال زیر نحوه ایجاد درخواست فایل به Google Drive را به عنوان یک تماس همزمان نشان می دهد:

private void loadFile(String filename) {
    new GetFileTask().execute(filename);
}

private class GetFileTask extends AsyncTask<String, Void, Void> {
    protected void doInBackground(String filename) {
        Query query = new Query.Builder()
                .addFilter(Filters.eq(SearchableField.TITLE, filename))
                .build();
        // Invoke the query synchronously
        DriveApi.MetadataBufferResult result =
                Drive.DriveApi.query(mGoogleApiClient, query).await();

        // Continue doing other stuff synchronously
        // ...
    }
}

به API پوشیدنی دسترسی پیدا کنید

API پوشیدنی یک کانال ارتباطی را برای برنامه هایی که در دستگاه های دستی و پوشیدنی اجرا می شوند ، فراهم می کند. API شامل مجموعه ای از اشیاء داده است که سیستم می تواند ارسال و همگام سازی کند ، و شنوندگان که با استفاده از یک لایه داده ، برنامه های شما را از رویدادهای مهم مطلع می کنند. API پوشیدنی در دستگاه هایی که Android 4.3 (API سطح 18) یا بالاتر دارند در هنگام اتصال یک دستگاه پوشیدنی و برنامه Wear Os همراه بر روی دستگاه در دسترس است.

با استفاده از مستقل API پوشیدنی

اگر برنامه شما از API پوشیدنی اما API های Google دیگر استفاده نمی کند ، می توانید با فراخوانی روش addApi() این API را اضافه کنید. مثال زیر نحوه اضافه کردن API پوشیدنی را به نمونه GoogleApiClient خود نشان می دهد:

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
    .enableAutoManage(this /* FragmentActivity */,
                      this /* OnConnectionFailedListener */)
    .addApi(Wearable.API)
    .build();

در شرایطی که API پوشیدنی در دسترس نیست ، درخواست های اتصال که شامل API پوشیدنی است با کد خطای API_UNAVAILABLE شکست می خورد.

مثال زیر نشان می دهد که چگونه API پوشیدنی در دسترس است:

// Connection failed listener method for a client that only
// requests access to the Wearable API
@Override
public void onConnectionFailed(ConnectionResult result) {
    if (result.getErrorCode() == ConnectionResult.API_UNAVAILABLE) {
        // The Wearable API is unavailable
    }
    // ...
}

با استفاده از API پوشیدنی با سایر API های Google

اگر برنامه شما علاوه بر سایر API های Google از API پوشیدنی استفاده می کند ، با روش addApiIfAvailable() تماس بگیرید و در API پوشیدنی عبور کنید تا بررسی کنید که آیا در دسترس است. شما می توانید از این چک استفاده کنید تا به برنامه خود کمک کنید تا مواردی را که API در دسترس نیست ، به طرز فجیعی کنترل کنید.

مثال زیر نحوه دسترسی به API پوشیدنی را به همراه API درایو نشان می دهد:

// Create a GoogleApiClient instance
mGoogleApiClient = new GoogleApiClient.Builder(this)
        .enableAutoManage(this /* FragmentActivity */,
                          this /* OnConnectionFailedListener */)
        .addApi(Drive.API)
        .addApiIfAvailable(Wearable.API)
        .addScope(Drive.SCOPE_FILE)
        .build();

در مثال بالا ، GoogleApiClient می تواند با موفقیت با Google Drive بدون اتصال به API پوشیدنی در صورت عدم دسترسی ، با Google Drive ارتباط برقرار کند. بعد از اتصال نمونه GoogleApiClient خود ، اطمینان حاصل کنید که API پوشیدنی قبل از برقراری تماس های API در دسترس است:

boolean wearAvailable = mGoogleApiClient.hasConnectedApi(Wearable.API);

نادیده گرفتن شکست های اتصال API

اگر addApi() تماس بگیرید و GoogleApiClient قادر به اتصال موفقیت آمیز به آن API نیست ، کل عملیات اتصال برای آن مشتری شکست می خورد و پاسخ تماس onConnectionFailed() را ایجاد می کند.

با استفاده از addApiIfAvailable() می توانید یک عدم اتصال API را ثبت کنید. اگر یک API با addApiIfAvailable() به دلیل خطای غیر قابل بازیافت (مانند API_UNAVAILABLE برای سایش) به آن متصل شود ، آن API از GoogleApiClient شما رها می شود و مشتری برای اتصال به API های دیگر ادامه می یابد. با این حال ، اگر هرگونه اتصال API با یک خطای قابل بازیابی (مانند یک هدف وضوح رضایت OAUTH) شکست بخورد ، عملکرد اتصال مشتری با شکست مواجه می شود. هنگام استفاده از یک اتصال به طور خودکار مدیریت شده ، GoogleApiClient سعی خواهد کرد در صورت امکان چنین خطاهایی را برطرف کند. هنگام استفاده از یک اتصال دستی که به صورت دستی مدیریت می شود ، ConnectionResult حاوی یک وضوح به قصد پاسخ به تماس با شماره onConnectionFailed() ارسال می شود. خرابی های اتصال API فقط در صورت عدم وضوح برای خرابی نادیده گرفته می شود و API با addApiIfAvailable() اضافه می شود. برای یادگیری نحوه اجرای دستیابی به خرابی اتصال دستی ، به خرابی اتصال به دسته مراجعه کنید.

از آنجا که API ها با افزودنی addApiIfAvailable() ممکن است همیشه در نمونه GoogleApiClient متصل وجود نداشته باشد ، باید با اضافه کردن یک چک با استفاده از hasConnectedApi() از تماس های این API ها محافظت کنید. برای اینکه دریابید که چرا یک API خاص در هنگام موفقیت کل عملکرد اتصال برای مشتری ، نتوانسته است به هم وصل شود ، getConnectionResult() تماس بگیرید و کد خطا را از شیء ConnectionResult دریافت کنید. اگر مشتری شما هنگام اتصال به مشتری ، با API تماس می گیرد ، تماس با کد وضعیت API_NOT_AVAILABLE خراب می شود.

اگر API را که از طریق addApiIfAvailable() به یک یا چند دامنه نیاز دارید ، آن دسته از دامنه ها را به عنوان پارامترهای موجود در روش addApiIfAvailable() به جای استفاده از روش addScope() اضافه کنید. در صورت عدم موفقیت اتصال API قبل از رضایت OAUTH ، Scopes اضافه شده با استفاده از این روش ممکن است درخواست نشود ، در حالی که همیشه از Scopes اضافه شده با addScope() درخواست می شود.

اتصالات مدیریت شده دستی

اکثر این راهنما به شما نشان می دهد که چگونه می توانید از روش enableAutoManage برای شروع اتصال به طور خودکار مدیریت شده با خطاهای حل شده به طور خودکار استفاده کنید. تقریباً در همه موارد ، این بهترین و ساده ترین راه برای اتصال به Google API از برنامه Android شما است. با این حال ، موقعیت هایی وجود دارد که می خواهید در برنامه خود از یک اتصال دستی به صورت دستی به Google API استفاده کنید:

  • برای دسترسی به API های Google خارج از یک فعالیت یا حفظ کنترل اتصال API
  • برای سفارشی سازی خطای اتصال و وضوح خطای اتصال

در این بخش نمونه هایی از این موارد و سایر موارد استفاده پیشرفته ارائه شده است.

یک اتصال دستی را به صورت دستی شروع کنید

برای شروع یک اتصال دستی به صورت دستی به GoogleApiClient ، باید اجرای رابط های پاسخ به تماس ، ConnectionCallbacks و OnConnectionFailedListener را مشخص کنید. این رابط ها در پاسخ به روش connect() هنگام اتصال به خدمات Google Play موفق می شوند ، یا به حالت تعلیق در می آیند.

    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addApi(Drive.API)
            .addScope(Drive.SCOPE_FILE)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build()

هنگام مدیریت اتصال به صورت دستی ، باید در نقاط مناسب در چرخه عمر برنامه خود با روش های connect() و disconnect() تماس بگیرید. در یک زمینه فعالیت ، بهترین روش این است که connect() در روش onStart() فعالیت خود و disconnect() در روش onStop() فعالیت خود فراخوانی کنید. روشهای connect() و disconnect() هنگام استفاده از یک اتصال به صورت خودکار مدیریت شده به صورت خودکار خوانده می شوند.

اگر از GoogleApiClient برای اتصال به API هایی که نیاز به تأیید اعتبار دارند ، مانند Google Drive یا Google Play Games استفاده می کنید ، یک فرصت خوب وجود دارد که اولین تلاش برای اتصال شما شکست بخورد و برنامه شما با خطای SIGN_IN_REQUIRED یک تماس با onConnectionFailed() دریافت می کند زیرا حساب کاربری مشخص نشده است.

انجام خرابی های اتصال

هنگامی که برنامه شما تماس تلفنی با پاسخ به تماس onConnectionFailed() دریافت می کند ، باید با hasResolution() در مورد ConnectionResult ارائه شده تماس بگیرید. اگر درست برگردد ، برنامه شما می تواند درخواست کند که کاربر با فراخوانی startResolutionForResult() در مورد شیء ConnectionResult ، اقدام به انجام این خطا کند. روش startResolutionForResult() در این شرایط مانند startActivityForResult() رفتار می کند و فعالیتی متناسب با زمینه ای را انجام می دهد که به کاربر کمک می کند تا خطا را برطرف کند (مانند فعالیتی که به کاربر کمک می کند تا یک حساب را انتخاب کند).

اگر hasResolution() نادرست را برگرداند ، برنامه شما باید با GoogleApiAvailability.getErrorDialog() تماس بگیرد ، و کد خطا را به این روش منتقل می کند. این Dialog ارائه شده توسط Google Play Services متناسب با خطا است. این گفتگو ممکن است به سادگی پیامی را توضیح دهد که خطا را توضیح می دهد ، یا همچنین ممکن است عملی را برای راه اندازی فعالیتی فراهم کند که بتواند خطا را برطرف کند (مانند زمانی که کاربر نیاز به نصب نسخه جدیدتر از خدمات Google Play دارد).

به عنوان مثال ، روش پاسخ onConnectionFailed() اکنون باید به این شکل باشد:

public class MyActivity extends Activity
        implements ConnectionCallbacks, OnConnectionFailedListener {

    // Request code to use when launching the resolution activity
    private static final int REQUEST_RESOLVE_ERROR = 1001;
    // Unique tag for the error dialog fragment
    private static final String DIALOG_ERROR = "dialog_error";
    // Bool to track whether the app is already resolving an error
    private boolean mResolvingError = false;

    // ...

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        if (mResolvingError) {
            // Already attempting to resolve an error.
            return;
        } else if (result.hasResolution()) {
            try {
                mResolvingError = true;
                result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
            } catch (SendIntentException e) {
                // There was an error with the resolution intent. Try again.
                mGoogleApiClient.connect();
            }
        } else {
            // Show dialog using GoogleApiAvailability.getErrorDialog()
            showErrorDialog(result.getErrorCode());
            mResolvingError = true;
        }
    }

    // The rest of this code is all about building the error dialog

    /* Creates a dialog for an error message */
    private void showErrorDialog(int errorCode) {
        // Create a fragment for the error dialog
        ErrorDialogFragment dialogFragment = new ErrorDialogFragment();
        // Pass the error that should be displayed
        Bundle args = new Bundle();
        args.putInt(DIALOG_ERROR, errorCode);
        dialogFragment.setArguments(args);
        dialogFragment.show(getSupportFragmentManager(), "errordialog");
    }

    /* Called from ErrorDialogFragment when the dialog is dismissed. */
    public void onDialogDismissed() {
        mResolvingError = false;
    }

    /* A fragment to display an error dialog */
    public static class ErrorDialogFragment extends DialogFragment {
        public ErrorDialogFragment() { }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            // Get the error code and retrieve the appropriate dialog
            int errorCode = this.getArguments().getInt(DIALOG_ERROR);
            return GoogleApiAvailability.getInstance().getErrorDialog(
                    this.getActivity(), errorCode, REQUEST_RESOLVE_ERROR);
        }

        @Override
        public void onDismiss(DialogInterface dialog) {
            ((MyActivity) getActivity()).onDialogDismissed();
        }
    }
}

پس از اتمام کاربر گفتگوی ارائه شده توسط startResolutionForResult() یا پیام ارائه شده توسط GoogleApiAvailability.getErrorDialog() را رد می کند ، فعالیت شما با کد نتیجه RESULT_OK onActivityResult() پاسخ می دهد. برنامه شما می تواند دوباره با connect() تماس بگیرد. به عنوان مثال:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_RESOLVE_ERROR) {
        mResolvingError = false;
        if (resultCode == RESULT_OK) {
            // Make sure the app is not already connected or attempting to connect
            if (!mGoogleApiClient.isConnecting() &&
                    !mGoogleApiClient.isConnected()) {
                mGoogleApiClient.connect();
            }
        }
    }
}

در کد فوق ، شما احتمالاً متوجه Boolean ، mResolvingError . این امر در حالی که کاربر در حال حل و فصل خطا برای جلوگیری از تلاش های تکراری برای حل و فصل همان خطا است ، وضعیت برنامه را پیگیری می کند. به عنوان مثال ، در حالی که گفتگوی Account Picker برای کمک به کاربر برای حل و فصل خطای SIGN_IN_REQUIRED نمایش داده می شود ، کاربر ممکن است صفحه را بچرخاند. این فعالیت شما را بازآفرینی می کند و باعث می شود که روش onStart() شما دوباره فراخوانی شود ، که سپس دوباره connect() را فراخوانی می کند. این منجر به فراخوانی دیگری به startResolutionForResult() می شود ، که گفتگوی انتخاب کننده حساب دیگری را در مقابل مورد موجود ایجاد می کند.

این بولی فقط در صورت ادامه در موارد فعالیت ، هدف مورد نظر خود را انجام می دهد. در بخش بعدی نحوه حفظ خطای رسیدگی به حالت برنامه شما با وجود سایر اقدامات کاربر یا رویدادهایی که در دستگاه رخ می دهد ، توضیح می دهد.

ضمن حل یک خطا ، حالت را حفظ کنید

برای جلوگیری از اجرای کد در onConnectionFailed() در حالی که تلاش قبلی برای حل خطا در حال انجام است ، باید یک بولی را حفظ کنید که آیا برنامه شما در حال حاضر در تلاش برای حل خطا است.

همانطور که در مثال کد در بالا نشان داده شده است ، برنامه شما باید هر بار که به startResolutionForResult() می خواند ، یک boolean را true تنظیم کند یا گفتگو را از GoogleApiAvailability.getErrorDialog() نشان می دهد. سپس ، هنگامی که برنامه شما در RESULT_OK به تماس onActivityResult() دریافت می کند ، Boolean را به false تنظیم کنید.

برای پیگیری راه اندازی مجدد Boolean در سراسر فعالیت (مانند زمانی که کاربر صفحه را می چرخاند) ، Boolean را در داده های ذخیره شده ذخیره شده با استفاده از onSaveInstanceState() :

private static final String STATE_RESOLVING_ERROR = "resolving_error";

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putBoolean(STATE_RESOLVING_ERROR, mResolvingError);
}

سپس حالت ذخیره شده را در حین onCreate() بازیابی کنید:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // ...
    mResolvingError = savedInstanceState != null
            && savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false);
}

اکنون آماده هستید تا با خیال راحت برنامه خود را اجرا کرده و به صورت دستی به Google Play Services متصل شوید.

،

برای دسترسی به API های Google ارائه شده در کتابخانه خدمات Google Play (مانند ورود به سیستم Google ، بازی ها و درایو) می توانید از شی GoogleApiClient ("Google API Client") استفاده کنید. مشتری Google API یک نقطه ورود مشترک به Google Play Services ارائه می دهد و اتصال شبکه بین دستگاه کاربر و هر سرویس Google را مدیریت می کند.

با این حال ، رابط جدید GoogleApi و پیاده سازی های آن آسان تر است و روش ارجح برای دسترسی به API های خدمات بازی است. به دسترسی به API های Google مراجعه کنید.

این راهنما نشان می دهد که چگونه می توانید:

  • به طور خودکار اتصال خود را به خدمات Google Play مدیریت کنید.
  • تماس های API همزمان و ناهمزمان را به هر یک از خدمات Google Play انجام دهید.
  • ارتباط خود را به صورت دستی با خدمات Google Play در موارد نادری که در آن لازم است مدیریت کنید. برای کسب اطلاعات بیشتر ، به اتصالات مدیریت شده دستی مراجعه کنید.
شکل 1: تصویری که نشان می دهد مشتری Google API چگونه رابط کاربری و برقراری تماس با هر یک از خدمات موجود در Google Play مانند Google Play Games و Google Drive را فراهم می کند.

برای شروع ، ابتدا باید کتابخانه خدمات Google Play (تجدید نظر 15 یا بالاتر) را برای Android SDK خود نصب کنید. اگر قبلاً این کار را نکرده اید ، دستورالعمل های Setup Google Play Services SDK را دنبال کنید.

یک اتصال به طور خودکار مدیریت شده را شروع کنید

پس از پیوند پروژه شما به کتابخانه خدمات Google Play ، نمونه ای از GoogleApiClient با استفاده از API های GoogleApiClient.Builder در روش onCreate() فعالیت خود ایجاد کنید. کلاس GoogleApiClient.Builder روش هایی را ارائه می دهد که به شما امکان می دهد API های Google را که می خواهید استفاده کنید و Scopes OAUTH 2.0 مورد نظر خود را مشخص کنید. در اینجا یک مثال کد وجود دارد که یک نمونه GoogleApiClient ایجاد می کند که با سرویس Google Drive ارتباط برقرار می کند:

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
    .enableAutoManage(this /* FragmentActivity */,
                      this /* OnConnectionFailedListener */)
    .addApi(Drive.API)
    .addScope(Drive.SCOPE_FILE)
    .build();

با افزودن تماس های اضافی به addApi() و addScope() می توانید چندین API و چندین دامنه را به همان GoogleApiClient اضافه کنید.

نکته مهم: اگر در حال اضافه کردن API Wearable به همراه سایر API ها به GoogleApiClient هستید ، ممکن است در دستگاههایی که برنامه OS OS را نصب نمی کنند ، خطاهای اتصال مشتری را وارد کنید. برای جلوگیری از خطاهای اتصال ، با روش addApiIfAvailable() تماس بگیرید و در API Wearable عبور کنید تا به مشتری خود اجازه دهید API مفقود شده را به طرز فجیعی اداره کند. برای اطلاعات بیشتر ، به API پوشیدنی دسترسی پیدا کنید.

برای شروع یک اتصال به طور خودکار مدیریت شده ، باید برای دریافت خطاهای اتصال غیرقابل حل ، یک رابط OnConnectionFailedListener را مشخص کنید. هنگامی که نمونه GoogleApiClient با مدیریت خودکار شما سعی در اتصال به API های Google دارد ، به طور خودکار UI را برای تلاش برای رفع هرگونه خرابی اتصال قابل حل نشان می دهد (به عنوان مثال ، اگر Google Play Services نیاز به به روزرسانی دارد). اگر خطایی رخ دهد که قابل حل نیست ، شما می توانید تماس با onConnectionFailed() دریافت کنید.

همچنین اگر برنامه شما باید بداند اتصال به طور خودکار مدیریت شده یا به حالت تعلیق درآمده است ، می توانید اجرای اختیاری را برای رابط ConnectionCallbacks مشخص کنید. به عنوان مثال اگر برنامه شما برای نوشتن داده ها به Google API تماس می گیرد ، فقط پس از فراخوانی روش onConnected() باید از این موارد استفاده شود.

در اینجا یک فعالیت مثال وجود دارد که رابط های پاسخ به تماس را پیاده سازی می کند و آنها را به مشتری Google API اضافه می کند:

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import gms.drive.*;
import android.support.v4.app.FragmentActivity;

public class MyActivity extends FragmentActivity
        implements OnConnectionFailedListener {
    private GoogleApiClient mGoogleApiClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Create a GoogleApiClient instance
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this /* FragmentActivity */,
                                  this /* OnConnectionFailedListener */)
                .addApi(Drive.API)
                .addScope(Drive.SCOPE_FILE)
                .build();

        // ...
    }

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        // An unresolvable error has occurred and a connection to Google APIs
        // could not be established. Display an error message, or handle
        // the failure silently

        // ...
    }
}

نمونه GoogleApiClient شما پس از تماس با فعالیت شما onStart() به طور خودکار متصل می شود و پس از تماس onStop() قطع می شود. برنامه شما می تواند بلافاصله پس از ساختن GoogleApiClient درخواست های خوانده شده به Google API را شروع کند ، بدون اینکه منتظر تکمیل اتصال باشید.

با Google Services ارتباط برقرار کنید

پس از اتصال ، مشتری شما می تواند با استفاده از API های خاص سرویس که برنامه شما مجاز است ، تماس های خواندن و نوشتن را انجام دهد ، همانطور که توسط API ها و Scopes که به نمونه GoogleApiClient خود اضافه کرده اید ، مشخص شده است.

توجه: قبل از برقراری تماس با خدمات خاص Google ، ممکن است ابتدا نیاز به ثبت برنامه خود در کنسول Google Developer داشته باشید. برای دستورالعمل ، به راهنمای مناسب برای شروع API مورد استفاده خود ، مانند Google Drive یا Google Sign Sign ، مراجعه کنید.

هنگامی که درخواست خواندن یا نوشتن را با استفاده از GoogleApiClient انجام می دهید ، مشتری API یک شیء PendingResult برمی گرداند که نمایانگر درخواست است. این بلافاصله قبل از ارسال درخواست به سرویس Google که برنامه شما با آن تماس می گیرد ، بلافاصله رخ می دهد.

به عنوان مثال ، در اینجا درخواستی برای خواندن پرونده ای از Google Drive وجود دارد که یک شیء PendingResult فراهم می کند:

Query query = new Query.Builder()
        .addFilter(Filters.eq(SearchableField.TITLE, filename));
PendingResult<DriveApi.MetadataBufferResult> result = Drive.DriveApi.query(mGoogleApiClient, query);

بعد از اینکه برنامه شما یک شیء PendingResult است ، برنامه شما می تواند مشخص کند که آیا این درخواست به عنوان یک تماس ناهمزمان یا به عنوان یک تماس همزمان انجام می شود.

نکته: برنامه شما می تواند درخواست های خوانده شده را در حالی که به Google Play Services وصل نشده است ، Enqueue Enqueue کند. به عنوان مثال ، برنامه شما می تواند با روش خواندن پرونده ای از Google Drive صرف نظر از اینکه آیا نمونه GoogleApiClient شما هنوز به هم وصل شده است. پس از برقراری اتصال ، درخواست های خواندن Enqueued اجرا می شود. اگر برنامه شما تماس با Google Play Services Methods می نویسد در حالی که مشتری Google API شما به هم وصل نشده است ، درخواست ها خطایی ایجاد می کنند.

با استفاده از تماس های ناهمزمان

برای ایجاد درخواست ناهمزمان ، با setResultCallback() در PendingResult تماس بگیرید و اجرای رابط ResultCallback ارائه دهید. به عنوان مثال ، درخواست اجرا شده به صورت غیر همزمان:

private void loadFile(String filename) {
    // Create a query for a specific filename in Drive.
    Query query = new Query.Builder()
            .addFilter(Filters.eq(SearchableField.TITLE, filename))
            .build();
    // Invoke the query asynchronously with a callback method
    Drive.DriveApi.query(mGoogleApiClient, query)
            .setResultCallback(new ResultCallback<DriveApi.MetadataBufferResult>() {
        @Override
        public void onResult(DriveApi.MetadataBufferResult result) {
            // Success! Handle the query result.
            // ...
        }
    });
}

هنگامی که برنامه شما در پاسخ به پاسخ onResult() یک شیء Result دریافت می کند ، به عنوان نمونه ای از زیر کلاس مناسب همانطور که توسط API مورد استفاده شما مشخص شده است ، مانند DriveApi.MetadataBufferResult ارائه می شود.

با استفاده از تماس های همزمان

اگر می خواهید کد شما به ترتیب کاملاً مشخصی اجرا شود ، شاید به این دلیل که نتیجه یک تماس به عنوان استدلال برای دیگری لازم است ، می توانید با فراخوانی await() در مورد PendingResult درخواست خود را همزمان کنید. این موضوع را مسدود می کند و پس از اتمام درخواست ، هدف Result را برمی گرداند. این شی به عنوان نمونه ای از زیر کلاس مناسب همانطور که توسط API مورد استفاده شما مشخص شده است ، به عنوان مثال DriveApi.MetadataBufferResult تحویل داده می شود.

از آنجا که فراخوانی await() موضوع را تا رسیدن به نتیجه مسدود می کند ، برنامه شما هرگز نباید درخواست های همزمان را به Google API در موضوع UI ارائه دهد. برنامه شما می تواند با استفاده از یک شیء AsyncTask یک موضوع جدید ایجاد کند و از آن موضوع برای ایجاد درخواست همزمان استفاده کند.

مثال زیر نحوه ایجاد درخواست فایل به Google Drive را به عنوان یک تماس همزمان نشان می دهد:

private void loadFile(String filename) {
    new GetFileTask().execute(filename);
}

private class GetFileTask extends AsyncTask<String, Void, Void> {
    protected void doInBackground(String filename) {
        Query query = new Query.Builder()
                .addFilter(Filters.eq(SearchableField.TITLE, filename))
                .build();
        // Invoke the query synchronously
        DriveApi.MetadataBufferResult result =
                Drive.DriveApi.query(mGoogleApiClient, query).await();

        // Continue doing other stuff synchronously
        // ...
    }
}

به API پوشیدنی دسترسی پیدا کنید

API پوشیدنی یک کانال ارتباطی را برای برنامه هایی که در دستگاه های دستی و پوشیدنی اجرا می شوند ، فراهم می کند. API شامل مجموعه ای از اشیاء داده است که سیستم می تواند ارسال و همگام سازی کند ، و شنوندگان که با استفاده از یک لایه داده ، برنامه های شما را از رویدادهای مهم مطلع می کنند. API پوشیدنی در دستگاه هایی که Android 4.3 (API سطح 18) یا بالاتر دارند در هنگام اتصال یک دستگاه پوشیدنی و برنامه Wear Os همراه بر روی دستگاه در دسترس است.

با استفاده از مستقل API پوشیدنی

اگر برنامه شما از API پوشیدنی اما API های Google دیگر استفاده نمی کند ، می توانید با فراخوانی روش addApi() این API را اضافه کنید. مثال زیر نحوه اضافه کردن API پوشیدنی را به نمونه GoogleApiClient خود نشان می دهد:

GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
    .enableAutoManage(this /* FragmentActivity */,
                      this /* OnConnectionFailedListener */)
    .addApi(Wearable.API)
    .build();

در شرایطی که API پوشیدنی در دسترس نیست ، درخواست های اتصال که شامل API پوشیدنی است با کد خطای API_UNAVAILABLE شکست می خورد.

مثال زیر نشان می دهد که چگونه API پوشیدنی در دسترس است:

// Connection failed listener method for a client that only
// requests access to the Wearable API
@Override
public void onConnectionFailed(ConnectionResult result) {
    if (result.getErrorCode() == ConnectionResult.API_UNAVAILABLE) {
        // The Wearable API is unavailable
    }
    // ...
}

با استفاده از API پوشیدنی با سایر API های Google

اگر برنامه شما علاوه بر سایر API های Google از API پوشیدنی استفاده می کند ، با روش addApiIfAvailable() تماس بگیرید و در API پوشیدنی عبور کنید تا بررسی کنید که آیا در دسترس است. شما می توانید از این چک استفاده کنید تا به برنامه خود کمک کنید تا مواردی را که API در دسترس نیست ، به طرز فجیعی کنترل کنید.

مثال زیر نحوه دسترسی به API پوشیدنی را به همراه API درایو نشان می دهد:

// Create a GoogleApiClient instance
mGoogleApiClient = new GoogleApiClient.Builder(this)
        .enableAutoManage(this /* FragmentActivity */,
                          this /* OnConnectionFailedListener */)
        .addApi(Drive.API)
        .addApiIfAvailable(Wearable.API)
        .addScope(Drive.SCOPE_FILE)
        .build();

در مثال بالا ، GoogleApiClient می تواند با موفقیت با Google Drive بدون اتصال به API پوشیدنی در صورت عدم دسترسی ، با Google Drive ارتباط برقرار کند. بعد از اتصال نمونه GoogleApiClient خود ، اطمینان حاصل کنید که API پوشیدنی قبل از برقراری تماس های API در دسترس است:

boolean wearAvailable = mGoogleApiClient.hasConnectedApi(Wearable.API);

نادیده گرفتن شکست های اتصال API

اگر addApi() تماس بگیرید و GoogleApiClient قادر به اتصال موفقیت آمیز به آن API نیست ، کل عملیات اتصال برای آن مشتری شکست می خورد و پاسخ تماس onConnectionFailed() را ایجاد می کند.

با استفاده از addApiIfAvailable() می توانید یک عدم اتصال API را ثبت کنید. اگر یک API با addApiIfAvailable() به دلیل خطای غیر قابل بازیافت (مانند API_UNAVAILABLE برای سایش) به آن متصل شود ، آن API از GoogleApiClient شما رها می شود و مشتری برای اتصال به API های دیگر ادامه می یابد. با این حال ، اگر هرگونه اتصال API با یک خطای قابل بازیابی (مانند یک هدف وضوح رضایت OAUTH) شکست بخورد ، عملکرد اتصال مشتری با شکست مواجه می شود. هنگام استفاده از یک اتصال به طور خودکار مدیریت شده ، GoogleApiClient سعی خواهد کرد در صورت امکان چنین خطاهایی را برطرف کند. هنگام استفاده از یک اتصال دستی که به صورت دستی مدیریت می شود ، ConnectionResult حاوی یک وضوح به قصد پاسخ به تماس onConnectionFailed() ارسال می شود. خرابی های اتصال API فقط در صورت عدم وضوح برای خرابی نادیده گرفته می شود و API با addApiIfAvailable() اضافه می شود. برای یادگیری نحوه اجرای دستیابی به خرابی اتصال دستی ، به خرابی اتصال به دسته مراجعه کنید.

از آنجا که API ها با افزودنی addApiIfAvailable() ممکن است همیشه در نمونه GoogleApiClient متصل وجود نداشته باشد ، باید با اضافه کردن یک چک با استفاده از hasConnectedApi() از تماس های این API ها محافظت کنید. برای اینکه دریابید که چرا یک API خاص در هنگام موفقیت کل عملکرد اتصال برای مشتری ، نتوانسته است به هم وصل شود ، getConnectionResult() تماس بگیرید و کد خطا را از شیء ConnectionResult دریافت کنید. اگر مشتری شما هنگام اتصال به مشتری ، با API تماس می گیرد ، تماس با کد وضعیت API_NOT_AVAILABLE خراب می شود.

اگر API را که از طریق addApiIfAvailable() به یک یا چند دامنه نیاز دارید ، آن دسته از دامنه ها را به عنوان پارامترهای موجود در روش addApiIfAvailable() به جای استفاده از روش addScope() اضافه کنید. در صورت عدم موفقیت اتصال API قبل از رضایت OAUTH ، Scopes اضافه شده با استفاده از این روش ممکن است درخواست نشود ، در حالی که همیشه از Scopes اضافه شده با addScope() درخواست می شود.

اتصالات مدیریت شده دستی

اکثر این راهنما به شما نشان می دهد که چگونه می توانید از روش enableAutoManage برای شروع اتصال به طور خودکار مدیریت شده با خطاهای حل شده به طور خودکار استفاده کنید. تقریباً در همه موارد ، این بهترین و ساده ترین راه برای اتصال به Google API از برنامه Android شما است. با این حال ، موقعیت هایی وجود دارد که می خواهید در برنامه خود از یک اتصال دستی به صورت دستی به Google API استفاده کنید:

  • برای دسترسی به API های Google خارج از یک فعالیت یا حفظ کنترل اتصال API
  • برای سفارشی سازی خطای اتصال و وضوح خطای اتصال

در این بخش نمونه هایی از این موارد و سایر موارد استفاده پیشرفته ارائه شده است.

یک اتصال دستی را به صورت دستی شروع کنید

برای شروع یک اتصال دستی به صورت دستی به GoogleApiClient ، باید اجرای رابط های پاسخ به تماس ، ConnectionCallbacks و OnConnectionFailedListener را مشخص کنید. این رابط ها در پاسخ به روش connect() هنگام اتصال به خدمات Google Play موفق می شوند ، یا به حالت تعلیق در می آیند.

    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addApi(Drive.API)
            .addScope(Drive.SCOPE_FILE)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build()

هنگام مدیریت اتصال به صورت دستی ، باید در نقاط مناسب در چرخه عمر برنامه خود با روش های connect() و disconnect() تماس بگیرید. در یک زمینه فعالیت ، بهترین روش این است که connect() در روش onStart() فعالیت خود و disconnect() در روش onStop() فعالیت خود فراخوانی کنید. روشهای connect() و disconnect() هنگام استفاده از یک اتصال به صورت خودکار مدیریت شده به صورت خودکار خوانده می شوند.

اگر از GoogleApiClient برای اتصال به API هایی که نیاز به تأیید اعتبار دارند ، مانند Google Drive یا Google Play Games استفاده می کنید ، یک فرصت خوب وجود دارد که اولین تلاش برای اتصال شما شکست بخورد و برنامه شما با خطای SIGN_IN_REQUIRED یک تماس با onConnectionFailed() دریافت می کند زیرا حساب کاربری مشخص نشده است.

انجام خرابی های اتصال

هنگامی که برنامه شما تماس تلفنی با پاسخ به تماس onConnectionFailed() دریافت می کند ، باید با hasResolution() در مورد ConnectionResult ارائه شده تماس بگیرید. اگر درست برگردد ، برنامه شما می تواند درخواست کند که کاربر با فراخوانی startResolutionForResult() در مورد شیء ConnectionResult ، اقدام به انجام این خطا کند. روش startResolutionForResult() در این شرایط مانند startActivityForResult() رفتار می کند و فعالیتی متناسب با زمینه ای را انجام می دهد که به کاربر کمک می کند تا خطا را برطرف کند (مانند فعالیتی که به کاربر کمک می کند تا یک حساب را انتخاب کند).

اگر hasResolution() نادرست را برگرداند ، برنامه شما باید با GoogleApiAvailability.getErrorDialog() تماس بگیرد ، و کد خطا را به این روش منتقل می کند. این Dialog ارائه شده توسط Google Play Services متناسب با خطا است. این گفتگو ممکن است به سادگی پیامی را توضیح دهد که خطا را توضیح می دهد ، یا همچنین ممکن است عملی را برای راه اندازی فعالیتی فراهم کند که بتواند خطا را برطرف کند (مانند زمانی که کاربر نیاز به نصب نسخه جدیدتر از خدمات Google Play دارد).

به عنوان مثال ، روش پاسخ onConnectionFailed() اکنون باید به این شکل باشد:

public class MyActivity extends Activity
        implements ConnectionCallbacks, OnConnectionFailedListener {

    // Request code to use when launching the resolution activity
    private static final int REQUEST_RESOLVE_ERROR = 1001;
    // Unique tag for the error dialog fragment
    private static final String DIALOG_ERROR = "dialog_error";
    // Bool to track whether the app is already resolving an error
    private boolean mResolvingError = false;

    // ...

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        if (mResolvingError) {
            // Already attempting to resolve an error.
            return;
        } else if (result.hasResolution()) {
            try {
                mResolvingError = true;
                result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
            } catch (SendIntentException e) {
                // There was an error with the resolution intent. Try again.
                mGoogleApiClient.connect();
            }
        } else {
            // Show dialog using GoogleApiAvailability.getErrorDialog()
            showErrorDialog(result.getErrorCode());
            mResolvingError = true;
        }
    }

    // The rest of this code is all about building the error dialog

    /* Creates a dialog for an error message */
    private void showErrorDialog(int errorCode) {
        // Create a fragment for the error dialog
        ErrorDialogFragment dialogFragment = new ErrorDialogFragment();
        // Pass the error that should be displayed
        Bundle args = new Bundle();
        args.putInt(DIALOG_ERROR, errorCode);
        dialogFragment.setArguments(args);
        dialogFragment.show(getSupportFragmentManager(), "errordialog");
    }

    /* Called from ErrorDialogFragment when the dialog is dismissed. */
    public void onDialogDismissed() {
        mResolvingError = false;
    }

    /* A fragment to display an error dialog */
    public static class ErrorDialogFragment extends DialogFragment {
        public ErrorDialogFragment() { }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            // Get the error code and retrieve the appropriate dialog
            int errorCode = this.getArguments().getInt(DIALOG_ERROR);
            return GoogleApiAvailability.getInstance().getErrorDialog(
                    this.getActivity(), errorCode, REQUEST_RESOLVE_ERROR);
        }

        @Override
        public void onDismiss(DialogInterface dialog) {
            ((MyActivity) getActivity()).onDialogDismissed();
        }
    }
}

پس از اتمام کاربر گفتگوی ارائه شده توسط startResolutionForResult() یا پیام ارائه شده توسط GoogleApiAvailability.getErrorDialog() را رد می کند ، فعالیت شما با کد نتیجه RESULT_OK onActivityResult() پاسخ می دهد. برنامه شما می تواند دوباره با connect() تماس بگیرد. به عنوان مثال:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_RESOLVE_ERROR) {
        mResolvingError = false;
        if (resultCode == RESULT_OK) {
            // Make sure the app is not already connected or attempting to connect
            if (!mGoogleApiClient.isConnecting() &&
                    !mGoogleApiClient.isConnected()) {
                mGoogleApiClient.connect();
            }
        }
    }
}

در کد فوق ، شما احتمالاً متوجه Boolean ، mResolvingError . این امر در حالی که کاربر در حال حل و فصل خطا برای جلوگیری از تلاش های تکراری برای حل و فصل همان خطا است ، وضعیت برنامه را پیگیری می کند. به عنوان مثال ، در حالی که گفتگوی Account Picker برای کمک به کاربر برای حل و فصل خطای SIGN_IN_REQUIRED نمایش داده می شود ، کاربر ممکن است صفحه را بچرخاند. این فعالیت شما را بازآفرینی می کند و باعث می شود که روش onStart() شما دوباره فراخوانی شود ، که سپس دوباره connect() را فراخوانی می کند. این منجر به فراخوانی دیگری به startResolutionForResult() می شود ، که گفتگوی انتخاب کننده حساب دیگری را در مقابل مورد موجود ایجاد می کند.

این بولی فقط در صورت ادامه در موارد فعالیت ، هدف مورد نظر خود را انجام می دهد. در بخش بعدی نحوه حفظ خطای رسیدگی به حالت برنامه شما با وجود سایر اقدامات کاربر یا رویدادهایی که در دستگاه رخ می دهد ، توضیح می دهد.

ضمن حل یک خطا ، حالت را حفظ کنید

برای جلوگیری از اجرای کد در onConnectionFailed() در حالی که تلاش قبلی برای حل خطا در حال انجام است ، باید یک بولی را حفظ کنید که آیا برنامه شما در حال حاضر در تلاش برای حل خطا است.

همانطور که در مثال کد در بالا نشان داده شده است ، برنامه شما باید هر بار که به startResolutionForResult() می خواند ، یک boolean را true تنظیم کند یا گفتگو را از GoogleApiAvailability.getErrorDialog() نشان می دهد. سپس ، هنگامی که برنامه شما در RESULT_OK به تماس onActivityResult() دریافت می کند ، Boolean را به false تنظیم کنید.

برای پیگیری راه اندازی مجدد Boolean در سراسر فعالیت (مانند زمانی که کاربر صفحه را می چرخاند) ، Boolean را در داده های ذخیره شده ذخیره شده با استفاده از onSaveInstanceState() :

private static final String STATE_RESOLVING_ERROR = "resolving_error";

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putBoolean(STATE_RESOLVING_ERROR, mResolvingError);
}

سپس حالت ذخیره شده را در حین onCreate() بازیابی کنید:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // ...
    mResolvingError = savedInstanceState != null
            && savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false);
}

اکنون آماده هستید تا با خیال راحت برنامه خود را اجرا کرده و به صورت دستی به Google Play Services متصل شوید.