capacitor icon indicating copy to clipboard operation
capacitor copied to clipboard

fix(android): Avoid handling redirection response in WebViewLocalServer (#4240)

Open mrkelvinli opened this issue 3 years ago • 8 comments

Fixes #4240

In WebViewLocalServer.handleProxyRequest(), avoid intercepting network request which will result in a redirection response. This is because intercepting redirection response in handleProxyRequest() will caused the redirection resolving in HttpURLConnection, rather than in web view. This in turn causes the window URL to be unchanged when we expected it to change after a redirect response.

mrkelvinli avatar Apr 06 '21 01:04 mrkelvinli

This indeed fixes my redirect problems! I do however notice that after a redirect, the capacitor and plugin packages have lost all knowledge of the native-bridge (no more device info). It restarts properly after a webview refresh. I'm not sure if this is a side effect of this fix though.

Moarcoo avatar Apr 08 '21 11:04 Moarcoo

Glad that this works for you both @Moarcoo and @tony-scio

If I recall correctly, one of the side effect to the redirected page is that it will not have the capacitor runtime (ie. the native bridge) as it skipped the jsInjector.getInjectedStream part which is located right after the if statement.

mrkelvinli avatar Jan 12 '22 12:01 mrkelvinli

If I recall correctly, one of the side effect to the redirected page is that it will not have the capacitor runtime (ie. the native bridge) as it skipped the jsInjector.getInjectedStream part which is located right after the if statement.

We didn't try changing the order of that. Worth a go.

tony-scio avatar Jan 12 '22 15:01 tony-scio

This is an issue that's been affecting us on Android, too, and while I think this may fix this issue with regards to redirects, there still exists a broader and more substantive difference between how the Capacitor code is injected on iOS and how it's injected on Android. The iOS approach is pretty clean and ensures that the code is always loaded, redirects are handled within the webview, etc. The Android approach, on the other hand, relies on proxying the content and delicately searching for

tags to inject the Capacitor code. We've been experimenting with a fork that we've created that appears to eliminate the need for the handleProxyRequest function altogether.

Specifically, we (a) eliminate handleProxyRequest, (b) set the jsInjector property to public on WebViewLocalServer, (c) remove references to jsInjector.getInjectedStream in handleLocalRequest, and (d) in Bridge.java, add to the reset() function a call to webView.evaluateJavascript that executes the script aggregate, which appears to have a pretty equivalent effect as the current behavior. With this new approach, however, no proxying is required, everything can happen in the webview, and we achieve a pretty equivalent behavior between the iOS and Android implementations.

We're happy to submit this as a PR, if folks may think this would be helpful, but I thought I'd chime in here first to see if we're missing some special context as to why this approach hasn't been taken already. The proxy code just seems like it's always going to be a fragile way to handle this remotely-loaded content on Android.

agclark27 avatar Mar 29 '22 01:03 agclark27

This is an issue that's been affecting us on Android, too, and while I think this may fix this issue with regards to redirects, there still exists a broader and more substantive difference between how the Capacitor code is injected on iOS and how it's injected on Android. The iOS approach is pretty clean and ensures that the code is always loaded, redirects are handled within the webview, etc. The Android approach, on the other hand, relies on proxying the content and delicately searching for tags to inject the Capacitor code. We've been experimenting with a fork that we've created that appears to eliminate the need for the handleProxyRequest function altogether.

Specifically, we (a) eliminate handleProxyRequest, (b) set the jsInjector property to public on WebViewLocalServer, (c) remove references to jsInjector.getInjectedStream in handleLocalRequest, and (d) in Bridge.java, add to the reset() function a call to webView.evaluateJavascript that executes the script aggregate, which appears to have a pretty equivalent effect as the current behavior. With this new approach, however, no proxying is required, everything can happen in the webview, and we achieve a pretty equivalent behavior between the iOS and Android implementations.

We're happy to submit this as a PR, if folks may think this would be helpful, but I thought I'd chime in here first to see if we're missing some special context as to why this approach hasn't been taken already. The proxy code just seems like it's always going to be a fragile way to handle this remotely-loaded content on Android.

@agclark27 We have similar issues with some webapp using Auth0 for login and do redirects for tracking tools. The fix provided in this PR is good enough for our use case, but I'll be very interested to see what solution you came with because as you say this fix doesn't really "fix" the underlying issue with the way webview handle requests.

avallete avatar Apr 05 '22 14:04 avallete

We've run into this issue using AWS Cognito and this patch fixes the problem as well.

SpenserJ avatar May 13 '22 16:05 SpenserJ

Is there any information when this might be integrated? And is there a fix that also prevents the problem with the missing native bridge?

Zacherl avatar Aug 17 '22 14:08 Zacherl

Hi Capacitor team, this can be fix by any chance? We want to use keycloak and this is the only blocking issue at the moment. Thank you for your work.

rengert avatar Sep 19 '22 05:09 rengert