Я пытаюсь интегрировать API данных YouTube v3 в свое приложение android для загрузки видео на YouTube из моего приложения. Я следовал руководству разработчиков Google, но мне не удалось загрузить видео на YouTube из моего приложения. У меня нет ошибок, и мне не удалось загрузить видео. Я не понимаю, в чем проблема. Как найти проблему?
MainActivity. java
import pub.devrel.easypermissions.EasyPermissions;
public class MainActivity extends Activity
implements EasyPermissions.PermissionCallbacks {
GoogleAccountCredential mCredential;
private TextView mOutputText;
private Button mCallApiButton;
ProgressBar 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 int GALLERY_RETURN = 2;
private static final int CAPTURE_RETURN = 1;
String filePath = null;
private static final String TAG = "MainActivity";
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,YouTubeScopes.YOUTUBE_UPLOAD, YouTubeScopes.YOUTUBE_FORCE_SSL };
/**
* Create the main activity.
* @param savedInstanceState previously saved instance data.
*/
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCallApiButton = findViewById(R.id.mCallApiButton);
mOutputText = findViewById(R.id.mOutputText);
mProgress =findViewById(R.id.mProgressbar);
mCallApiButton.setText(BUTTON_TEXT);
mCallApiButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCallApiButton.setEnabled(false);
mOutputText.setText("");
getResultsFromApi();
mCallApiButton.setEnabled(true);
}
});
mOutputText.setText(
"Click the \'" + BUTTON_TEXT +"\' button to test the API.");
mOutputText.setVerticalScrollBarEnabled(true);
mOutputText.setMovementMethod(new ScrollingMovementMethod());
int d = Integer.parseInt("100");
mProgress.setProgress(d);
mProgress.setVisibility(View.INVISIBLE);
// Initialize credentials and service object.
mCredential = GoogleAccountCredential.usingOAuth2(
getApplicationContext(), Arrays.asList(SCOPES))
.setBackOff(new ExponentialBackOff());//Arrays.asList(SCOPES))
}
/**
* 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();
}*/
else {
// new SaveTokenAsync().execute();
mOutputText.setText("Credentials Initialized");
initVideoPicker();
}
}
/**
* 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;
case GALLERY_RETURN:
if (resultCode == RESULT_OK)
{
new UploadVideoAsync(data.getData()).execute();
}
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 = NetHttpTransport.
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
mService = new com.google.api.services.youtube.YouTube.Builder(
new NetHttpTransport(), 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();
//mProgress.isShown();
mProgress.setVisibility(View.VISIBLE);
}
@Override
protected void onPostExecute(List<String> output) {
//mProgress.hide();
mProgress.setVisibility(View.INVISIBLE);
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();
mProgress.setVisibility(View.INVISIBLE);
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.");
}
}
}
@SuppressLint("StaticFieldLeak")
public class UploadVideoAsync extends AsyncTask<Void, Void, String> {
Uri data;
ProgressDialog progressDialog;
public UploadVideoAsync(Uri data) {
this.data = data;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage("Uploading Video to youtube");
progressDialog.show();
}
@Override
protected String doInBackground(Void... voids) {
return uploadYoutube(data);
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Toast.makeText(MainActivity.this, "VideoId is " + s, Toast.LENGTH_SHORT).show();
Log.i("VideoId", "" + s);
progressDialog.dismiss();
}
}
private String uploadYoutube(Uri data) {
// HttpTransport transport = AndroidHttp.newCompatibleTransport();
// JsonFactory jsonFactory = new AndroidJsonFactory(); // GsonFactory
// JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
final JsonFactory jsonFactory = new GsonFactory();
HttpRequestInitializer initializer = new HttpRequestInitializer() {
@Override
public void initialize(HttpRequest request) throws IOException {
mCredential.initialize(request);
request.setLoggingEnabled(true);
// request.setIOExceptionHandler(new HttpBackOffIOExceptionHandler(new ExponentialBackOff()));
}
};
YouTube.Builder youtubeBuilder = new YouTube.Builder(new NetHttpTransport(), jsonFactory, initializer);
youtubeBuilder.setApplicationName(getString(R.string.app_name));
// youtubeBuilder.setYouTubeRequestInitializer(new YouTubeRequestInitializer(API_KEY));
YouTube youtube = youtubeBuilder.build();
String PRIVACY_STATUS = "unlisted"; // or public,private
String PARTS = "snippet,status,contentDetails";
String videoId = null;
try {
Video videoObjectDefiningMetadata = new Video();
videoObjectDefiningMetadata.setStatus(new VideoStatus().setPrivacyStatus(PRIVACY_STATUS));
VideoSnippet snippet = new VideoSnippet();
snippet.setTitle("CALL YOUTUBE DATA API UNLISTED TEST " + System.currentTimeMillis());
snippet.setDescription("MyDescription");
snippet.setTags(Arrays.asList(new String[]{"TaG1,TaG2"}));
videoObjectDefiningMetadata.setSnippet(snippet);
YouTube.Videos.Insert videoInsert = youtube.videos().insert(
PARTS,
videoObjectDefiningMetadata,
getMediaContent(getFileFromUri(data, MainActivity.this)));
// .setKey("AIzaSyAQI2TVFZaRpZnhHicGbEJ1qRkOhZnreU0");
//setOauthToken(mCredential.getToken())
//getMediaContent(getFileFromUri(data, MainActivity.this)));/*.setOauthToken(token);*/ // .setKey(API_KEY);
MediaHttpUploader uploader = videoInsert.getMediaHttpUploader();
uploader.setDirectUploadEnabled(false);
MediaHttpUploaderProgressListener progressListener = new MediaHttpUploaderProgressListener() {
public void progressChanged(MediaHttpUploader uploader) throws IOException {
Log.d(TAG, "progressChanged: " + uploader.getUploadState());
switch (uploader.getUploadState()) {
case INITIATION_STARTED:
break;
case INITIATION_COMPLETE:
break;
case MEDIA_IN_PROGRESS:
break;
case MEDIA_COMPLETE:
case NOT_STARTED:
Log.d(TAG, "progressChanged: upload_not_started");
break;
}
}
};
uploader.setProgressListener(progressListener);
Log.d(TAG, "Uploading..");
System.out.println("URi************************************************************");
Video returnedVideo = videoInsert.execute();
System.out.println("PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP");
Log.d(TAG, "Video upload completed");
videoId = returnedVideo.getId();
Log.d(TAG, String.format("videoId = [%s]", videoId));
/*
if("a".equals("a")){
new VideoExecuteAsyncTask(videoInsert).execute();
System.out.println("PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP");
// System.out.println("URi************************************************************"+returnedVideo.getId());
Log.d(TAG, "Video upload completed");
// videoId = returnedVideo.getId();
Log.d(TAG, String.format("videoId = [%s]", videoId));
}*/
}
catch (final GooglePlayServicesAvailabilityIOException availabilityException) {
Log.e(TAG, "GooglePlayServicesAvailabilityIOException", availabilityException);
} catch (UserRecoverableAuthIOException userRecoverableException) {
Log.i(TAG, String.format("UserRecoverableAuthIOException: %s",
userRecoverableException.getMessage()));
} catch (IOException e) {
Log.e(TAG, "IOException", e);
}
return videoId;
}
private InputStreamContent getMediaContent(File file) throws FileNotFoundException {
System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"+file);
InputStreamContent mediaContent = new InputStreamContent(
"video/*",
new BufferedInputStream(new FileInputStream(file)));
mediaContent.setLength(file.length());
return mediaContent;
}
private static File getFileFromUri(Uri uri, Activity activity) {
try {
String filePath = null;
String[] proj = {MediaStore.Video.VideoColumns.DATA};
Cursor cursor = activity.getContentResolver().query(uri, proj, null, null, null);
if (cursor.moveToFirst()) {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Video.VideoColumns.DATA);
filePath = cursor.getString(column_index);
}
cursor.close();
File file = new File(filePath);
cursor.close();
return file;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void initVideoPicker() {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PICK);
intent.setType("video/*");
List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (list.size() <= 0) {
Log.d(TAG, "no video picker intent on this hardware");
Toast.makeText(MainActivity.this, "No video picker found on device", Toast.LENGTH_SHORT).show();
return;
}
startActivityForResult(intent, GALLERY_RETURN);
}
}
build.gradle (app)
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
defaultConfig {
applicationId "com.example.demovideov3"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.google.android.gms:play-services-auth:18.0.0'
implementation 'pub.devrel:easypermissions:0.3.0'
implementation 'com.google.http-client:google-http-client-gson:1.23.0' exclude module: 'httpclient'
implementation('com.google.api-client:google-api-client-android:1.30.9') {
exclude group: 'org.apache.httpcomponents'
}
implementation('com.google.apis:google-api-services-youtube:v3-rev183-1.22.0') {
exclude group: 'org.apache.httpcomponents'
}
}
AndroidManifest. xml file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.demovideov3">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>