android GoogleAuthUtil.getTokenWithNotification Intent 回调未触发
android GoogleAuthUtil.getTokenWithNotification Intent callback not triggering
我有一个调用 GoogleAuthUtl.getTokenWithNotification
的后台服务,它工作正常,但我正在尝试实现此函数的回调部分,但工作不正常。
我已经实现了一个广播接收器并将其添加到清单中,我的应用程序中也有一个 activity。以下是相关代码。
GoogleAuthUtil.getTokenWithNotification
GoogleAuthUtil.getTokenWithNotification(this.getContext(), account, "oauth2:" + GmailScopes.GMAIL_SEND, null, new Intent(AuthReceiver.AUTH_INTENT));
AuthReceiver
public class AuthReceiver extends BroadcastReceiver
{
public final static String AUTH_INTENT = "com.testoauth.AUTH_INTENT";
public AuthReceiver()
{
}
@Override
public void onReceive(Context context, Intent intent)
{
Log.d("RECEIVER", "Received Auth broadcast.");
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancelAll();
}
}
AndroidManifest
<receiver android:name=".AuthReceiver" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="com.testoauth.AUTH_INTENT" />
</intent-filter>
</receiver>
我不知道为什么收不到广播。我在日志中没有看到任何异常,也没有迹象表明接收器被调用了,调试时它甚至不会在断点处中断。我做错了什么吗?
编辑
我正在使用最小 sdk 16 和目标 sdk 25
来自 GoogleAuthUtil.getTokenWithNotification API 文档:
This method is specifically provided for background tasks. In the
event of an error that needs user intervention, this method takes care
of pushing relevant notification. After the user addresses the
notification, the callback is broadcasted. If the user cancels then
the callback is not fired.
无论用户是否取消,都不会触发回调。除了 ActivityManager
表示已显示通知 (Displayed com.google.android.gms/.auth.uiflows.gettoken.GetTokenActivity
) 之外,没有迹象表明指定的广播意图(在本例中为 com.testoauth.AUTH_INTENT
)已在日志中发送。日志中也没有 "Received Auth broadcast." 消息。
包含此功能的 SDK 示例 (<android-sdk>/extras/google/google_play_services/samples/auth/gau
) 甚至不起作用。
从 GoogleAuthUtil 和 Plus.API
迁移
如果您过去使用 GoogleAuthUtil.getToken 或 Plus.API 与 Google 登录集成,您应该迁移到最新的登录 API 以获得更高的安全性和更好的用户体验。
参考:https://developers.google.com/identity/sign-in/android/migration-guide
也看看这个是否有帮助
我在 Android API 25 上尝试了以下错误,但从未调用回调函数:
- 没有互联网
- 用户还没有登录
- 用户未授权代表his/her发送电子邮件
- Google Play 服务已禁用
- Google Play 服务已过期
如果回调方法调用对您的用例不是很重要,您可以按照Android Quickstart for Gmail API to send emails on user's behalf in Android. Check Sending Email创建Message。
您还可以查看使用上述教程创建的MyGoogleAuthUtilApplication。
希望对您有所帮助。
我已经实施 demo 我已经使用了最新版本的 auth gradle 及其工作。看起来授权版本可能有问题
public class AuthActivity extends Activity {
private static final int AUTHORIZATION_CODE = 1993;
private static final int ACCOUNT_CODE = 1601;
private AuthPreferences authPreferences;
private AccountManager accountManager;
/**
* change this depending on the scope needed for the things you do in
* doCoolAuthenticatedStuff()
*/
private final String SCOPE = "https://www.googleapis.com/auth/googletalk";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
accountManager = AccountManager.get(this);
authPreferences = new AuthPreferences(this);
if (authPreferences.getUser() != null
&& authPreferences.getToken() != null) {
doCoolAuthenticatedStuff();
} else {
chooseAccount();
}
}
private void doCoolAuthenticatedStuff() {
// TODO: insert cool stuff with authPreferences.getToken()
Log.e("AuthApp", authPreferences.getToken());
clickSendEmail();
}
private void chooseAccount() {
// use https://github.com/frakbot/Android-AccountChooser for
// compatibility with older devices
Intent intent = AccountManager.newChooseAccountIntent(null, null,
new String[] { "com.google" }, false, null, null, null, null);
startActivityForResult(intent, ACCOUNT_CODE);
}
private void requestToken() {
Account userAccount = null;
String user = authPreferences.getUser();
for (Account account : accountManager.getAccountsByType("com.google")) {
if (account.name.equals(user)) {
userAccount = account;
Preferences.setAccount(AuthActivity.this,account.name, account.type);
break;
}
}
accountManager.getAuthToken(userAccount, "oauth2:" + SCOPE, null, this,
new OnTokenAcquired(), null);
}
/**
* call this method if your token expired, or you want to request a new
* token for whatever reason. call requestToken() again afterwards in order
* to get a new token.
*/
private void invalidateToken() {
AccountManager accountManager = AccountManager.get(this);
accountManager.invalidateAuthToken("com.google",
authPreferences.getToken());
authPreferences.setToken(null);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == AUTHORIZATION_CODE) {
requestToken();
} else if (requestCode == ACCOUNT_CODE) {
String accountName = data
.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
authPreferences.setUser(accountName);
// invalidate old tokens which might be cached. we want a fresh
// one, which is guaranteed to work
invalidateToken();
requestToken();
}
}
}
private class OnTokenAcquired implements AccountManagerCallback<Bundle> {
@Override
public void run(AccountManagerFuture<Bundle> result) {
try {
Bundle bundle = result.getResult();
Intent launch = (Intent) bundle.get(AccountManager.KEY_INTENT);
if (launch != null) {
startActivityForResult(launch, AUTHORIZATION_CODE);
} else {
String token = bundle
.getString(AccountManager.KEY_AUTHTOKEN);
authPreferences.setToken(token);
doCoolAuthenticatedStuff();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private void clickSendEmail()
{
final Account account = Preferences.getAccount(this);
final String token = Preferences.getToken(this);
new Thread(new Runnable()
{
@Override
public void run()
{
try
{
Session session = Session.getDefaultInstance(new Properties(), null);
MimeMessage email = new MimeMessage(session);
email.setFrom(new InternetAddress(account.name));
//TODO: change email address to your email address for testing
email.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress("nasitraj2@gmail.com"));
email.setSubject("TEST OAUTH EMAIL");
email.setText("This is a test");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
email.writeTo(bytes);
String encodedEmail = Base64.encodeBase64URLSafeString(bytes.toByteArray());
Message message = new Message();
message.setRaw(encodedEmail);
Intent intent = new Intent(AUTH_INTENT);
PendingIntent pendingIntent = PendingIntent.getBroadcast(AuthActivity.this, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
, pendingIntent);
String test = GoogleAuthUtil.getTokenWithNotification(AuthActivity.this, account, "oauth2:" + GmailScopes.GMAIL_SEND, null, intent);
GoogleCredential credential = new GoogleCredential();
credential.setAccessToken(test);
boolean changed = false;
if (!test.equals(token))
{
changed = true;
// Snackbar.make(AuthActivity.this.getView(), "TOKEN CHANGED", Snackbar.LENGTH_LONG).show();
Preferences.setToken(AuthActivity.this, test);
}
Gmail service = new Gmail.Builder(AndroidHttp.newCompatibleTransport(),
AndroidJsonFactory.getDefaultInstance(), credential)
.setApplicationName("Test OAuth").build();
service.users().messages().send("me", message).execute();
String msg = "Email sent";
if (changed)
msg = "TOKEN CHANGED: " + msg;
}
catch (MessagingException e)
{
Log.d( "ERROR", e.getMessage());
}
catch (GoogleJsonResponseException e)
{
if (e.getDetails().getCode() == 401)
{
try
{
Intent intent = new Intent(AUTH_INTENT);
GoogleAuthUtil.clearToken(AuthActivity.this, Preferences.getToken(AuthActivity.this));
GoogleAuthUtil.getTokenWithNotification(AuthActivity.this, account, "oauth2:" + GmailScopes.GMAIL_SEND, null, intent);
}
catch (Exception e1)
{
//ignore
}
}
}
catch (IOException e)
{
// Snackbar.make(AuthActivity.this.getView(), "ERROR", Snackbar.LENGTH_LONG).show();
Log.d( "ERROR", e.getMessage());
}
catch (Exception e)
{
//Snackbar.make(AuthActivity.this.getView(), "ERROR", Snackbar.LENGTH_LONG).show();
Log.d( "ERROR", e.getMessage());
}
}
}).start();
}
}
看来没有人能正确回答这个问题;关于如何解决这个问题有很多非常好的建议,但没有回答实际问题。我得出的结论是,这一定是 Android 或 Google Play 服务中的错误。不幸的是,我已将此问题报告给 Android 问题跟踪器和 Google Play 服务支持论坛...两者都互相指责,甚至拒绝查看该问题。
我有一个调用 GoogleAuthUtl.getTokenWithNotification
的后台服务,它工作正常,但我正在尝试实现此函数的回调部分,但工作不正常。
我已经实现了一个广播接收器并将其添加到清单中,我的应用程序中也有一个 activity。以下是相关代码。
GoogleAuthUtil.getTokenWithNotification
GoogleAuthUtil.getTokenWithNotification(this.getContext(), account, "oauth2:" + GmailScopes.GMAIL_SEND, null, new Intent(AuthReceiver.AUTH_INTENT));
AuthReceiver
public class AuthReceiver extends BroadcastReceiver
{
public final static String AUTH_INTENT = "com.testoauth.AUTH_INTENT";
public AuthReceiver()
{
}
@Override
public void onReceive(Context context, Intent intent)
{
Log.d("RECEIVER", "Received Auth broadcast.");
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancelAll();
}
}
AndroidManifest
<receiver android:name=".AuthReceiver" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="com.testoauth.AUTH_INTENT" />
</intent-filter>
</receiver>
我不知道为什么收不到广播。我在日志中没有看到任何异常,也没有迹象表明接收器被调用了,调试时它甚至不会在断点处中断。我做错了什么吗?
编辑
我正在使用最小 sdk 16 和目标 sdk 25
来自 GoogleAuthUtil.getTokenWithNotification API 文档:
This method is specifically provided for background tasks. In the event of an error that needs user intervention, this method takes care of pushing relevant notification. After the user addresses the notification, the callback is broadcasted. If the user cancels then the callback is not fired.
无论用户是否取消,都不会触发回调。除了 ActivityManager
表示已显示通知 (Displayed com.google.android.gms/.auth.uiflows.gettoken.GetTokenActivity
) 之外,没有迹象表明指定的广播意图(在本例中为 com.testoauth.AUTH_INTENT
)已在日志中发送。日志中也没有 "Received Auth broadcast." 消息。
包含此功能的 SDK 示例 (<android-sdk>/extras/google/google_play_services/samples/auth/gau
) 甚至不起作用。
从 GoogleAuthUtil 和 Plus.API
迁移如果您过去使用 GoogleAuthUtil.getToken 或 Plus.API 与 Google 登录集成,您应该迁移到最新的登录 API 以获得更高的安全性和更好的用户体验。
参考:https://developers.google.com/identity/sign-in/android/migration-guide
也看看这个是否有帮助
我在 Android API 25 上尝试了以下错误,但从未调用回调函数:
- 没有互联网
- 用户还没有登录
- 用户未授权代表his/her发送电子邮件
- Google Play 服务已禁用
- Google Play 服务已过期
如果回调方法调用对您的用例不是很重要,您可以按照Android Quickstart for Gmail API to send emails on user's behalf in Android. Check Sending Email创建Message。 您还可以查看使用上述教程创建的MyGoogleAuthUtilApplication。
希望对您有所帮助。
我已经实施 demo 我已经使用了最新版本的 auth gradle 及其工作。看起来授权版本可能有问题
public class AuthActivity extends Activity {
private static final int AUTHORIZATION_CODE = 1993;
private static final int ACCOUNT_CODE = 1601;
private AuthPreferences authPreferences;
private AccountManager accountManager;
/**
* change this depending on the scope needed for the things you do in
* doCoolAuthenticatedStuff()
*/
private final String SCOPE = "https://www.googleapis.com/auth/googletalk";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
accountManager = AccountManager.get(this);
authPreferences = new AuthPreferences(this);
if (authPreferences.getUser() != null
&& authPreferences.getToken() != null) {
doCoolAuthenticatedStuff();
} else {
chooseAccount();
}
}
private void doCoolAuthenticatedStuff() {
// TODO: insert cool stuff with authPreferences.getToken()
Log.e("AuthApp", authPreferences.getToken());
clickSendEmail();
}
private void chooseAccount() {
// use https://github.com/frakbot/Android-AccountChooser for
// compatibility with older devices
Intent intent = AccountManager.newChooseAccountIntent(null, null,
new String[] { "com.google" }, false, null, null, null, null);
startActivityForResult(intent, ACCOUNT_CODE);
}
private void requestToken() {
Account userAccount = null;
String user = authPreferences.getUser();
for (Account account : accountManager.getAccountsByType("com.google")) {
if (account.name.equals(user)) {
userAccount = account;
Preferences.setAccount(AuthActivity.this,account.name, account.type);
break;
}
}
accountManager.getAuthToken(userAccount, "oauth2:" + SCOPE, null, this,
new OnTokenAcquired(), null);
}
/**
* call this method if your token expired, or you want to request a new
* token for whatever reason. call requestToken() again afterwards in order
* to get a new token.
*/
private void invalidateToken() {
AccountManager accountManager = AccountManager.get(this);
accountManager.invalidateAuthToken("com.google",
authPreferences.getToken());
authPreferences.setToken(null);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == AUTHORIZATION_CODE) {
requestToken();
} else if (requestCode == ACCOUNT_CODE) {
String accountName = data
.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
authPreferences.setUser(accountName);
// invalidate old tokens which might be cached. we want a fresh
// one, which is guaranteed to work
invalidateToken();
requestToken();
}
}
}
private class OnTokenAcquired implements AccountManagerCallback<Bundle> {
@Override
public void run(AccountManagerFuture<Bundle> result) {
try {
Bundle bundle = result.getResult();
Intent launch = (Intent) bundle.get(AccountManager.KEY_INTENT);
if (launch != null) {
startActivityForResult(launch, AUTHORIZATION_CODE);
} else {
String token = bundle
.getString(AccountManager.KEY_AUTHTOKEN);
authPreferences.setToken(token);
doCoolAuthenticatedStuff();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private void clickSendEmail()
{
final Account account = Preferences.getAccount(this);
final String token = Preferences.getToken(this);
new Thread(new Runnable()
{
@Override
public void run()
{
try
{
Session session = Session.getDefaultInstance(new Properties(), null);
MimeMessage email = new MimeMessage(session);
email.setFrom(new InternetAddress(account.name));
//TODO: change email address to your email address for testing
email.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress("nasitraj2@gmail.com"));
email.setSubject("TEST OAUTH EMAIL");
email.setText("This is a test");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
email.writeTo(bytes);
String encodedEmail = Base64.encodeBase64URLSafeString(bytes.toByteArray());
Message message = new Message();
message.setRaw(encodedEmail);
Intent intent = new Intent(AUTH_INTENT);
PendingIntent pendingIntent = PendingIntent.getBroadcast(AuthActivity.this, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
, pendingIntent);
String test = GoogleAuthUtil.getTokenWithNotification(AuthActivity.this, account, "oauth2:" + GmailScopes.GMAIL_SEND, null, intent);
GoogleCredential credential = new GoogleCredential();
credential.setAccessToken(test);
boolean changed = false;
if (!test.equals(token))
{
changed = true;
// Snackbar.make(AuthActivity.this.getView(), "TOKEN CHANGED", Snackbar.LENGTH_LONG).show();
Preferences.setToken(AuthActivity.this, test);
}
Gmail service = new Gmail.Builder(AndroidHttp.newCompatibleTransport(),
AndroidJsonFactory.getDefaultInstance(), credential)
.setApplicationName("Test OAuth").build();
service.users().messages().send("me", message).execute();
String msg = "Email sent";
if (changed)
msg = "TOKEN CHANGED: " + msg;
}
catch (MessagingException e)
{
Log.d( "ERROR", e.getMessage());
}
catch (GoogleJsonResponseException e)
{
if (e.getDetails().getCode() == 401)
{
try
{
Intent intent = new Intent(AUTH_INTENT);
GoogleAuthUtil.clearToken(AuthActivity.this, Preferences.getToken(AuthActivity.this));
GoogleAuthUtil.getTokenWithNotification(AuthActivity.this, account, "oauth2:" + GmailScopes.GMAIL_SEND, null, intent);
}
catch (Exception e1)
{
//ignore
}
}
}
catch (IOException e)
{
// Snackbar.make(AuthActivity.this.getView(), "ERROR", Snackbar.LENGTH_LONG).show();
Log.d( "ERROR", e.getMessage());
}
catch (Exception e)
{
//Snackbar.make(AuthActivity.this.getView(), "ERROR", Snackbar.LENGTH_LONG).show();
Log.d( "ERROR", e.getMessage());
}
}
}).start();
}
}
看来没有人能正确回答这个问题;关于如何解决这个问题有很多非常好的建议,但没有回答实际问题。我得出的结论是,这一定是 Android 或 Google Play 服务中的错误。不幸的是,我已将此问题报告给 Android 问题跟踪器和 Google Play 服务支持论坛...两者都互相指责,甚至拒绝查看该问题。