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:

  • Otomatis mengelola koneksi Anda ke layanan Google Play.
  • Melakukan panggilan API sinkron dan asinkron ke salah satu layanan Google Play.
  • Kelola koneksi Anda ke layanan Google Play secara manual 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 salah satu layanan Google Play yang tersedia seperti Google Play Game dan Google Drive.

Untuk memulai, Anda harus terlebih dahulu menginstal library layanan Google Play (revisi 15 atau yang lebih tinggi) untuk Android SDK Anda. 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 Anda menambahkan Wearable API bersama dengan API lain ke GoogleApiClient, Anda mungkin akan mengalami error koneksi klien di perangkat yang belum 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 implementasi untuk antarmuka OnConnectionFailedListener guna 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 diselesaikan (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 perlu mengetahui kapan koneksi yang dikelola secara otomatis dibuat atau ditangguhkan. Misalnya, jika aplikasi Anda melakukan panggilan untuk menulis data ke Google API, panggilan tersebut harus dipanggil hanya 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 memanggil onStart() dan terputus setelah memanggil onStop(). Aplikasi Anda dapat segera mulai membuat permintaan baca ke Google API setelah mem-build GoogleApiClient, tanpa perlu menunggu koneksi selesai.

Berkomunikasi dengan Layanan Google

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

Catatan: Sebelum melakukan panggilan ke layanan Google tertentu, Anda mungkin perlu mendaftarkan aplikasi Anda di Google Developers Console terlebih dahulu. Untuk mendapatkan petunjuk, baca 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 oleh 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 Anda memiliki objek PendingResult, aplikasi Anda kemudian 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 tidak. Setelah koneksi tersambung, 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() pada PendingResult dan sediakan implementasi antarmuka ResultCallback. Misalnya, berikut adalah permintaan yang dieksekusi 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 akan dikirim sebagai instance subclass yang sesuai seperti yang ditetapkan oleh API yang Anda gunakan, seperti DriveApi.MetadataBufferResult.

Menggunakan panggilan sinkron

Jika ingin kode Anda dieksekusi dalam urutan yang ditentukan secara ketat, mungkin karena hasil dari satu panggilan diperlukan sebagai argumen ke panggilan lainnya, Anda dapat membuat permintaan sinkron dengan memanggil await() pada 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() akan memblokir thread hingga hasil 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 {
    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 terdiri dari sekumpulan objek data yang dapat dikirim dan disinkronkan oleh sistem, dan 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 baru saat perangkat wearable terhubung dan aplikasi pendamping Wear OS diinstal di perangkat.

Menggunakan Wearable API secara mandiri

Jika aplikasi Anda menggunakan Wearable API, tetapi tidak API Google 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 ketersediaannya. Anda dapat menggunakan pemeriksaan ini untuk membantu aplikasi menangani dengan baik kasus saat API tidak tersedia.

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 dapat berhasil terhubung dengan Google Drive tanpa terhubung ke Wearable API jika tidak tersedia. Setelah Anda 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 berhasil terhubung ke API tersebut, seluruh operasi koneksi untuk klien tersebut akan gagal dan memicu callback onConnectionFailed().

Anda dapat mendaftarkan kegagalan koneksi API agar 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 Anda dan klien akan melanjutkan koneksi ke API lain. Namun, jika koneksi API gagal dengan error yang dapat dipulihkan (seperti intent resolusi izin OAuth), operasi client connect akan gagal. Saat menggunakan koneksi yang terkelola secara otomatis, GoogleApiClient akan mencoba menyelesaikan error tersebut jika memungkinkan. Saat menggunakan koneksi yang dikelola secara manual, ConnectionResult yang berisi intent resolusi dikirimkan ke callback onConnectionFailed(). Kegagalan koneksi API hanya diabaikan jika tidak ada penyelesaian untuk kegagalan tersebut dan API telah ditambahkan dengan addApiIfAvailable(). Untuk mempelajari cara mengimplementasikan penanganan kegagalan koneksi manual, lihat Menangani kegagalan koneksi.

Karena API yang ditambahkan dengan addApiIfAvailable() mungkin tidak selalu ada dalam 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 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 perlu 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 resolusi error koneksi

Bagian ini memberikan contoh kasus penggunaan tersebut dan kasus penggunaan lanjutan 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 Anda dan disconnect() dalam metode onStop() aktivitas Anda. 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, ada kemungkinan besar percobaan 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 nilai benar (true), aplikasi dapat meminta pengguna segera mengambil tindakan untuk 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 mengatasi error (seperti aktivitas yang membantu pengguna untuk memilih akun).

Jika hasResolution() menampilkan nilai salah, aplikasi Anda harus memanggil GoogleApiAvailability.getErrorDialog(), dan meneruskan kode error ke metode ini. Tindakan ini akan menampilkan Dialog yang disediakan oleh layanan Google Play yang sesuai dengan error yang terjadi. 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 versi layanan Google Play 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 menolak pesan yang diberikan oleh GoogleApiAvailability.getErrorDialog(), aktivitas Anda akan menerima callback onActivityResult() dengan kode hasil RESULT_OK. Selanjutnya, 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 dapat melacak status aplikasi saat pengguna menyelesaikan error untuk menghindari upaya berulang guna menyelesaikan error yang sama. Misalnya, saat dialog pemilih akun ditampilkan untuk membantu pengguna menyelesaikan 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 yang sudah ada.

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

Mempertahankan status saat menyelesaikan error

Untuk menghindari eksekusi kode di onConnectionFailed() saat upaya sebelumnya untuk menyelesaikan error sedang berlangsung, Anda harus mempertahankan boolean yang melacak apakah aplikasi Anda sudah mencoba menyelesaikan 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 menerima RESULT_OK di callback onActivityResult(), tetapkan boolean ke false.

Untuk terus melacak boolean saat aktivitas dimulai ulang (misalnya ketika pengguna merotasi 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 tersimpan selama onCreate():

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

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

Kini Anda siap untuk menjalankan aplikasi dengan aman dan menghubungkan ke layanan Google Play secara manual.