Java 使用OpenId AppAuth Android库时,具有隐式意图的PendingEvent返回取消的异常
我正在尝试实现oauth2,以允许用户使用Reddit登录。我已经在reddit上用适当的重定向uri创建了我的应用程序 我所做的: 带有登录按钮的MainActivity。单击登录按钮,启动授权流。要创建授权请求,我们需要传递一个挂起的意图,库使用该意图调用我们希望它在授权成功后调用的适当组件 问题: 当使用隐式意图创建挂起的意图(在创建意图时仅设置操作字符串)时,库在调用挂起的意图时会收到一个已取消的异常。我还提到了清单文件中MainActivity的意图过滤器中的操作字符串 我尝试过的: 1.我尝试使用显式意图创建挂起的意图(定义创建意图时我要打开的活动类),我的活动的onStart被正确的意图调用。 2.我尝试直接从活动本身调用挂起的意图(带有隐式意图),结果成功地调用了它 观察: 1.如果我使用较旧版本的库(v0.2.0),则带有隐式意图的挂起意图可以正常工作 OpenId AppAuth库的当前版本-0.7.1 在Android 9(Pie)上测试-OnePlus 3T 下面是我的MainActivity.javaJava 使用OpenId AppAuth Android库时,具有隐式意图的PendingEvent返回取消的异常,java,android,android-pendingintent,appauth,Java,Android,Android Pendingintent,Appauth,我正在尝试实现oauth2,以允许用户使用Reddit登录。我已经在reddit上用适当的重定向uri创建了我的应用程序 我所做的: 带有登录按钮的MainActivity。单击登录按钮,启动授权流。要创建授权请求,我们需要传递一个挂起的意图,库使用该意图调用我们希望它在授权成功后调用的适当组件 问题: 当使用隐式意图创建挂起的意图(在创建意图时仅设置操作字符串)时,库在调用挂起的意图时会收到一个已取消的异常。我还提到了清单文件中MainActivity的意图过滤器中的操作字符串 我尝试过的:
package com.prateekgrover.redditline;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.prateekgrover.redditline.services.RedditAuthService;
import net.openid.appauth.AuthState;
import net.openid.appauth.AuthorizationException;
import net.openid.appauth.AuthorizationRequest;
import net.openid.appauth.AuthorizationResponse;
import net.openid.appauth.AuthorizationService;
import net.openid.appauth.AuthorizationServiceConfiguration;
import net.openid.appauth.TokenRequest;
import net.openid.appauth.TokenResponse;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
private String USED_INTENT = "1";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button loginButton = findViewById(R.id.reddit_login);
loginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Intent intent = new Intent(MainActivity.this, RedditAuthService.class);
// startService(intent);
performRedditAuthAction(MainActivity.this, "com.prateekgrover.redditline.HANDLE_AUTHORIZATION_RESPONSE");
}
});
}
public void performRedditAuthAction(Context context, String actionRedirect) {
String uuid = UUID.randomUUID().toString();
AuthorizationServiceConfiguration serviceConfiguration = new AuthorizationServiceConfiguration(
Uri.parse("https://www.reddit.com/api/v1/authorize") /* auth endpoint */,
Uri.parse("https://www.reddit.com/api/v1/access_token") /* token endpoint */
);
String clientId = "<my client id>";
Uri redirectUri = Uri.parse("com.prateekgrover.redditline://oauth2callback");
AuthorizationRequest.Builder builder = new AuthorizationRequest.Builder(
serviceConfiguration,
clientId,
"code",
redirectUri
);
builder.setState(uuid);
builder.setScopes("identity", "mysubreddits", "read", "save", "submit", "subscribe", "vote");
AuthorizationRequest request = builder.build();
AuthorizationService authorizationService = new AuthorizationService(context);
String action = actionRedirect;
Intent postAuthorizationIntent = new Intent("com.prateekgrover.redditline.HANDLE_AUTHORIZATION_RESPONSE");
PendingIntent pendingIntent = PendingIntent.getActivity(this, request.hashCode(), postAuthorizationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
authorizationService.performAuthorizationRequest(request, pendingIntent);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (intent != null && intent.getAction() != null) {
String action = intent.getAction();
switch (action) {
case "com.prateekgrover.redditline.HANDLE_AUTHORIZATION_RESPONSE":
redirectIntent(intent);
break;
default:
}
}
}
private void redirectIntent(@Nullable Intent intent) {
if (!intent.hasExtra(USED_INTENT)) {
handleAuthorizationResponse(intent);
intent.putExtra(USED_INTENT, true);
}
}
private void handleAuthorizationResponse(Intent intent) {
AuthorizationResponse response = AuthorizationResponse.fromIntent(intent);
AuthorizationException error = AuthorizationException.fromIntent(intent);
final AuthState authState = new AuthState(response, error);
if (response != null) {
AuthorizationService service = new AuthorizationService(this);
service.performTokenRequest(response.createTokenExchangeRequest(), new AuthorizationService.TokenResponseCallback() {
@Override
public void onTokenRequestCompleted(@Nullable TokenResponse tokenResponse, @Nullable AuthorizationException exception) {
if (exception != null) {
} else {
if (tokenResponse != null) {
authState.update(tokenResponse, exception);
System.out.println(tokenResponse.accessToken + " refresh_token " + tokenResponse.refreshToken);
}
}
}
});
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
@Override
protected void onStart() {
super.onStart();
Intent intent = getIntent();
if (intent != null && intent.getAction() != null) {
String action = intent.getAction();
switch (action) {
case "com.prateekgrover.redditline.HANDLE_AUTHORIZATION_RESPONSE":
redirectIntent(intent);
break;
default:
}
}
}
}
以防其他人偶然发现这个问题 使用app auth android github项目中的示例应用程序。 不要使用GoogleCodeLabs应用程序验证示例!上面问题中的代码来自Google CodeLabs,它非常古老,不再有效(该州于2020年7月发布)。 我也犯了同样的错误,appauth在自己的页面/自述中链接了codelabs,所以我开始使用codelabs代码,结果出现了很多问题和错误
新的应用程序auth版本0.7.x使用了一个json配置文件,示例应用程序显示了如何处理有关挂起的意图等的错误。为什么您希望在此处使用隐式
意图
?这是一个授权流程。使用隐式意图
意味着如果另一个应用程序使用与您的隐式意图
匹配的
执行活动,则您对拦截该授权流的其他应用程序感到满意。只有当你明确想要一个任意的应用程序响应时,才使用隐式的意图。我遵循了使用隐式意图的谷歌代码实验室。这在版本0.2.0中运行良好,但当我尝试更新库时,它不起作用。这就是问题所在。我正在使用显式意图,但只是好奇为什么它不起作用。希望库检测到隐式intent
,并因此失败。如果不是,应该是这样。就代码实验室而言,我认为,但由于该代码已经没有维护和过时,我几乎不希望谷歌会修复它。我用来创建Intent
的操作字符串是自定义字符串。图书馆如何检测到这一点?此外,库调用completeIntent.send
的相关部分失败,出现canceledexception
。此外,库检测到重定向uri,然后在处理结果后,它发送pendingent
“库如何检测到它?”--嗯,这是一个好的观点。有一些隐藏的API可以让你窥探挂起的内容
,尽管它们可能在Android 9.0+上被禁止,作为整个禁止隐藏API计划的一部分。
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="com.prateekgrover.redditline.HANDLE_AUTHORIZATION_RESPONSE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
private void extractState(Bundle state) {
if (state == null) {
Logger.warn("No stored state - unable to handle response");
finish();
return;
}
mAuthIntent = state.getParcelable(KEY_AUTH_INTENT);
mAuthorizationStarted = state.getBoolean(KEY_AUTHORIZATION_STARTED, false);
try {
String authRequestJson = state.getString(KEY_AUTH_REQUEST, null);
mAuthRequest = authRequestJson != null
? AuthorizationRequest.jsonDeserialize(authRequestJson)
: null;
} catch (JSONException ex) {
throw new IllegalStateException("Unable to deserialize authorization request", ex);
}
mCompleteIntent = state.getParcelable(KEY_COMPLETE_INTENT);
mCancelIntent = state.getParcelable(KEY_CANCEL_INTENT);
}
private void handleAuthorizationComplete() {
Uri responseUri = getIntent().getData();
Intent responseData = extractResponseData(responseUri);
if (responseData == null) {
Logger.error("Failed to extract OAuth2 response from redirect");
return;
}
responseData.setData(responseUri);
if (mCompleteIntent != null) {
Logger.debug("Authorization complete - invoking completion intent");
try {
mCompleteIntent.send(this, 0, responseData);
} catch (CanceledException ex) {
Logger.error("Failed to send completion intent", ex);
}
} else {
setResult(RESULT_OK, responseData);
}
}