In diesem Leitfaden wird erläutert, wie du eine einfache Android-App einrichtest, die Anfragen an die YouTube Data API sendet.
Voraussetzungen
Zum Ausführen dieser Kurzanleitung benötigen Sie Folgendes:
- Android Studio SDK 1.2 oder höher
- Android SDK-Pakete für API 23 oder höher, einschließlich der aktuellen Versionen des Google Repositorys, der Android-Supportbibliothek und der Google Play-Dienste
- Internetzugriff auf dem Testgerät.
- Ein Google-Konto.
In dieser Kurzanleitung wird davon ausgegangen, dass Sie die Android Studio IDE (nicht die eigenständigen SDK-Tools) verwenden und mit dem Finden, Erstellen und Bearbeiten von Dateien in einem Studio-Projekt vertraut sind.
Schritt 1: SHA1-Fingerabdruck abrufen
Führen Sie in einem Terminal den folgenden Befehl Keytool utility aus, um den SHA1-Fingerabdruck abzurufen, mit dem Sie die API aktivieren.
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v
Wenn Sie nach einem Schlüsselspeicherpasswort gefragt werden, geben Sie „android“ ein.
Das Keytool gibt den Fingerabdruck in der Shell aus. Beispiel:
$ 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
Kopieren Sie den SHA1-Fingerabdruck, der im obigen Beispiel hervorgehoben ist.
Schritt 2: YouTube Data API aktivieren
-
Verwenden Sie diesen Assistenten, um ein Projekt in der Google Developers Console zu erstellen oder auszuwählen und die API automatisch zu aktivieren. Klicken Sie auf Weiter und dann auf Zu den Anmeldedaten.
-
Klicken Sie auf der Seite Anmeldedaten erstellen auf Abbrechen.
-
Klicken Sie oben auf der Seite auf den Tab OAuth-Zustimmungsbildschirm. Wählen Sie eine E-Mail-Adresse aus, geben Sie einen Produktnamen ein, falls noch nicht festgelegt, und klicken Sie auf die Schaltfläche Speichern.
-
Wählen Sie den Tab Anmeldedaten aus, klicken Sie auf die Schaltfläche Anmeldedaten erstellen und wählen Sie OAuth-Client-ID aus.
- Wählen Sie den Anwendungstyp Android aus.
- Kopieren Sie den SHA1-Fingerabdruck aus Schritt 1 in das Feld Signaturzertifikat-Fingerabdruck.
- Geben Sie im Feld Paketname
com.example.quickstart
ein. - Klicken Sie auf Erstellen.
Schritt 3: Neues Android-Projekt erstellen
- Öffnen Sie Android Studio und starten Sie ein neues Android Studio-Projekt.
- Nennen Sie die Anwendung im Bildschirm Neues Projekt „Kurzanleitung“.
- Setzen Sie die Unternehmensdomain auf „example.com“ und prüfen Sie, ob der automatisch generierte Paketname mit dem übereinstimmt, den Sie in Schritt 2 in der Developer Console eingegeben haben. Klicken Sie auf Weiter.
- Klicken Sie auf dem Bildschirm Ziel-Android-Geräte das Kästchen Smartphone und Tablet an und wählen Sie als Mindest-SDK „API 14: Android 4.0 (IceCreamSandwich)“ aus. Lassen Sie die anderen Kontrollkästchen deaktiviert. Klicken Sie auf Weiter.
- Klicken Sie auf dem Bildschirm Aktivität auf Mobilgeräten hinzufügen auf Keine Aktivität hinzufügen.
- Klicken Sie auf Fertig.
An dieser Stelle wird das Projekt in Android Studio erstellt und geöffnet.
Schritt 4: Projekt vorbereiten
Die Projektseitenleiste ist eine maximierbare Liste der Standardprojektdateien, die von Android Studio erstellt wurden. Maximieren Sie in dieser Liste die Liste der Gradle-Skripts und öffnen Sie die Datei build.gradle
, die mit dem Modul „app“ (nicht dem Projekt) verknüpft ist.
- Öffnen Sie die Datei
build.gradle
der App und ersetzen Sie den Inhalt durch Folgendes: - Wählen Sie in der Symbolleiste Tools > Android > Projekt mit Gradle-Dateien synchronisieren aus. Dadurch werden die Bibliotheken erworben und zur Verfügung gestellt, die für Ihr Projekt erforderlich sind.
- Suchen und öffnen Sie die Standarddatei
src/main/AndroidManifest.xml
. In der Projektseitenleiste ist diese Datei unterapp
und dann untermanifests
verschachtelt. Ersetzen Sie den Inhalt der Datei durch den folgenden Code:<?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>
Schritt 5: Beispiel einrichten
Erstellen Sie eine neue Java-Klasse. Wählen Sie dazu zuerst in der Projektseitenleiste den Ordner java
aus. Dieser Ordner wird in der Gruppe von app
Dateien angezeigt. Nachdem Sie auf den Ordner geklickt haben, können Sie in der Menüleiste .../app/src/main/java
aus.
Nennen Sie die Klasse „MainActivity“ und klicken Sie auf OK. Ersetzen Sie den Inhalt der neuen Datei durch den folgenden Code.
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."); } } } }
Schritt 6: Anwendung ausführen
- Klicken Sie zum Testen der App auf den Menüpunkt Ausführen > App ausführen.
- Sie werden aufgefordert, ein verbundenes Gerät (empfohlen) oder eine Emulation auszuwählen, auf der die App ausgeführt werden soll. Wenn Sie eine Emulation ausführen, muss sie für die Verwendung eines der System-Images mit Google APIs konfiguriert sein. Wenn Sie versuchen, die Kurzanleitung auf einem Gerät auszuführen, auf dem derzeit keine Google Play-Dienste installiert sind, wird ein Dialogfeld angezeigt, über das Sie sie installieren können.
- Wenn Sie ihn in einem Emulator ausführen, warten Sie, bis er vollständig gestartet und eine Netzwerkverbindung hergestellt werden kann.
- Wenn Sie den Emulator zum ersten Mal starten, müssen Sie möglicherweise seinen Bildschirm entsperren. Unabhängig davon sollte die Kurzanleitungs-App automatisch gestartet werden.
- Wenn Sie die Anwendung zum ersten Mal ausführen, werden Sie aufgefordert, ein Konto anzugeben. Schließen Sie den Anmeldevorgang ab, um ein Konto für die Verknüpfung auszuwählen.
- Nachdem Sie ein Konto ausgewählt haben, werden Sie in der App aufgefordert, den Zugriff zu autorisieren. Klicken Sie zum Autorisieren auf OK.
Hinweise
- Autorisierungsinformationen werden mit der Anwendung gespeichert, sodass nachfolgende Ausführungen nicht zur Autorisierung aufgefordert werden.
Weitere Informationen
- Google Developers Console-Hilfe
- Dokumentation zum Google APIs-Client für Java
- Android API-Leitfäden
- Google Play-Dienste
- Referenzdokumentation zur YouTube Data API
Fehlerbehebung
Nicht registrierte Android-App
Wenn das OAuth-Dialogfeld den Eintrag „Nicht registrierte Android-Anwendung“ enthält, bedeutet dies, dass die in Schritt 2 erstellte OAuth2-Client-ID nicht gefunden wurde und Android auf einen Standardclient zurückgreift. Der Standardclient wird nicht für die Verwendung dieser API konfiguriert. Daher schlagen Anfragen mit Fehlern wie accessNotConfigured.
fehl. In diesen Fehlern kann auch die Standardprojektnummer 608941808256
angegeben werden.
Sie können das Problem beheben, indem Sie dafür sorgen, dass der in Schritt 1 abgerufene SHA1-Fingerabdruck und der applicationId
in der Datei build.gradle
genau mit den Werten übereinstimmen, die Sie in der Google Developers Console festgelegt haben.