在 android 应用中显示用户的 YouTube 数据,例如用户喜欢的视频和订阅
show user's YouTube data like user's liked videos and subscriptions in android app
我要实现的是:
我正在尝试开发一个 Android 应用程序,它让用户使用 Google SignIn 登录,然后要求用户授予 Youtube 的范围访问权限,以便我的应用程序可以访问并获取用户的订阅和其他数据由 Youtube Data API 提供。我已经设置了 Google Developer's Console 项目并且用户正在登录,但是当我请求 Youtube 的附加范围时,屏幕在登录后出现并且一直在加载。我还启用了 Youtube Data API v3,并将范围添加到 Developer Console 中的 OAuth Consent。这是代码。它是在 Android Studio 中编写的本机 Java 代码。而且,我已经在网上搜索过,但我找不到任何解决方案,或者我无法理解。
public class MainActivity extends AppCompatActivity{
private static final String TAG = "tagg";
// Bundle key for account object
private static final String KEY_ACCOUNT = "key_account";
// Request codes
private static final int RC_SIGN_IN = 9001;
private static final int RC_RECOVERABLE = 9002;
private static final int RC_REQUEST_PERMISSION_SUCCESS_CONTINUE_FILE_CREATION = 0011;
private Account mAccount;
// Global instance of the HTTP transport
private static final HttpTransport HTTP_TRANSPORT = AndroidHttp.newCompatibleTransport();
// Global instance of the JSON factory
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private GoogleSignInClient mGoogleSignInClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GoogleSignInOptions gso = new GoogleSignInOptions
.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
//.requestScopes(new Scope(YOUTUBE_SCOPE))
.requestEmail()
.requestIdToken("992631576722-dkn5pp9du25idplr9ll0vkub8pa1sq95.apps.googleusercontent.com")
.build();
mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
findViewById(R.id.signinbtn).setOnClickListener(v -> {
signIn();
});
findViewById(R.id.logout).setOnClickListener(v -> {
mGoogleSignInClient.revokeAccess();
});
}
@Override
public void onStart() {
super.onStart();
GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
if (account==null) Toast.makeText(this,"Not Signed",Toast.LENGTH_SHORT).show();
}
private void signIn() {
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
startActivityForResult(signInIntent, RC_SIGN_IN);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
if (task==null) Toast.makeText(getApplicationContext(),"Null task",Toast.LENGTH_SHORT)
.show();
else {
if (!GoogleSignIn.hasPermissions(
task.getResult(),new Scope(YouTubeScopes.YOUTUBE_FORCE_SSL))) {
GoogleSignIn.requestPermissions(
MainActivity.this,
RC_REQUEST_PERMISSION_SUCCESS_CONTINUE_FILE_CREATION,
task.getResult(),
new Scope(YouTubeScopes.YOUTUBE_FORCE_SSL));
} else {
//task.addOnSuccessListener(googleSignInAccount -> Log.d(TAG, "onSuccess: task
successful"))
// .addOnFailureListener(e -> Log.d(TAG, "onFailure: "+e.getLocalizedMessage()));
handleSignInResult(task);
new Thread(() -> {
try {
Log.d(TAG, "the token: "+GoogleAuthUtil
.getToken(getApplicationContext(),
task.getResult().getAccount(),YouTubeScopes.YOUTUBE_READONLY));
} catch (IOException | GoogleAuthException e) {
Log.d(TAG, "token failed: "+e.getLocalizedMessage());
}
}).start();
//}
}
}
}
private void handleSignInResult(@NonNull Task<GoogleSignInAccount> completedTask) {
Log.d(TAG, "handleSignInResult:" + completedTask.isSuccessful());
try {
GoogleSignInAccount account = completedTask.getResult(ApiException.class);
// Store the account from the result
mAccount = account.getAccount();
account.requestExtraScopes(new Scope(YouTubeScopes.YOUTUBE_READONLY));
Log.d(TAG, "id token: "+account.getIdToken());
// Asynchronously access the Youtube API for the account
new GetSubscriptionTask().execute(mAccount);
} catch (ApiException e) {
Log.d(TAG, "handleSignInResult:error"+e.getStatusCode());
// Clear the local account
mAccount = null;
}
}
/**
* AsyncTask that uses the credentials from Google Sign In to access Youtube subscription API.
*/
private class GetSubscriptionTask extends AsyncTask<Account, Void, List<Subscription>> {
@Override
protected List<Subscription> doInBackground(Account... params) {
Log.d(TAG, "doInBackground: ");
try {
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(
MainActivity.this,
Collections.singleton(YouTubeScopes.YOUTUBE_READONLY));
credential.setSelectedAccount(params[0]);
YouTube youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName("Get User's Own Channel")
.build();
ChannelListResponse channelListResponse = youtube
.channels()
.list("id,contentDetails")
.setMine(true)
.setFields("items(contentDetails/relatedPlaylists/uploads,id)")
.execute();
// get signed user channel id:
Channel myChannel = channelListResponse.getItems().get(0);
String channelId = myChannel.getId(); // this is user's channel ID
Log.d(TAG, "my youtube channel id: " + channelId);
SubscriptionListResponse connectionsResponse = youtube
.subscriptions()
.list("snippet")
.setChannelId(channelId)
.execute();
return connectionsResponse.getItems();
} catch (UserRecoverableAuthIOException userRecoverableException) {
Log.d(TAG, "getSubscription:recoverable exception"+userRecoverableException.getLocalizedMessage());
startActivityForResult(userRecoverableException.getIntent(), RC_RECOVERABLE);
} catch (IOException e) {
Log.d(TAG, "getSubscription:exception"+e.getLocalizedMessage());
}
return null;
}
@Override
protected void onPostExecute(List<Subscription> subscriptions) {
if (subscriptions != null) {
Log.d(TAG, "subscriptions : size=" + subscriptions.size());
for (Subscription subscription : subscriptions) {
Log.v(TAG, "subscription : " + subscription.getId());
}
} else {
Log.d(TAG, "subscriptions: null");
}
}
}
布局上有登录和退出按钮。
当应用程序正在测试时,问题是您必须在云控制台中添加测试用户的电子邮件,然后只有使用该电子邮件才能登录。当应用程序在云控制台上验证后,它将正常工作。
我要实现的是:
我正在尝试开发一个 Android 应用程序,它让用户使用 Google SignIn 登录,然后要求用户授予 Youtube 的范围访问权限,以便我的应用程序可以访问并获取用户的订阅和其他数据由 Youtube Data API 提供。我已经设置了 Google Developer's Console 项目并且用户正在登录,但是当我请求 Youtube 的附加范围时,屏幕在登录后出现并且一直在加载。我还启用了 Youtube Data API v3,并将范围添加到 Developer Console 中的 OAuth Consent。这是代码。它是在 Android Studio 中编写的本机 Java 代码。而且,我已经在网上搜索过,但我找不到任何解决方案,或者我无法理解。
public class MainActivity extends AppCompatActivity{
private static final String TAG = "tagg";
// Bundle key for account object
private static final String KEY_ACCOUNT = "key_account";
// Request codes
private static final int RC_SIGN_IN = 9001;
private static final int RC_RECOVERABLE = 9002;
private static final int RC_REQUEST_PERMISSION_SUCCESS_CONTINUE_FILE_CREATION = 0011;
private Account mAccount;
// Global instance of the HTTP transport
private static final HttpTransport HTTP_TRANSPORT = AndroidHttp.newCompatibleTransport();
// Global instance of the JSON factory
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private GoogleSignInClient mGoogleSignInClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GoogleSignInOptions gso = new GoogleSignInOptions
.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
//.requestScopes(new Scope(YOUTUBE_SCOPE))
.requestEmail()
.requestIdToken("992631576722-dkn5pp9du25idplr9ll0vkub8pa1sq95.apps.googleusercontent.com")
.build();
mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
findViewById(R.id.signinbtn).setOnClickListener(v -> {
signIn();
});
findViewById(R.id.logout).setOnClickListener(v -> {
mGoogleSignInClient.revokeAccess();
});
}
@Override
public void onStart() {
super.onStart();
GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
if (account==null) Toast.makeText(this,"Not Signed",Toast.LENGTH_SHORT).show();
}
private void signIn() {
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
startActivityForResult(signInIntent, RC_SIGN_IN);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
if (task==null) Toast.makeText(getApplicationContext(),"Null task",Toast.LENGTH_SHORT)
.show();
else {
if (!GoogleSignIn.hasPermissions(
task.getResult(),new Scope(YouTubeScopes.YOUTUBE_FORCE_SSL))) {
GoogleSignIn.requestPermissions(
MainActivity.this,
RC_REQUEST_PERMISSION_SUCCESS_CONTINUE_FILE_CREATION,
task.getResult(),
new Scope(YouTubeScopes.YOUTUBE_FORCE_SSL));
} else {
//task.addOnSuccessListener(googleSignInAccount -> Log.d(TAG, "onSuccess: task
successful"))
// .addOnFailureListener(e -> Log.d(TAG, "onFailure: "+e.getLocalizedMessage()));
handleSignInResult(task);
new Thread(() -> {
try {
Log.d(TAG, "the token: "+GoogleAuthUtil
.getToken(getApplicationContext(),
task.getResult().getAccount(),YouTubeScopes.YOUTUBE_READONLY));
} catch (IOException | GoogleAuthException e) {
Log.d(TAG, "token failed: "+e.getLocalizedMessage());
}
}).start();
//}
}
}
}
private void handleSignInResult(@NonNull Task<GoogleSignInAccount> completedTask) {
Log.d(TAG, "handleSignInResult:" + completedTask.isSuccessful());
try {
GoogleSignInAccount account = completedTask.getResult(ApiException.class);
// Store the account from the result
mAccount = account.getAccount();
account.requestExtraScopes(new Scope(YouTubeScopes.YOUTUBE_READONLY));
Log.d(TAG, "id token: "+account.getIdToken());
// Asynchronously access the Youtube API for the account
new GetSubscriptionTask().execute(mAccount);
} catch (ApiException e) {
Log.d(TAG, "handleSignInResult:error"+e.getStatusCode());
// Clear the local account
mAccount = null;
}
}
/**
* AsyncTask that uses the credentials from Google Sign In to access Youtube subscription API.
*/
private class GetSubscriptionTask extends AsyncTask<Account, Void, List<Subscription>> {
@Override
protected List<Subscription> doInBackground(Account... params) {
Log.d(TAG, "doInBackground: ");
try {
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(
MainActivity.this,
Collections.singleton(YouTubeScopes.YOUTUBE_READONLY));
credential.setSelectedAccount(params[0]);
YouTube youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName("Get User's Own Channel")
.build();
ChannelListResponse channelListResponse = youtube
.channels()
.list("id,contentDetails")
.setMine(true)
.setFields("items(contentDetails/relatedPlaylists/uploads,id)")
.execute();
// get signed user channel id:
Channel myChannel = channelListResponse.getItems().get(0);
String channelId = myChannel.getId(); // this is user's channel ID
Log.d(TAG, "my youtube channel id: " + channelId);
SubscriptionListResponse connectionsResponse = youtube
.subscriptions()
.list("snippet")
.setChannelId(channelId)
.execute();
return connectionsResponse.getItems();
} catch (UserRecoverableAuthIOException userRecoverableException) {
Log.d(TAG, "getSubscription:recoverable exception"+userRecoverableException.getLocalizedMessage());
startActivityForResult(userRecoverableException.getIntent(), RC_RECOVERABLE);
} catch (IOException e) {
Log.d(TAG, "getSubscription:exception"+e.getLocalizedMessage());
}
return null;
}
@Override
protected void onPostExecute(List<Subscription> subscriptions) {
if (subscriptions != null) {
Log.d(TAG, "subscriptions : size=" + subscriptions.size());
for (Subscription subscription : subscriptions) {
Log.v(TAG, "subscription : " + subscription.getId());
}
} else {
Log.d(TAG, "subscriptions: null");
}
}
}
布局上有登录和退出按钮。
当应用程序正在测试时,问题是您必须在云控制台中添加测试用户的电子邮件,然后只有使用该电子邮件才能登录。当应用程序在云控制台上验证后,它将正常工作。