این راهنما نحوه راهاندازی یک برنامه ساده اندروید را که درخواستهایی را به API داده یوتیوب ارسال میکند، توضیح میدهد.
پیشنیازها
برای اجرای این شروع سریع، به موارد زیر نیاز دارید:
- اندروید استودیو SDK نسخه ۱.۲ یا بالاتر .
- بستههای SDK اندروید برای API 23 یا بالاتر، شامل آخرین نسخههای مخزن گوگل، کتابخانه پشتیبانی اندروید و سرویسهای گوگل پلی.
- دسترسی به اینترنت در دستگاه آزمایشی شما.
- یک حساب گوگل.
این راهنمای سریع فرض میکند که شما از محیط توسعه یکپارچه اندروید استودیو (برخلاف ابزارهای SDK مستقل) استفاده میکنید و در یافتن، ایجاد و ویرایش فایلها در یک پروژه استودیو مشکلی ندارید.
مرحله ۱: دریافت اثر انگشت SHA1
در یک ترمینال، دستور Keytool زیر را اجرا کنید تا اثر انگشت SHA1 مورد استفاده برای فعال کردن API را دریافت کنید.
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v
وقتی از شما رمز عبور keystore خواسته شد، «android» را وارد کنید.
ابزار کلید، اثر انگشت را روی پوسته چاپ میکند. برای مثال:
$ 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
اثر انگشت SHA1 را که در مثال بالا هایلایت شده است، کپی کنید.
مرحله ۲: فعال کردن API داده یوتیوب
از این ویزارد برای ایجاد یا انتخاب یک پروژه در کنسول توسعهدهندگان گوگل و فعال کردن خودکار API استفاده کنید. روی ادامه کلیک کنید، سپس به اعتبارنامهها بروید .
در صفحه ایجاد اعتبارنامه ، روی دکمه لغو کلیک کنید.
در بالای صفحه، برگهی «رضایت OAuth» را انتخاب کنید. یک آدرس ایمیل انتخاب کنید، اگر نام محصول از قبل تعیین نشده است، آن را وارد کنید و روی دکمهی «ذخیره» کلیک کنید.
برگه اعتبارنامهها را انتخاب کنید، روی دکمه ایجاد اعتبارنامهها کلیک کنید و شناسه کلاینت OAuth را انتخاب کنید.
- نوع برنامه را اندروید انتخاب کنید.
- اثر انگشت SHA1 را از مرحله 1 در فیلد اثر انگشت Signing-certificate کپی کنید.
- در فیلد نام بسته ،
com.example.quickstartرا وارد کنید. - روی دکمهی ایجاد کلیک کنید.
مرحله ۳: ایجاد یک پروژه جدید اندروید
- اندروید استودیو را باز کنید و یک پروژه جدید اندروید استودیو ایجاد کنید.
- در صفحه پروژه جدید ، نام برنامه را "Quickstart" بگذارید.
- دامنه شرکت را روی "example.com" تنظیم کنید و تأیید کنید که نام بستهای که بهطور خودکار تولید میشود با نامی که در مرحله 2 در کنسول توسعهدهندگان وارد کردهاید، مطابقت داشته باشد. روی بعدی کلیک کنید.
- در صفحه Target Android Devices ، گزینه Phone and Tablet را تیک بزنید و Minimum SDK را برابر با "API 14: Android 4.0 (IceCreamSandwich)" انتخاب کنید. سایر گزینهها را بدون تیک بگذارید. روی Next کلیک کنید.
- در صفحه افزودن فعالیت به موبایل ، روی «افزودن بدون فعالیت» کلیک کنید.
- روی پایان کلیک کنید.
در این مرحله، اندروید استودیو پروژه را ایجاد و باز میکند.
مرحله ۴: آمادهسازی پروژه
نوار کناری پروژه، فهرستی قابل گسترش از فایلهای پیشفرض پروژه است که اندروید استودیو ایجاد کرده است. در آن فهرست، فهرست اسکریپتهای Gradle را گسترش دهید و فایل build.gradle را که با ماژول "app" (نه پروژه) مرتبط است، باز کنید.
فایل
build.gradleبرنامه را باز کنید و محتویات آن را با موارد زیر جایگزین کنید:در نوار ابزار، Tools > Android > Sync Project with Gradle Files را انتخاب کنید. این کار کتابخانههای مورد نیاز پروژه شما را دریافت و در دسترس قرار میدهد.
فایل پیشفرض
src/main/AndroidManifest.xmlرا پیدا کرده و باز کنید. در نوار کناری پروژه، این فایل در پوشهappو سپس در پوشهmanifestsقرار دارد. محتوای فایل را با کد زیر جایگزین کنید:<?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>
مرحله ۵: نمونه را تنظیم کنید
یک کلاس جاوا جدید ایجاد کنید. برای انجام این کار، ابتدا پوشه java را در نوار کناری پروژه انتخاب کنید. این پوشه در گروه فایلهای app ظاهر میشود. پس از کلیک روی پوشه، میتوانید.../app/src/main/java را انتخاب کنید.
نام کلاس را "MainActivity" بگذارید و روی OK کلیک کنید. محتویات فایل جدید را با کد زیر جایگزین کنید.
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."); } } } }
مرحله ۶: اجرای برنامه
- برای آزمایش برنامه، روی گزینه منو Run > Run app کلیک کنید.
- از شما خواسته میشود که یک دستگاه متصل (توصیه شده) یا یک شبیهساز برای اجرای برنامه انتخاب کنید. اگر برنامه را روی یک شبیهساز اجرا میکنید، مطمئن شوید که برای استفاده از یکی از تصاویر سیستمی با APIهای گوگل پیکربندی شده است. اگر سعی کنید Quickstart را روی دستگاهی اجرا کنید که در حال حاضر سرویسهای Google Play روی آن نصب نشده است، Quickstart یک کادر محاورهای ایجاد میکند که میتوانید از طریق آن برنامه را نصب کنید.
- اگر روی یک شبیهساز اجرا میشود، اجازه دهید کاملاً راهاندازی شود و اتصال شبکه خود را برقرار کند.
- اگر برای اولین بار است که شبیهساز را اجرا میکنید، ممکن است لازم باشد قفل صفحه آن را باز کنید. در هر صورت، برنامه شروع سریع باید به طور خودکار اجرا شود.
- اولین باری که برنامه را اجرا میکنید، از شما خواسته میشود که یک حساب کاربری مشخص کنید. برای انتخاب یک حساب کاربری برای اتصال، مراحل ورود به سیستم را تکمیل کنید.
- پس از انتخاب یک حساب کاربری، برنامه از شما میخواهد که دسترسی را تأیید کنید. برای تأیید، روی تأیید کلیک کنید.
یادداشتها
- اطلاعات مجوز در برنامه ذخیره میشود، بنابراین اجراهای بعدی نیازی به مجوز ندارند.
مطالعه بیشتر
- مستندات راهنمای کنسول توسعهدهندگان گوگل
- کلاینت APIهای گوگل برای مستندسازی جاوا
- راهنماهای API اندروید
- سرویسهای گوگل پلی
- مستندات مرجع API دادههای یوتیوب
عیبیابی
اپلیکیشن اندروید ثبت نشده
وقتی کادر محاورهای OAuth حاوی ورودی با عنوان "Unregistered Android application" باشد، به این معنی است که شناسه کلاینت OAuth2 که در مرحله 2 ایجاد کردهاید، پیدا نمیشود و اندروید به یک کلاینت پیشفرض برمیگردد. کلاینت پیشفرض برای استفاده از این API پیکربندی نشده است، بنابراین درخواستها با خطاهایی مانند accessNotConfigured. این خطاها ممکن است به شماره پروژه پیشفرض 608941808256 نیز اشاره داشته باشند.
برای رفع مشکل، مطمئن شوید که اثر انگشت SHA1 که در مرحله 1 بازیابی کردهاید و applicationId ذکر شده در فایل build.gradle شما دقیقاً با مقادیری که در کنسول Google Developers تنظیم کردهاید، مطابقت دارند.