使用OpenId AppAuth-Android库时,带有隐式意图的PendingIntent返回取消的异常 [英] PendingIntent with implicit intent returning cancelled exception when using OpenId AppAuth-Android library

查看:161
本文介绍了使用OpenId AppAuth-Android库时,带有隐式意图的PendingIntent返回取消的异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现oauth2以使用户能够使用Reddit登录.我已经使用适当的重定向uri在reddit上创建了我的应用.

I am trying to implement oauth2 to enable users to login with Reddit. I have created my app on reddit with the appropriate redirect uri.

我做什么: 一个带有登录按钮的MainActivity.单击登录按钮,开始授权流程.要创建授权请求,我们需要传递一个挂起的意图,该意图用于库在授权成功后调用我们希望其调用的适当组件.

What I did: A MainActivity with a login button. Clicking the login button, starts the authorization flow. To create the authorization request, we need to pass a pending intent that the library uses to call the appropriate component that we want it to call after authorization is successful.

问题: 当使用隐式意图(在创建意图时仅设置动作字符串)做出暂挂意图时,库在调用暂挂意图时会得到取消的异常.我还在清单文件中的MainActivity的意图过滤器中提到了操作字符串.

Problem: When the pending intent is made using an implicit intent (setting only action string while creating intent), the library gets a cancelled exception while invoking the pending intent. I have mentioned the action string in the intent filter for the MainActivity in manifest file also.

我尝试过的事情: 1.我尝试使用显式意图(定义要在创建意图时打开的活动类)创建挂起的意图,我的活动的onStart被正确的意图调用. 2.我尝试通过直接从活动本身调用挂起的意图(具有隐式意图)来成功调用它.

What I have tried: 1. I tried creating pending intent using an explicit intent (defining the activity class I want to open while creating intent), my activity's onStart is getting called with the correct intent. 2. I tried by directly invoking the pending intent (with implicit intent) from the activity itself and it got called successfully.

观察: 1.如果我使用的是旧版本的库(v0.2.0),则带有隐式意图的挂起意图可以正常工作.

Observation: 1. If I use an older version of the library (v0.2.0), the pending intent with implicit intent works fine.

OpenId AppAuth库的当前版本-0.7.1 在Android 9(Pie)-OnePlus 3T上进行了测试

Current version of OpenId AppAuth library - 0.7.1 Tested on Android 9 (Pie) - OnePlus 3T

下面是我的MainActivity.java

Below is my MainActivity.java

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:
            }
        }
    }
}

清单文件:

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

库的相关部分-mCompleteIntent是我发送到库的PendingIntent

Relevant parts of the library - mCompleteIntent is the PendingIntent that I sending to the library

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

推荐答案

以防其他人偶然发现此问题.

In case anybody else stumbles upon this issue.

在app-auth android github项目中使用示例应用程序. 不要使用Google CodeLabs应用程序身份验证示例!上面问题中的代码来自Google CodeLabs,它很旧并且不再起作用(状态为2020年7月). 我犯了同样的错误,app-auth在自己的页面/自述文件上链接了代码实验室,因此我开始使用codelabs代码,结果遇到很多问题和错误.

Use the example app within app-auth android github project. Don't use Google CodeLabs app-auth example! The code from the question above is from Google CodeLabs, it is very old and no longer works (state at July 2020). I did the same mistake, app-auth links codelabs on their own page/readme, so I started using codelabs code and ended up with lots of problems and errors.

新的app-auth版本0.7.x使用json配置文件,示例应用程序显示了如何处理未决意图等方面的错误.

The new app-auth version 0.7.x uses a json configuration file and the example app shows how to handle errors around pending intents etc. .

这篇关于使用OpenId AppAuth-Android库时,带有隐式意图的PendingIntent返回取消的异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆