Panduan ini menjelaskan cara menyiapkan aplikasi Android sederhana yang membuat permintaan ke YouTube Data API.
Prasyarat
Untuk menjalankan quickstart ini, Anda memerlukan:
- Android Studio SDK 1.2 atau yang lebih baru.
- Paket Android SDK untuk API 23 atau yang lebih baru, termasuk Repositori Google versi terbaru, Android Support Library, dan Layanan Google Play.
- Akses ke internet di perangkat pengujian Anda.
- Akun Google.
Panduan memulai ini akan mengasumsikan bahwa Anda menggunakan IDE Android Studio (bukan Alat SDK mandiri) dan dapat menemukan, membuat, dan mengedit file dalam project Studio dengan mudah.
Langkah 1: Dapatkan sidik jari SHA1
Di terminal, jalankan perintah utilitas Keytool berikut untuk mendapatkan sidik jari SHA1 yang akan Anda gunakan untuk mengaktifkan API.
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v
Saat diminta memasukkan sandi keystore, masukkan "android".
Keytool mencetak sidik jari ke shell. Contoh:
$ keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v Enter keystore password: Type "android" if using debug.keystore Alias name: androiddebugkey Creation date: Dec 4, 2014 Entry type: PrivateKeyEntry Certificate chain length: 1 Certificate[1]: Owner: CN=Android Debug, O=Android, C=US Issuer: CN=Android Debug, O=Android, C=US Serial number: 503bd581 Valid from: Mon Aug 27 13:16:01 PDT 2012 until: Wed Aug 20 13:16:01 PDT 2042 Certificate fingerprints: MD5: 1B:2B:2D:37:E1:CE:06:8B:A0:F0:73:05:3C:A3:63:DD SHA1: D8:AA:43:97:59:EE:C5:95:26:6A:07:EE:1C:37:8E:F4:F0:C8:05:C8 SHA256: F3:6F:98:51:9A:DF:C3:15:4E:48:4B:0F:91:E3:3C:6A:A0:97:DC:0A:3F:B2:D2:E1:FE:23:57:F5:EB:AC:13:30 Signature algorithm name: SHA1withRSA Version: 3
Salin sidik jari SHA1, yang ditandai dalam contoh di atas.
Langkah 2: Aktifkan YouTube Data API
-
Gunakan wizard ini untuk membuat atau memilih project di Konsol Google Developers dan mengaktifkan API secara otomatis. Klik Lanjutkan, lalu Buka kredensial.
-
Di halaman Create credentials, klik tombol Cancel.
-
Di bagian atas halaman, pilih tab Layar persetujuan OAuth. Pilih Alamat email, masukkan Nama produk jika belum ditetapkan, lalu klik tombol Simpan.
-
Pilih tab Kredensial, klik tombol Buat kredensial, lalu pilih ID klien OAuth.
- Pilih jenis aplikasi Android.
- Salin sidik jari SHA1 dari Langkah 1 ke kolom Signing-certificate fingerprint.
- Di kolom Package name, masukkan
com.example.quickstart
. - Klik tombol Buat.
Langkah 3: Buat project Android baru
- Buka Android Studio, lalu mulai Project Android Studio Baru.
- Di layar New Project, beri nama aplikasi "Quickstart".
- Tetapkan Company Domain ke "example.com" dan pastikan nama paket yang dihasilkan secara otomatis cocok dengan nama yang Anda masukkan ke Developer Console di Langkah 2. Klik Next.
- Di layar Target Android Devices, centang kotak Phone and Tablet dan pilih Minimum SDK "API 14: Android 4.0 (IceCreamSandwich)". Biarkan kotak centang lainnya tidak dicentang. Klik Next.
- Di layar Tambahkan aktivitas ke Perangkat Seluler, klik Tambahkan Tidak Ada Aktivitas.
- Klik Selesai.
Pada tahap ini, Android Studio akan membuat dan membuka project.
Langkah 4: Siapkan project
Sidebar Project adalah daftar file project default yang dapat diperluas yang telah dibuat oleh
Android Studio. Dalam daftar tersebut, luaskan daftar skrip Gradle dan buka
file build.gradle
yang terkait dengan modul "aplikasi"
(bukan project).
- Buka file
build.gradle
aplikasi dan ganti kontennya dengan kode berikut: - Di toolbar, pilih Tools > Android > Sync Project with Gradle Files. Tindakan ini akan memperoleh dan menyediakan library yang diperlukan project Anda.
- Temukan dan buka file
src/main/AndroidManifest.xml
default. Di sidebar Project, file ini disusun bertingkat di bagianapp
, lalu di bagianmanifests
. Ganti konten file dengan kode berikut:<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.quickstart"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="YouTube Data API Android Quickstart" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="YouTube Data API Android Quickstart" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Langkah 5: Siapkan contoh aplikasi
Buat class Java baru. Untuk melakukannya, pilih folder java
terlebih dahulu di
sidebar Project. Folder ini muncul dalam grup file app
. Setelah
mengklik folder, Anda dapat memilih
.../app/src/main/java
.
Beri nama class "MainActivity", lalu klik OK. Ganti konten file baru dengan kode berikut.
package com.example.quickstart; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GoogleApiAvailability; import com.google.api.client.extensions.android.http.AndroidHttp; import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential; import com.google.api.client.googleapis.extensions.android.gms.auth.GooglePlayServicesAvailabilityIOException; import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException; import com.google.api.client.http.HttpTransport; import com.google.api.client.json.JsonFactory; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.client.util.ExponentialBackOff; import com.google.api.services.youtube.YouTubeScopes; import com.google.api.services.youtube.model.*; import android.Manifest; import android.accounts.AccountManager; import android.app.Activity; import android.app.Dialog; import android.app.ProgressDialog; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.NonNull; import android.text.TextUtils; import android.text.method.ScrollingMovementMethod; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import pub.devrel.easypermissions.AfterPermissionGranted; import pub.devrel.easypermissions.EasyPermissions; public class MainActivity extends Activity implements EasyPermissions.PermissionCallbacks { GoogleAccountCredential mCredential; private TextView mOutputText; private Button mCallApiButton; ProgressDialog mProgress; static final int REQUEST_ACCOUNT_PICKER = 1000; static final int REQUEST_AUTHORIZATION = 1001; static final int REQUEST_GOOGLE_PLAY_SERVICES = 1002; static final int REQUEST_PERMISSION_GET_ACCOUNTS = 1003; private static final String BUTTON_TEXT = "Call YouTube Data API"; private static final String PREF_ACCOUNT_NAME = "accountName"; private static final String[] SCOPES = { YouTubeScopes.YOUTUBE_READONLY }; /** * Create the main activity. * @param savedInstanceState previously saved instance data. */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout activityLayout = new LinearLayout(this); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); activityLayout.setLayoutParams(lp); activityLayout.setOrientation(LinearLayout.VERTICAL); activityLayout.setPadding(16, 16, 16, 16); ViewGroup.LayoutParams tlp = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); mCallApiButton = new Button(this); mCallApiButton.setText(BUTTON_TEXT); mCallApiButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mCallApiButton.setEnabled(false); mOutputText.setText(""); getResultsFromApi(); mCallApiButton.setEnabled(true); } }); activityLayout.addView(mCallApiButton); mOutputText = new TextView(this); mOutputText.setLayoutParams(tlp); mOutputText.setPadding(16, 16, 16, 16); mOutputText.setVerticalScrollBarEnabled(true); mOutputText.setMovementMethod(new ScrollingMovementMethod()); mOutputText.setText( "Click the \'" + BUTTON_TEXT +"\' button to test the API."); activityLayout.addView(mOutputText); mProgress = new ProgressDialog(this); mProgress.setMessage("Calling YouTube Data API ..."); setContentView(activityLayout); // Initialize credentials and service object. mCredential = GoogleAccountCredential.usingOAuth2( getApplicationContext(), Arrays.asList(SCOPES)) .setBackOff(new ExponentialBackOff()); } /** * Attempt to call the API, after verifying that all the preconditions are * satisfied. The preconditions are: Google Play Services installed, an * account was selected and the device currently has online access. If any * of the preconditions are not satisfied, the app will prompt the user as * appropriate. */ private void getResultsFromApi() { if (! isGooglePlayServicesAvailable()) { acquireGooglePlayServices(); } else if (mCredential.getSelectedAccountName() == null) { chooseAccount(); } else if (! isDeviceOnline()) { mOutputText.setText("No network connection available."); } else { new MakeRequestTask(mCredential).execute(); } } /** * Attempts to set the account used with the API credentials. If an account * name was previously saved it will use that one; otherwise an account * picker dialog will be shown to the user. Note that the setting the * account to use with the credentials object requires the app to have the * GET_ACCOUNTS permission, which is requested here if it is not already * present. The AfterPermissionGranted annotation indicates that this * function will be rerun automatically whenever the GET_ACCOUNTS permission * is granted. */ @AfterPermissionGranted(REQUEST_PERMISSION_GET_ACCOUNTS) private void chooseAccount() { if (EasyPermissions.hasPermissions( this, Manifest.permission.GET_ACCOUNTS)) { String accountName = getPreferences(Context.MODE_PRIVATE) .getString(PREF_ACCOUNT_NAME, null); if (accountName != null) { mCredential.setSelectedAccountName(accountName); getResultsFromApi(); } else { // Start a dialog from which the user can choose an account startActivityForResult( mCredential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER); } } else { // Request the GET_ACCOUNTS permission via a user dialog EasyPermissions.requestPermissions( this, "This app needs to access your Google account (via Contacts).", REQUEST_PERMISSION_GET_ACCOUNTS, Manifest.permission.GET_ACCOUNTS); } } /** * Called when an activity launched here (specifically, AccountPicker * and authorization) exits, giving you the requestCode you started it with, * the resultCode it returned, and any additional data from it. * @param requestCode code indicating which activity result is incoming. * @param resultCode code indicating the result of the incoming * activity result. * @param data Intent (containing result data) returned by incoming * activity result. */ @Override protected void onActivityResult( int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch(requestCode) { case REQUEST_GOOGLE_PLAY_SERVICES: if (resultCode != RESULT_OK) { mOutputText.setText( "This app requires Google Play Services. Please install " + "Google Play Services on your device and relaunch this app."); } else { getResultsFromApi(); } break; case REQUEST_ACCOUNT_PICKER: if (resultCode == RESULT_OK && data != null && data.getExtras() != null) { String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME); if (accountName != null) { SharedPreferences settings = getPreferences(Context.MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor.putString(PREF_ACCOUNT_NAME, accountName); editor.apply(); mCredential.setSelectedAccountName(accountName); getResultsFromApi(); } } break; case REQUEST_AUTHORIZATION: if (resultCode == RESULT_OK) { getResultsFromApi(); } break; } } /** * Respond to requests for permissions at runtime for API 23 and above. * @param requestCode The request code passed in * requestPermissions(android.app.Activity, String, int, String[]) * @param permissions The requested permissions. Never null. * @param grantResults The grant results for the corresponding permissions * which is either PERMISSION_GRANTED or PERMISSION_DENIED. Never null. */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); EasyPermissions.onRequestPermissionsResult( requestCode, permissions, grantResults, this); } /** * Callback for when a permission is granted using the EasyPermissions * library. * @param requestCode The request code associated with the requested * permission * @param list The requested permission list. Never null. */ @Override public void onPermissionsGranted(int requestCode, List<String> list) { // Do nothing. } /** * Callback for when a permission is denied using the EasyPermissions * library. * @param requestCode The request code associated with the requested * permission * @param list The requested permission list. Never null. */ @Override public void onPermissionsDenied(int requestCode, List<String> list) { // Do nothing. } /** * Checks whether the device currently has a network connection. * @return true if the device has a network connection, false otherwise. */ private boolean isDeviceOnline() { ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); return (networkInfo != null && networkInfo.isConnected()); } /** * Check that Google Play services APK is installed and up to date. * @return true if Google Play Services is available and up to * date on this device; false otherwise. */ private boolean isGooglePlayServicesAvailable() { GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance(); final int connectionStatusCode = apiAvailability.isGooglePlayServicesAvailable(this); return connectionStatusCode == ConnectionResult.SUCCESS; } /** * Attempt to resolve a missing, out-of-date, invalid or disabled Google * Play Services installation via a user dialog, if possible. */ private void acquireGooglePlayServices() { GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance(); final int connectionStatusCode = apiAvailability.isGooglePlayServicesAvailable(this); if (apiAvailability.isUserResolvableError(connectionStatusCode)) { showGooglePlayServicesAvailabilityErrorDialog(connectionStatusCode); } } /** * Display an error dialog showing that Google Play Services is missing * or out of date. * @param connectionStatusCode code describing the presence (or lack of) * Google Play Services on this device. */ void showGooglePlayServicesAvailabilityErrorDialog( final int connectionStatusCode) { GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance(); Dialog dialog = apiAvailability.getErrorDialog( MainActivity.this, connectionStatusCode, REQUEST_GOOGLE_PLAY_SERVICES); dialog.show(); } /** * An asynchronous task that handles the YouTube Data API call. * Placing the API calls in their own task ensures the UI stays responsive. */ private class MakeRequestTask extends AsyncTask<Void, Void, List<String>> { private com.google.api.services.youtube.YouTube mService = null; private Exception mLastError = null; MakeRequestTask(GoogleAccountCredential credential) { HttpTransport transport = AndroidHttp.newCompatibleTransport(); JsonFactory jsonFactory = JacksonFactory.getDefaultInstance(); mService = new com.google.api.services.youtube.YouTube.Builder( transport, jsonFactory, credential) .setApplicationName("YouTube Data API Android Quickstart") .build(); } /** * Background task to call YouTube Data API. * @param params no parameters needed for this task. */ @Override protected List<String> doInBackground(Void... params) { try { return getDataFromApi(); } catch (Exception e) { mLastError = e; cancel(true); return null; } } /** * Fetch information about the "GoogleDevelopers" YouTube channel. * @return List of Strings containing information about the channel. * @throws IOException */ private List<String> getDataFromApi() throws IOException { // Get a list of up to 10 files. List<String> channelInfo = new ArrayList<String>(); ChannelListResponse result = mService.channels().list("snippet,contentDetails,statistics") .setForUsername("GoogleDevelopers") .execute(); List<Channel> channels = result.getItems(); if (channels != null) { Channel channel = channels.get(0); channelInfo.add("This channel's ID is " + channel.getId() + ". " + "Its title is '" + channel.getSnippet().getTitle() + ", " + "and it has " + channel.getStatistics().getViewCount() + " views."); } return channelInfo; } @Override protected void onPreExecute() { mOutputText.setText(""); mProgress.show(); } @Override protected void onPostExecute(List<String> output) { mProgress.hide(); if (output == null || output.size() == 0) { mOutputText.setText("No results returned."); } else { output.add(0, "Data retrieved using the YouTube Data API:"); mOutputText.setText(TextUtils.join("\n", output)); } } @Override protected void onCancelled() { mProgress.hide(); if (mLastError != null) { if (mLastError instanceof GooglePlayServicesAvailabilityIOException) { showGooglePlayServicesAvailabilityErrorDialog( ((GooglePlayServicesAvailabilityIOException) mLastError) .getConnectionStatusCode()); } else if (mLastError instanceof UserRecoverableAuthIOException) { startActivityForResult( ((UserRecoverableAuthIOException) mLastError).getIntent(), MainActivity.REQUEST_AUTHORIZATION); } else { mOutputText.setText("The following error occurred:\n" + mLastError.getMessage()); } } else { mOutputText.setText("Request cancelled."); } } } }
Langkah 6: Jalankan aplikasi
- Untuk menguji aplikasi, klik item menu Run > Run app.
- Anda akan diminta untuk memilih perangkat yang terhubung (direkomendasikan) atau emulasi untuk menjalankan aplikasi. Jika Anda menjalankannya di emulasi, pastikan emulator tersebut dikonfigurasi untuk menggunakan salah satu image sistem dengan Google API. Jika Anda mencoba menjalankan panduan memulai di perangkat yang saat ini tidak menginstal layanan Google Play, panduan memulai akan menghasilkan dialog yang dapat Anda gunakan untuk menginstalnya.
- Jika berjalan di emulator, izinkan aplikasi untuk memulai sepenuhnya dan membuat koneksi jaringannya.
- Jika memulai emulator untuk pertama kalinya, Anda mungkin perlu membuka kunci layarnya. Apa pun yang terjadi, aplikasi memulai cepat akan dimulai secara otomatis.
- Saat pertama kali menjalankan aplikasi, Anda akan diminta untuk menentukan akun. Selesaikan alur login untuk memilih akun yang akan dihubungkan.
- Setelah memilih akun, aplikasi akan meminta Anda untuk memberikan otorisasi akses. Klik Oke untuk memberikan otorisasi.
Catatan
- Informasi otorisasi disimpan dengan aplikasi, sehingga eksekusi berikutnya tidak meminta otorisasi.
Bacaan lebih lanjut
- Dokumentasi bantuan Google Developers Console
- Dokumentasi Klien Google API untuk Java
- Panduan Android API
- Layanan Google Play
- Dokumentasi referensi YouTube Data API
Pemecahan masalah
Aplikasi Android tak terdaftar
Jika dialog OAuth berisi entri yang bertuliskan "Aplikasi Android
yang tidak terdaftar", artinya client ID OAuth2 yang Anda buat di Langkah 2 tidak dapat
ditemukan dan Android kembali ke klien default. Klien default
tidak akan dikonfigurasi untuk menggunakan API ini, sehingga permintaan gagal dengan error seperti
accessNotConfigured.
Error ini mungkin juga menyebutkan nomor project
default 608941808256
.
Untuk memperbaiki masalah ini, pastikan sidik jari SHA1 yang Anda ambil di Langkah 1
dan applicationId
yang tercantum dalam file build.gradle
cocok persis dengan
nilai yang Anda tetapkan di konsol Google Developers.