2013-08-02 52 views
5

Tôi đang làm việc trên ứng dụng Android ghi video và cho phép người dùng tải video trực tiếp lên YouTube bằng API dữ liệu YouTube v3.Video tải lên YouTube API 3 - Quyền truy cập không được định cấu hình - Android

Tôi đã thiết lập ứng dụng của mình trong bảng điều khiển API của Google. Theo dịch vụ, tôi đã bật API dữ liệu YouTube v3. Trong quyền truy cập API, tôi có cả phần "ID ứng dụng cho ứng dụng đã cài đặt" (bao gồm ID ứng dụng khách và Bí mật ứng dụng khách) và phần "Truy cập API đơn giản" -> "Khóa cho ứng dụng Android (có chứng chỉ)" (bao gồm khóa API và một phần "Ứng dụng Android", để trống bây giờ, tức là cho phép tất cả các ứng dụng Android, nhưng tôi đã thử bằng cách đặt khóa android của mình).

Tôi đã dựa mã của tôi từ một số nơi, chủ yếu là:

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

Việc tải initialises OK, bắt đầu AsyncTask, nhưng sau đó tôi nhận được một IOException ném câu nói:

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

SO bài viết tương tự cho thấy nó là để làm với các thiết lập giao diện điều khiển API Google của tôi, nhưng tôi không thể tìm thấy bất cứ điều gì sai trái. Bất kỳ đề xuất? Tôi tự hỏi nếu đó là vì tôi không cung cấp ID khách hàng hoặc bí mật ở bất cứ đâu ...

Cảm ơn.

Mã của tôi chạy từ một đoạn có chứa danh sách video. Các phần liên quan là:

- Init

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<String> 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; 

- Cài đặt chứng chỉ và youtube

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

- Mở nút nhấp chuột, bắt đầu upload

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

     ... 
    } 

- Xây dựng thông tin xác thực

/** 
    * 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<String> scopes) throws Exception { 
     credential = GoogleAccountCredential.usingOAuth2(context, scopes) 
      .setSelectedAccountName(PreferenceManager.getAccountName()); 
     return credential; 
    } 

- Yêu cầu một tài khoản từ người sử dụng

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

- Khi trở về từ người dùng lựa chọn và chiếm -/đề nghị cấp phép

/** 
    * 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; 
     } 
    } 

- Được gọi là nhiều lần tùy thuộc vào những gì thông tin chúng tôi có - tài khoản, ủy quyền, v.v.

/** 
    * 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); 
     } 
    } 

- Chuẩn bị tải lên - Đặt tất cả mọi thứ cùng nhau

/** 
    * 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<String> tags = new ArrayList<String>(); 
      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; 
     } 
    } 

- Yêu cầu Dịch vụ 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 chạy thực thi trên tải lên

public class VideoUploadAsyncTask extends AsyncTask<Insert, Void, Void> { 
     @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; 
     } 
    } 

} 
+0

Các câu hỏi liên quan được đưa ra bởi SO đã chỉ cho tôi https://github.com/youtube/ytd-android, tôi sẽ xem chi tiết hơn, nhưng thoạt nhìn, có vẻ như chúng tôi đang sử dụng một phương pháp rất giống nhau . –

+0

Xin chào, bạn có thể đăng toàn bộ mã để tham khảo không? –

+0

Tôi nhầm lẫn với "Khóa API Android" được viết trong trang chủ của dự án. Điều đó có nghĩa là "Client ID cho ứng dụng Android"? –

Trả lời

3

Câu trả lời được cung cấp bởi @Ibrahim gần như chính xác đối với tôi. Những gì tôi cần làm là chỉnh sửa cấu hình API của mình. Tuy nhiên, đó không phải là phần "Truy cập API đơn giản" mà tôi cần chỉnh sửa, đó là cài đặt sau khi nhấp vào nút "Tạo một Id ứng dụng khách khác".

Sau đó, tôi có thể chọn "Ứng dụng đã cài đặt" -> "Android". Sau khi nhập tên gói và SHA1 của tôi và chờ 15 phút, ứng dụng của tôi hoạt động như mong đợi. Tôi cũng đã thiết lập "Truy cập API đơn giản". Tôi không chắc bạn có cần cả hai hay không.

+0

Xin chào Jon G, tôi không hiểu bạn có thể giải thích rõ ràng những gì bạn đã làm. bởi vì tôi có cùng một vấn đề liên quan đến việc xác thực trong ứng dụng của tôi. Cảm ơn trước – siva

2

Vâng, YouTube Direct Lite dành cho Android cũng tương tự. Bạn phải định cấu hình truy cập API đơn giản bằng khóa SHA1 của mình. Explains here.

+0

Cảm ơn câu trả lời của bạn @Ibrahim. Tôi đã cho rằng một thử, và đôi kiểm tra bây giờ ... nó dường như không tạo ra một sự khác biệt. Tôi đã tạo khóa SHA1 và thêm khóa đó vào bảng điều khiển API của mình là: khóa; com.bla.bla.myapp –

+0

Khi bạn cập nhật bảng điều khiển, hãy cung cấp 15 phút hoặc lâu hơn. –

+0

Vẫn không có may mắn @Ibrahim. Tôi nhận thấy rằng không có nơi nào trong mã của tôi để tôi sử dụng khóa API của mình ... Trong lần thử trước, tôi đã sử dụng "YouTubeRequestInitializer" thay vì "GoogleAccountCredential" để khởi tạo đối tượng YouTube của tôi, lấy khóa API làm đầu vào. Tôi có nên bao gồm khóa API ở đâu đó trong GoogleAccountCredential không? –