apache / cordova-android

Apache Cordova Android
https://cordova.apache.org/
Apache License 2.0
3.59k stars 1.52k forks source link

Support custom scheme or domain for local content on Android #1004

Closed AshleyScirra closed 2 years ago

AshleyScirra commented 3 years ago

Feature Request

As of cordova-ios 6.0.0, you can use the following in config.xml:

<preference name="scheme" value="app"/>
<preference name="hostname" value="localhost"/>

Then the app runs on app://localhost instead of file://. This does not appear to work on Android though - having tried it the app still runs at a file:// URL.

Motivation Behind Feature

Running on file: brings a number of origin-related problems. Notably on file:, the browser treats every resource as a different origin, causing some features to be blocked. In particular, fetch() cannot be used at all, because it's actually written in to the specification that it can just throw on file: protocol and that's what Chromium chooses to do.

Further, this will allow Cordova Android apps to more closely align their codebases with iOS, since in both cases it can be running on the same URL (app://localhost) with identical capabilities regarding the security origin, use of fetch(), etc.

Alternatives or Workarounds

Right now we are forced to use cordova-plugin-file to read local files, and in many cases use some ugly code involving blobs and blob URLs to work around restrictions with file: URLs. We also have to maintain two significantly different codepaths, one using fetch(), the other using cordova-plugin-file methods.

jcesarmobile commented 3 years ago

Google engineers have recommended to discourage custom schemes in Android apps in this ionic webview issue, so I don't think this is something we should do in cordova-android.

But maybe, as ionic webview does, intercept the requests so they load as http/https urls. That should fix some of the mentioned problems.

But even that, I don't think it should be in cordova-android for now, should start as a separate plugin as cordova-plugin-wkwebview-engine and if people uses it, integrate it in cordova-android later on.

AshleyScirra commented 3 years ago

Ah, I see, interesting.

It sounds like an alternative could be to host on a custom local domain, e.g. https://cordova.local. I imagine this then makes it clear whether the request should be served locally by matching the cordova.local domain on the request, and then everything is still treated as same-origin and using the well-defined and stable https scheme. (Would that work? It seems odd to use https without a certificate, but if that will do the job then I think it's fine)

The real motivation here is to not use file: due to the cross-origin obstacles it would throw in the way, so a custom domain on https would still solve the original problem. So could that work instead?

brodybits commented 3 years ago

host on a custom local domain, e.g. https://cordova.local.

Or maybe use .localhost tld for an extra 0.001 % safety factor ref:

It seems odd to use https without a certificate

Maybe use http scheme?

dpogue commented 3 years ago

A few notes:

AshleyScirra commented 3 years ago

A key detail is the webview should still think the page is in a secure context, since some features are gated behind that. I'm not sure if a URL like http://cordova.localhost will quality as a secure context. If it does not it would be preferable to use https.

breautek commented 3 years ago

But even that, I don't think it should be in cordova-android for now, should start as a separate plugin as cordova-plugin-wkwebview-engine and if people uses it, integrate it in cordova-android later on.

Just noting that a solution like this should solve https://github.com/apache/cordova-android/issues/560 ... where the current workaround is to use the ionic webview.

AshleyScirra commented 3 years ago

Note: this may also be necessary to support JavaScript Modules (#1142).

jcesarmobile commented 2 years ago

This PR that uses the WebViewAssetLoader will allow to load apps from https, the <preference name="hostname" value="localhost"/> will be available, the scheme will not, will always use https.

hariprakashnagar commented 1 month ago

Is it possible to change app://localhost to http://localhost/ on Cordova ios >6. We are facing an issue with Cross Origin because app://localhost is not a valid domain.

breautek commented 1 month ago

Is it possible to change app://localhost to http://localhost/ on Cordova ios >6. We are facing an issue with Cross Origin because app://localhost is not a valid domain.

Short answer is this isn't possible.

On iOS the WKURLSchemeHandler is the backing API and only allows you to use a scheme that is not already registered. This means that all well known standard schemes like http or https is automatically not supported by the iOS API.

On Android, the WebViewAssetLoader is the backing API and it only supports setting either http or https as the scheme. So this creates a situation where you cannot make the two platforms consistent.

Your backend must either enable all domains using a wildcard for the Access-Control-Allow-Origin response header, or your backend must read the request's Origin header and dynamically set the Access-Control-Allow-Origin response header accordingly if the Origin is a value that you expect.

hariprakashnagar commented 1 month ago

Is it possible to change app://localhost to http://localhost/ on Cordova ios >6. We are facing an issue with Cross Origin because app://localhost is not a valid domain.

Short answer is this isn't possible.

On iOS the WKURLSchemeHandler is the backing API and only allows you to use a scheme that is not already registered. This means that all well known standard schemes like http or https is automatically not supported by the iOS API.

On Android, the WebViewAssetLoader is the backing API and it only supports setting either http or https as the scheme. So this creates a situation where you cannot make the two platforms consistent.

Your backend must either enable all domains using a wildcard for the Access-Control-Allow-Origin response header, or your backend must read the request's Origin header and dynamically set the Access-Control-Allow-Origin response header accordingly if the Origin is a value that you expect.

Yes, we can do this but PDF embed viewer does not work with Web view [Mobile browser] if we use from hosted URL.

breautek commented 1 month ago

Yes, we can do this but PDF embed viewer does not work with Web view [Mobile browser] if we use from hosted URL.

This doesn't sound like a CORS issue then.

The scheme urls used by the webview is only accessible by that webview instance. So if the PDF viewer for example is either a third-party application OR a cordova plugin that attempts to use native APIs to fetch that resource (including native http APIs) then those requests aren't intercepted by the webview and you don't get access to your content. It sounds like your issue is this.

If you're trying to expose a local app asset, you might be able to form a file:// url instead. The file plugin has useful constants to get to your app's storage data. For iOS, cordova.file.applicationDirectory + "www/" should yield a file:// path that leads to your www directory.

On Android it should be the same, as your www folder will be inside file:///android_asset/. This path isn't accessible by the webview if you have schemes enabled, but it should still be accessible by native APIs, so it should still work in your use case if my assumption about your PDF viewer is correct.

If it isn't, or you still have trouble, it may be worth opening a discussion at https://github.com/apache/cordova/discussions for further support. I'll be locking this thread since it's now getting off-topic and I don't want to spam the OP.