Mengakses Google API dengan GoogleApiClient (tidak digunakan lagi)

Anda dapat menggunakan objek GoogleApiClient ("Klien Google API") untuk mengakses Google API yang disediakan di library layanan Google Play (seperti Login dengan Google, Game, dan Drive). Klien Google API menyediakan titik entri umum ke layanan Google Play dan mengelola koneksi jaringan antara perangkat pengguna dan setiap layanan Google.

Namun, antarmuka GoogleApi yang lebih baru dan implementasinya lebih mudah digunakan dan merupakan cara yang lebih disukai untuk mengakses API layanan Play. Lihat Mengakses Google API.

Panduan ini menunjukkan cara:

  • Mengelola koneksi Anda ke layanan Google Play secara otomatis.
  • Melakukan panggilan API sinkron dan asinkron ke layanan Google Play mana pun.
  • Mengelola koneksi Anda ke layanan Google Play secara manual dalam kasus yang jarang terjadi jika diperlukan. Untuk mempelajari lebih lanjut, lihat Koneksi yang dikelola secara manual.
Gambar 1: Ilustrasi yang menunjukkan cara Klien Google API menyediakan antarmuka untuk menghubungkan dan melakukan panggilan ke layanan Google Play yang tersedia seperti Google Play Game dan Google Drive.

Untuk memulai, Anda harus menginstal library layanan Google Play (revisi 15 atau yang lebih tinggi) untuk Android SDK terlebih dahulu. Jika Anda belum melakukannya, ikuti petunjuk di Menyiapkan SDK Layanan Google Play.

Memulai koneksi yang dikelola secara otomatis

Setelah project Anda ditautkan ke library layanan Google Play, buat instance GoogleApiClient menggunakan GoogleApiClient.Builder API dalam metode onCreate() aktivitas Anda. Class GoogleApiClient.Builder menyediakan metode yang memungkinkan Anda menentukan Google API yang ingin digunakan dan cakupan OAuth 2.0 yang diinginkan. Berikut adalah contoh kode yang membuat instance GoogleApiClient yang terhubung dengan layanan Google Drive:

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

Anda dapat menambahkan beberapa API dan beberapa cakupan ke GoogleApiClient yang sama dengan menambahkan panggilan tambahan ke addApi() dan addScope().

Penting: Jika menambahkan Wearable API bersama dengan API lain ke GoogleApiClient, Anda mungkin mengalami error koneksi klien di perangkat yang tidak menginstal aplikasi Wear OS. Untuk menghindari error koneksi, panggil metode addApiIfAvailable() dan teruskan Wearable API agar klien Anda dapat menangani API yang hilang dengan baik. Untuk informasi selengkapnya, lihat Mengakses Wearable API.

Untuk memulai koneksi yang dikelola secara otomatis, Anda harus menentukan penerapan untuk antarmuka OnConnectionFailedListener agar menerima error koneksi yang tidak dapat diselesaikan. Saat instance GoogleApiClient yang dikelola otomatis mencoba terhubung ke Google API, instance tersebut akan otomatis menampilkan UI untuk mencoba memperbaiki kegagalan koneksi yang dapat di-resolve (misalnya, jika layanan Google Play perlu diupdate). Jika terjadi error yang tidak dapat diselesaikan, Anda akan menerima panggilan ke onConnectionFailed().

Anda juga dapat menentukan implementasi opsional untuk antarmuka ConnectionCallbacks jika aplikasi Anda perlu mengetahui kapan koneksi yang dikelola secara otomatis dibuat atau ditangguhkan. Misalnya, jika aplikasi Anda melakukan panggilan untuk menulis data ke Google API, panggilan ini hanya boleh dipanggil setelah metode onConnected() dipanggil.

Berikut adalah contoh aktivitas yang mengimplementasikan antarmuka callback dan menambahkannya ke Klien 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

        // ...
    }
}

Instance GoogleApiClient akan otomatis terhubung setelah aktivitas Anda memanggil onStart() dan memutuskan hubungan setelah memanggil onStop(). Aplikasi Anda dapat langsung mulai membuat permintaan baca ke Google API setelah mem-build GoogleApiClient, tanpa menunggu koneksi selesai.

Berkomunikasi dengan Layanan Google

Setelah terhubung, klien Anda dapat melakukan panggilan baca dan tulis menggunakan API khusus layanan yang diberi otorisasi oleh aplikasi Anda, seperti yang ditentukan oleh API dan cakupan yang Anda tambahkan ke instance GoogleApiClient.

Catatan: Sebelum melakukan panggilan ke layanan Google tertentu, Anda mungkin perlu mendaftarkan aplikasi terlebih dahulu di Konsol Google Play. Untuk mendapatkan petunjuk, lihat panduan memulai yang sesuai untuk API yang Anda gunakan, seperti Google Drive atau Login dengan Google.

Saat Anda melakukan permintaan baca atau tulis menggunakan GoogleApiClient, klien API akan menampilkan objek PendingResult yang mewakili permintaan tersebut. Hal ini terjadi segera, sebelum permintaan dikirim ke layanan Google yang dipanggil aplikasi Anda.

Misalnya, berikut adalah permintaan untuk membaca file dari Google Drive yang menyediakan objek PendingResult:

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

Setelah aplikasi memiliki objek PendingResult, aplikasi Anda dapat menentukan apakah permintaan ditangani sebagai panggilan asinkron atau sebagai panggilan sinkron.

Tips: Aplikasi Anda dapat mengantrekan permintaan baca saat tidak terhubung ke layanan Google Play. Misalnya, aplikasi Anda dapat memanggil metode untuk membaca file dari Google Drive, terlepas dari apakah instance GoogleApiClient Anda sudah terhubung atau belum. Setelah koneksi dibuat, permintaan baca yang diantrekan akan dieksekusi. Permintaan tulis akan menghasilkan error jika aplikasi Anda memanggil metode tulis layanan Google Play saat Klien Google API tidak terhubung.

Menggunakan panggilan asinkron

Untuk membuat permintaan asinkron, panggil setResultCallback() di PendingResult dan berikan implementasi antarmuka ResultCallback. Misalnya, berikut permintaan yang dijalankan secara asinkron:

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

Saat aplikasi Anda menerima objek Result dalam callback onResult(), objek tersebut dikirim sebagai instance subclass yang sesuai seperti yang ditentukan oleh API yang Anda gunakan, seperti DriveApi.MetadataBufferResult.

Menggunakan panggilan sinkron

Jika Anda ingin kode dieksekusi dalam urutan yang ditentukan secara ketat, mungkin karena hasil dari satu panggilan diperlukan sebagai argumen untuk panggilan lainnya, Anda dapat membuat permintaan sinkron dengan memanggil await() di PendingResult. Tindakan ini akan memblokir thread dan menampilkan objek Result saat permintaan selesai. Objek ini dikirim sebagai instance subclass yang sesuai seperti yang ditentukan oleh API yang Anda gunakan, misalnya DriveApi.MetadataBufferResult.

Karena memanggil await() memblokir thread hingga hasilnya tiba, aplikasi Anda tidak boleh membuat permintaan sinkron ke Google API di UI thread. Aplikasi Anda dapat membuat thread baru menggunakan objek AsyncTask, dan menggunakan thread tersebut untuk membuat permintaan sinkron.

Contoh berikut menunjukkan cara membuat permintaan file ke Google Drive sebagai panggilan sinkron:

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
        // ...
    }
}

Mengakses Wearable API

Wearable API menyediakan saluran komunikasi untuk aplikasi yang berjalan di perangkat genggam dan wearable. API ini terdiri dari sekumpulan objek data yang dapat dikirim dan disinkronkan oleh sistem, serta pemroses yang memberi tahu aplikasi Anda tentang peristiwa penting menggunakan lapisan data. Wearable API tersedia di perangkat yang menjalankan Android 4.3 (API level 18) atau yang lebih tinggi saat perangkat wearable terhubung dan aplikasi pendamping Wear OS diinstal di perangkat.

Menggunakan Wearable API mandiri

Jika aplikasi Anda menggunakan Wearable API, tetapi tidak menggunakan Google API lainnya, Anda dapat menambahkan API ini dengan memanggil metode addApi(). Contoh berikut menunjukkan cara menambahkan Wearable API ke instance GoogleApiClient:

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

Jika Wearable API tidak tersedia, permintaan koneksi yang menyertakan Wearable API akan gagal dengan kode error API_UNAVAILABLE.

Contoh berikut menunjukkan cara menentukan apakah Wearable API tersedia:

// 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
    }
    // ...
}

Menggunakan Wearable API dengan Google API lainnya

Jika aplikasi Anda menggunakan Wearable API selain Google API lainnya, panggil metode addApiIfAvailable() dan teruskan Wearable API untuk memeriksa apakah API tersebut tersedia. Anda dapat menggunakan pemeriksaan ini untuk membantu aplikasi menangani kasus saat API tidak tersedia dengan baik.

Contoh berikut menunjukkan cara mengakses Wearable API beserta 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();

Pada contoh di atas, GoogleApiClient berhasil terhubung dengan Google Drive tanpa terhubung ke Wearable API jika tidak tersedia. Setelah menghubungkan instance GoogleApiClient, pastikan Wearable API tersedia sebelum melakukan panggilan API:

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

Mengabaikan Kegagalan Koneksi API

Jika Anda memanggil addApi() dan GoogleApiClient tidak dapat terhubung dengan API tersebut, seluruh operasi koneksi untuk klien tersebut akan gagal dan memicu callback onConnectionFailed().

Anda dapat mendaftarkan kegagalan koneksi API untuk diabaikan menggunakan addApiIfAvailable(). Jika API yang ditambahkan dengan addApiIfAvailable() gagal terhubung karena error yang tidak dapat dipulihkan (seperti API_UNAVAILABLE untuk Wear), API tersebut akan dihapus dari GoogleApiClient dan klien akan melanjutkan untuk terhubung ke API lain. Namun, jika koneksi API gagal dengan error yang dapat dipulihkan (seperti intent resolusi izin OAuth), operasi koneksi klien akan gagal. Saat menggunakan koneksi yang dikelola secara otomatis, GoogleApiClient akan mencoba menyelesaikan error tersebut jika memungkinkan. Saat menggunakan koneksi yang dikelola secara manual, ConnectionResult yang berisi intent resolusi akan dikirim ke callback onConnectionFailed(). Kegagalan koneksi API hanya diabaikan jika tidak ada resolusi untuk kegagalan tersebut dan API ditambahkan dengan addApiIfAvailable(). Untuk mempelajari cara menerapkan penanganan kegagalan koneksi manual, lihat Menangani kegagalan koneksi.

Karena API yang ditambahkan dengan addApiIfAvailable() mungkin tidak selalu ada di instance GoogleApiClient yang terhubung, Anda harus menjaga panggilan ke API ini dengan menambahkan pemeriksaan menggunakan hasConnectedApi(). Untuk mengetahui alasan API tertentu gagal terhubung saat seluruh operasi koneksi berhasil untuk klien, panggil getConnectionResult() dan dapatkan kode error dari objek ConnectionResult. Jika klien Anda memanggil API saat tidak terhubung ke klien, panggilan akan gagal dengan kode status API_NOT_AVAILABLE.

Jika API yang Anda tambahkan melalui addApiIfAvailable() memerlukan satu atau beberapa cakupan, tambahkan cakupan tersebut sebagai parameter dalam panggilan metode addApiIfAvailable(), bukan dengan menggunakan metode addScope(). Cakupan yang ditambahkan menggunakan pendekatan ini mungkin tidak diminta jika koneksi API gagal sebelum mendapatkan izin OAuth, sedangkan cakupan yang ditambahkan dengan addScope() selalu diminta.

Koneksi yang dikelola secara manual

Sebagian besar panduan ini menunjukkan cara menggunakan metode enableAutoManage untuk memulai koneksi yang dikelola secara otomatis dengan error yang di-resolve secara otomatis. Dalam hampir semua kasus, ini adalah cara terbaik dan termudah untuk terhubung ke Google API dari aplikasi Android Anda. Namun, ada beberapa situasi saat Anda ingin menggunakan koneksi yang dikelola secara manual ke Google API di aplikasi Anda:

  • Untuk mengakses Google API di luar aktivitas atau mempertahankan kontrol koneksi API
  • Untuk menyesuaikan penanganan dan penyelesaian error koneksi

Bagian ini memberikan contoh kasus penggunaan lanjutan ini dan lainnya.

Memulai koneksi yang dikelola secara manual

Untuk memulai koneksi yang dikelola secara manual ke GoogleApiClient, Anda harus menentukan implementasi untuk antarmuka callback, ConnectionCallbacks dan OnConnectionFailedListener. Antarmuka ini menerima callback sebagai respons terhadap metode connect() asinkron saat koneksi ke layanan Google Play berhasil, gagal, atau ditangguhkan.

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

Saat mengelola koneksi secara manual, Anda harus memanggil metode connect() dan disconnect() pada titik yang tepat dalam siklus proses aplikasi. Dalam konteks aktivitas, praktik terbaiknya adalah memanggil connect() dalam metode onStart() aktivitas dan disconnect() dalam metode onStop() aktivitas. Metode connect() dan disconnect() dipanggil secara otomatis saat menggunakan koneksi yang dikelola secara otomatis.

Jika Anda menggunakan GoogleApiClient untuk terhubung ke API yang memerlukan autentikasi, seperti Google Drive atau Google Play Game, kemungkinan besar upaya koneksi pertama Anda akan gagal dan aplikasi Anda akan menerima panggilan ke onConnectionFailed() dengan error SIGN_IN_REQUIRED karena akun pengguna tidak ditentukan.

Menangani kegagalan koneksi

Saat aplikasi menerima panggilan ke callback onConnectionFailed(), Anda harus memanggil hasResolution() pada objek ConnectionResult yang disediakan. Jika menampilkan true, aplikasi Anda dapat meminta pengguna untuk segera mengambil tindakan guna menyelesaikan error dengan memanggil startResolutionForResult() pada objek ConnectionResult. Metode startResolutionForResult() berperilaku sama seperti startActivityForResult() dalam situasi ini, dan meluncurkan aktivitas yang sesuai dengan konteks yang membantu pengguna menyelesaikan error (seperti aktivitas yang membantu pengguna memilih akun).

Jika hasResolution() menampilkan nilai salah (false), aplikasi Anda harus memanggil GoogleApiAvailability.getErrorDialog(), yang meneruskan kode error ke metode ini. Tindakan ini akan menampilkan Dialog yang disediakan oleh layanan Google Play yang sesuai dengan error. Dialog mungkin hanya memberikan pesan yang menjelaskan error, atau juga dapat memberikan tindakan untuk meluncurkan aktivitas yang dapat menyelesaikan error (seperti saat pengguna perlu menginstal layanan Google Play versi yang lebih baru).

Misalnya, metode callback onConnectionFailed() Anda sekarang akan terlihat seperti ini:

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

Setelah pengguna menyelesaikan dialog yang disediakan oleh startResolutionForResult() atau menutup pesan yang disediakan oleh GoogleApiAvailability.getErrorDialog(), aktivitas Anda akan menerima callback onActivityResult() dengan kode hasil RESULT_OK. Kemudian, aplikasi Anda dapat memanggil connect() lagi. Contoh:

@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();
            }
        }
    }
}

Dalam kode di atas, Anda mungkin melihat boolean, mResolvingError. Hal ini melacak status aplikasi saat pengguna menyelesaikan error untuk menghindari upaya berulang dalam menyelesaikan error yang sama. Misalnya, saat dialog pemilih akun ditampilkan untuk membantu pengguna mengatasi error SIGN_IN_REQUIRED, pengguna dapat memutar layar. Tindakan ini akan membuat ulang aktivitas Anda dan menyebabkan metode onStart() dipanggil lagi, yang kemudian memanggil connect() lagi. Hal ini menghasilkan panggilan lain ke startResolutionForResult(), yang membuat dialog pemilih akun lain di depan dialog yang ada.

Boolean ini berfungsi sesuai tujuannya hanya jika tetap ada di seluruh instance aktivitas. Bagian berikutnya menjelaskan cara mempertahankan status penanganan error aplikasi Anda meskipun ada tindakan atau peristiwa pengguna lain yang terjadi di perangkat.

Mempertahankan status saat menyelesaikan error

Untuk menghindari eksekusi kode di onConnectionFailed() saat upaya sebelumnya untuk mengatasi error sedang berlangsung, Anda harus mempertahankan boolean yang melacak apakah aplikasi Anda sudah mencoba mengatasi error.

Seperti yang ditunjukkan dalam contoh kode di atas, aplikasi Anda harus menetapkan boolean ke true setiap kali memanggil startResolutionForResult() atau menampilkan dialog dari GoogleApiAvailability.getErrorDialog(). Kemudian, saat aplikasi Anda menerima RESULT_OK dalam callback onActivityResult(), tetapkan boolean ke false.

Untuk melacak boolean di seluruh aktivitas yang dimulai ulang (seperti saat pengguna memutar layar), simpan boolean dalam data instance tersimpan aktivitas menggunakan 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);
}

Kemudian, pulihkan status yang disimpan selama onCreate():

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

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

Sekarang Anda siap menjalankan aplikasi dengan aman dan terhubung ke layanan Google Play secara manual.