YouTube API 3 Загрузка видео – доступ не настроен – Android

Я работаю над Android-приложением, которое записывает видео и позволяет пользователю загружать его прямо на YouTube с помощью API данных YouTube версии 3.

Я установил свое приложение в консоли API Google. В рамках служб у меня включен API данных YouTube v3. При доступе к API у меня есть и раздел «Идентификатор клиента для установленных приложений» (включая идентификатор клиента и секрет клиента), так и раздел «Простой доступ к API» -> «Ключ для приложений Android (с сертификатами)» (который включает в себя ключ API и раздел «Приложения для Android», который сейчас остается пустым, то есть разрешить все приложения для Android, но я попробовал его с настройкой моего андроида).

Я основывал свой код на нескольких местах, в первую очередь:

https://developers.google.com/youtube/v3/code_samples/java#upload_a_video

а также

https://code.google.com/p/google-api-java-client/source/browse/tasks-android-sample/src/main/java/com/google/api/services/samples/tasks/android/ TasksSample.java?repo=samples

Загрузка инициализирует OK, запускает AsyncTask, но затем я получаю сообщение об ошибке IOException:

{ "code": 403, "errors": [ { "domain": "usageLimits", "message": "Access Not Configured", "reason": "accessNotConfigured" } ], "message": "Access Not Configured" } 

Подобные сообщения SO предполагают, что это связано с настройками консоли Google API, но я не могу найти ничего плохого. Какие-либо предложения? Интересно, если это потому, что я не предоставляю свой идентификатор клиента или секрет где-нибудь …

Благодарю.

Мой код запускается из fragmentа, содержащего список видео. Соответствующие разделы:

— В этом

 public class UploadFragment extends Fragment { private static GoogleAccountCredential credential; private static final HttpTransport transport = AndroidHttp.newCompatibleTransport(); private static final JsonFactory jsonFactory = new GsonFactory(); public YouTube youtube; List scopes = Lists.newArrayList(YouTubeScopes.YOUTUBE_UPLOAD); private static String VIDEO_FILE_FORMAT = "video/*"; static final int REQUEST_GOOGLE_PLAY_SERVICES = 0; static final int REQUEST_AUTHORIZATION = 1; static final int REQUEST_ACCOUNT_PICKER = 2; 

– Настройка учетных данных и youtube

  @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ... credential = googleAccountCredential(scopes); youtube = new YouTube.Builder(transport, jsonFactory, credential) .setApplicationName("MyAppName") .build(); ... } 

– При нажатии кнопки инициировать загрузку

  @Override void onClick(View v) { ... if (hasGooglePlayServices()) { uploadYouTubeVideos(); ... } 

– Создайте учетные данные

  /** * Get the credential to authorize the installed application to access user's protected data. * * @param scopes list of scopes needed to run YouTube upload. */ private static GoogleAccountCredential googleAccountCredential(List scopes) throws Exception { credential = GoogleAccountCredential.usingOAuth2(context, scopes) .setSelectedAccountName(PreferenceManager.getAccountName()); return credential; } 

– Запросить учетную запись у пользователя

  /** * Fire intent to get user to choose account * Return to onActivityResult */ private void chooseAccount() { startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER); } 

– При возврате от пользователя, выбирающего и учетной записи – / запрашивая авторизацию

  /** * Returns from chooseAccount and from request authorization */ @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQUEST_AUTHORIZATION: if (resultCode == Activity.RESULT_OK) { uploadYouTubeVideos(); } else { chooseAccount(); } break; case REQUEST_ACCOUNT_PICKER: if (resultCode == Activity.RESULT_OK && data != null && data.getExtras() != null) { String accountName = data.getExtras().getString(AccountManager.KEY_ACCOUNT_NAME); if (accountName != null) { credential.setSelectedAccountName(accountName); PreferenceManager.setAccountName(accountName); uploadYouTubeVideos(); } } break; } } 

– Вызывается несколько раз в зависимости от того, какая у нас информация – учетная запись, авторизация и т. Д.

  /** * Uploads user selected video to the user's YouTube account using OAuth2 * for authentication. * * @param videoFile file to be uploaded */ public void uploadYouTubeVideos() { if (credential.getSelectedAccountName() == null) { chooseAccount(); } else { File videoFile = getVideoFile(); Insert videoInsert = prepareUpload(videoFile); new VideoUploadAsyncTask().execute(videoInsert); } } 

– Подготовьте загрузку – Собирает все вместе

  /** * Prepare upload. Just leaves execute to be run in AsyncTask. * * @param videoFile file to be uploaded * @return */ public Insert prepareUpload( File videoFile ) { try { // Add extra information to the video before uploading. Video videoObjectDefiningMetadata = new Video(); // Set the video to public (default). VideoStatus status = new VideoStatus(); status.setPrivacyStatus("public"); videoObjectDefiningMetadata.setStatus(status); // We set a majority of the metadata with the VideoSnippet object. VideoSnippet snippet = new VideoSnippet(); // Video file name. snippet.setTitle(videoFile.getName()); snippet.setDescription("Test description"); // Set keywords. List tags = new ArrayList(); tags.add("test"); snippet.setTags(tags); // Set completed snippet to the video object. videoObjectDefiningMetadata.setSnippet(snippet); InputStreamContent mediaContent = new InputStreamContent( VIDEO_FILE_FORMAT, new BufferedInputStream(new FileInputStream(videoFile))); mediaContent.setLength(videoFile.length()); /* * The upload command includes: 1. Information we want returned after file is successfully * uploaded. 2. Metadata we want associated with the uploaded video. 3. Video file itself. */ YouTube.Videos.Insert videoInsert = youtube.videos() .insert("snippet,statistics,status", videoObjectDefiningMetadata, mediaContent); // Set the upload type and add event listener. MediaHttpUploader uploader = videoInsert.getMediaHttpUploader(); /* * Sets whether direct media upload is enabled or disabled. True = whole media content is * uploaded in a single request. False (default) = resumable media upload protocol to upload * in data chunks. */ uploader.setDirectUploadEnabled(false); MediaHttpUploaderProgressListener progressListener = new MediaHttpUploaderProgressListener() { public void progressChanged(MediaHttpUploader uploader) throws IOException { switch (uploader.getUploadState()) { case INITIATION_STARTED: Log.d(TAG, "Upload file: Initiation Started"); break; case INITIATION_COMPLETE: Log.d(TAG, "Upload file: Initiation Completed"); break; case MEDIA_IN_PROGRESS: Log.d(TAG, "Upload file: Upload in progress"); Log.d(TAG, "Upload file: Upload percentage: " + uploader.getProgress()); break; case MEDIA_COMPLETE: Log.d(TAG, "Upload file: Upload Completed!"); break; case NOT_STARTED: Log.d(TAG, "Upload file: Upload Not Started!"); break; } } }; uploader.setProgressListener(progressListener); return videoInsert; } catch (FileNotFoundException e) { Log.e(TAG, "File not found: " + e.getMessage()); return null; } catch (IOException e) { Log.e(TAG, "IOException: " + e.getMessage()); return null; } } 

– Требовать сервисы Google Play

  /** * Pop up dialog requesting user to download Google Play Services. * Returns to onActivityResult */ void showGooglePlayServicesAvailabilityErrorDialog(final int connectionStatusCode) { getActivity().runOnUiThread(new Runnable() { public void run() { Dialog dialog = GooglePlayServicesUtil.getErrorDialog(connectionStatusCode, getActivity(), REQUEST_GOOGLE_PLAY_SERVICES); dialog.show(); } }); } 

– AsyncTask, который запускает выполнение при загрузке

  public class VideoUploadAsyncTask extends AsyncTask { @Override protected Void doInBackground( Insert... inserts ) { Insert videoInsert = inserts[0]; try { Video returnVideo = videoInsert.execute(); } catch (final GooglePlayServicesAvailabilityIOException availabilityException) { showGooglePlayServicesAvailabilityErrorDialog( availabilityException.getConnectionStatusCode()); } catch (UserRecoverableAuthIOException userRecoverableException) { startActivityForResult( userRecoverableException.getIntent(), UploadFragment.REQUEST_AUTHORIZATION); } catch (IOException e) { Log.e(TAG, "IOException: " + e.getMessage()); } return null; } } } 

Ответ, предоставленный @Ibrahim, был почти правильным для меня. Мне нужно было отредактировать мою конфигурацию API. Однако для редактирования мне не нужен раздел «Simple API access», это были настройки после нажатия кнопки «Создать другой идентификатор клиента».

Тогда я мог бы выбрать «Установленное приложение» -> «Android». После ввода имени моего пакета и SHA1 и ожидания 15 минут мое приложение работало так, как ожидалось. У меня также есть «Simple API access». Я не уверен, нужны ли вам оба или нет.

Да, YouTube Direct Lite для Android похож. Вам необходимо настроить простой доступ к API с помощью ключа SHA1. Объясняет здесь .