Groosha
Groosha

Reputation: 3067

Android WebView with custom protocol

I have a problem with implementing user authentification in a WebView.

As API Docs say, I need to load URL "http://example.com/?key=abc" then User enters his login & password and then he's redirected to webpage "myapp://token#access_token=123456".

All I need is to load this in a WebView and return to my application with that "123456" token. The first problem is that WebView doesn't support custom protocols and it gives me an error "ERR_UNKNOWN_URL_SCHEME".

Second problem is that I don't fully understand how to return to my application with page data.

In AndroidManifest.xml I have this:

 <activity
        android:name="(appname)"
        android:label="@string/app_name"
        android:configChanges="orientation">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.VIEW"/>
            <category android:name="android.intent.category.DEFAULT"/>
            <category android:name="android.intent.category.BROWSABLE"/>
            <data
                android:scheme="myapp"
                android:host="token"/>
        </intent-filter>
    </activity>

In Main.java file I have the following code:

            Intent i = new Intent(Main.this, LoginWebViewActivity.class);
            startActivityForResult(i, 1);

and in LoginWebActivity.java I have the following code:

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.webviewact);
        webView = (WebView) findViewById(R.id.webView);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.loadUrl("http://example.com/?key=abc");
    }

I see one fast solution: Open this link in external browser, however, I don't understand how can my application get data from external browser.

Upvotes: 0

Views: 4872

Answers (2)

Jim
Jim

Reputation: 10278

This is not a "web page":

myapp://token#access_token=123456

That is possibly a URI that you could filter on if you do it properly. You need to implement your own URI with an IntentFilter like this:

see this post:

How to implement my very own URI scheme on Android

EDIT:

To explain - you are sending a "login" request. Then you say you are "redirecting" the client to

myapp://token#access_token=123456

You can't tell the client to "redirect" to a non-URL webpage. The WebView client is an "http" client - it does not accept data schemes / mime types that it does not recognize. So your "redirect" is failing.

When you do the page request, the response should be the URI not a redirect. You can parse the response data to see if you got this response (vs a failed login) and if you did, you can launch a new Activity. Simple as that.

There is an answer here that suggests that you override shouldOverrideUrlLoading which is also acceptable. In this case, we're assuming you are doing a client-side redirect, in which case this method will allow you to capture the authentication response, parse it for the data that you need, then you can launch whatever URL or activity you want.

To explain further, the XML data scheme is only useful for Intents. Your WebView is responding internally - no intent is sent. You have to get the HTTP response, parse it, then broadcast an Intent to get that portion of your code to work.

Upvotes: 0

Greg Ennis
Greg Ennis

Reputation: 15379

You should not need to implement a custom scheme. You should be passing that callback URL into the webpage, and then you look for and intercept that callback in your code by handling shouldOverrideUrlLoading:

    webView.setWebViewClient(new WebViewClient() {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            if (url.startsWith("http://myapp/token#access_token=")) {
                // Parse the token fom the URL and close the webview
                return true;
            } else {
                return super.shouldOverrideUrlLoading(view, url);
            }
        }
    });

Upvotes: 2

Related Questions