Open JiaoLiu opened 11 months ago
Hi @JiaoLiu Are you using webview_flutter to load that web page? If so, which version are you using?
Also, that would be helpful if you can provide a minimal sample code for this. And please provide output of flutter doctor -v
as well. Thanks!
Hi @JiaoLiu Are you using webview_flutter to load that web page? If so, which version are you using?
Also, that would be helpful if you can provide a minimal sample code for this. And please provide output of
flutter doctor -v
as well. Thanks!
we are not using webview_flutter. we use native webview to load the html source with 'file://' scheme. The web source is stored in the sandbox(ios)&SD card(android). It works on iphone, but android show the error.
[✓] Flutter (Channel stable, 3.10.2, on macOS 12.6.3 21G419 darwin-x64, locale zh-Hans-CN)
[✗] Android toolchain - develop for Android devices
✗ Unable to locate Android SDK.
Install Android Studio from: https://developer.android.com/studio/index.html
On first launch it will assist you in installing the Android SDK components.
(or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
If the Android SDK has been installed to a custom location, please use
flutter config --android-sdk
to update to that location.
[✓] Xcode - develop for iOS and macOS (Xcode 14.2) [✓] Chrome - develop for the web [!] Android Studio (not installed) [✓] VS Code (version 1.78.2) [✓] Connected device (3 available)
Can you please share a minimal sample code for android native part? (The flutter web build output can be skipped as I can do it)
It would be appreciated if you could provide a GitHub repository in this case. Thank you!
Can you please share a minimal sample code for android native part? (The flutter web build output can be skipped as I can do it)
It would be appreciated if you could provide a GitHub repository in this case. Thank you!
just use a native webview load this web source. you can create a activity to wrap the webview.
this.webview?.loadUrl(Uri.fromFile(File("file:///sdcard/index.html"))
BTW, we found the reason maybe flutter(3.10.0) using 'fetch' instead of 'XMLHttpRequest' (flutter 3.7.0). 'fetch' method only support https/http on android?
Unfortunately, I'm hitting ERR_ACCESS_DENIED
error when doing this. Below is my settings to load web on Android:
val flutterWebFile = File("${extStoragePath}/web/index.html")
Log.d("TAG", "flutterWebFile path: ${flutterWebFile.path}") // /storage/emulated/0/web/index.html
Log.d("TAG", "pathFlutterWeb is existed: ${flutterWebFile.exists()}") // true
val pathFlutterWeb = "file:///$flutterWebFile"
binding.webview.settings.allowFileAccess = true
binding.webview.settings.allowContentAccess = true
binding.webview.loadUrl(pathFlutterWeb)
Is there missing something to replicate this issue? (checking this on Pixel 3a, Android 12)
Unfortunately, I'm hitting
ERR_ACCESS_DENIED
error when doing this. Below is my settings to load web on Android:val flutterWebFile = File("${extStoragePath}/web/index.html") Log.d("TAG", "flutterWebFile path: ${flutterWebFile.path}") // /storage/emulated/0/web/index.html Log.d("TAG", "pathFlutterWeb is existed: ${flutterWebFile.exists()}") // true val pathFlutterWeb = "file:///$flutterWebFile" binding.webview.settings.allowFileAccess = true binding.webview.settings.allowContentAccess = true binding.webview.loadUrl(pathFlutterWeb)
Is there missing something to replicate this issue? (checking this on Pixel 3a, Android 12)
1、put the builded web source to android device, for example, go to source dir(/xxx/flutter/build/web/), adb push all files to where you will load later:
cd /xxx/flutter/build/web/
adb push * /storage/emulated/0/Download/
2、add<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
to AndroidManifest.xml
3、 add method:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
when {
ContextCompat.checkSelfPermission(
MainActivity@this,
android.Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED -> {
val outdir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
if (!outdir.exists()) {
outdir.mkdirs()
}
// eg: /storage/emulated/0/Download/
this.webview?.loadUrl("file://${File(outdir.absolutePath,"index.html").absoluteFile}")
}
shouldShowRequestPermissionRationale(android.Manifest.permission.READ_EXTERNAL_STORAGE) -> {
}
else -> {
requestPermissions(
arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE),
0x100)
}
}
}
Thanks but that error still persists with your updated code. I'm checking this on Pixel 3a, Android 12.
I was thinking to storage permission on Android version change, so I checked this on Android 11 device and add requestLegacyExternalStorage = true
to bypass scope storage if any. But the result is still the same.
Also, the web path to index.html
is existing (path.exists()
is true). I added these settings too, but not working as well:
binding.webview.settings.allowContentAccess = true
binding.webview.settings.allowFileAccess = true
Maybe this is a new issue with native webview recently that I'm not aware?
Can you check this sample code if it's missing anything? load_flutter_web_128760
Thanks but that error still persists with your updated code. I'm checking this on Pixel 3a, Android 12.
Screenshot I was thinking to storage permission on Android version change, so I checked this on Android 11 device and add
requestLegacyExternalStorage = true
to bypass scope storage if any. But the result is still the same.Also, the web path to
index.html
is existing (path.exists()
is true). I added these settings too, but not working as well:binding.webview.settings.allowContentAccess = true binding.webview.settings.allowFileAccess = true
Maybe this is a new issue with native webview recently that I'm not aware?
Can you check this sample code if it's missing anything? load_flutter_web_128760
https://github.com/huycozy/Android-Native-Sample/blob/load_flutter_web_128760/app/build.gradle
line 13.
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
namespace 'com.example.androidnativesample'
compileSdk 33
defaultConfig {
applicationId "com.example.androidnativesample"
minSdk 24
targetSdk 33
build.gradle change targetSdk 33 to targetSdk 28.
It's only displaying a white screen instead. In order to make this issue actionable and faster, please provide a sample code and affected Android devices (OS, model) so I can just clone and check it. Thanks!
It's only displaying a white screen instead. In order to make this issue actionable and faster, please provide a sample code and affected Android devices (OS, model) so I can just clone and check it. Thanks!
can you connect android device to chrome & inspect the web?
maybe you should modify your /web/index.html file.
It's only displaying a white screen instead. In order to make this issue actionable and faster, please provide a sample code and affected Android devices (OS, model) so I can just clone and check it. Thanks!
can you connect android device to chrome & inspect the web?
maybe you should modify your /web/index.html file.
<head>
<!-- <base href="/"> -->
</head>
When I inspect the webview, I got another error:
Access to internal resource at 'file:///storage/emulated/0/Download/manifest.json' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https, chrome-untrusted.
Can you share a complete and workable sample code along with device info that you are seeing this issue?
you have repoduced this error successfully('Cross origin requests are only supported for protocol schemes: http, data, chrome, https, chrome-untrusted.' similar reason, all source is loaded with 'file' scheme, there should be no Cross origin requests). this error will block the first view. but if you build with flutter 3.7.x, everything is fine. all android device will show this error, but iphone works. our company has security policy, we can't publish source code on outside web.
same flutter code build web.
flutter 3.7.x build web.
flutter 3.10.2 build web.
Unfortunately, I get a similar result as my previous comment when using Flutter 3.7.0 (it's not worked on 3.7.0 as your result). Also, I see a similar error on desktop browser which also uses file
scheme as mobile.
Access to XMLHttpRequest at 'file:///Users/huynq/Desktop/file_scheme_128760/build/web/assets/FontManifest.json' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, isolated-app, chrome-extension, chrome, https, chrome-untrusted.
There is a difference between XMLHttpRequest
and internal resource
(my result)/Fetch API
(your result) in the error message.
Based on what you share at https://github.com/flutter/flutter/issues/128760#issuecomment-1592301391, it may be related to https://github.com/flutter/engine/pull/39657. Keeping this issue open and labeling it for further investigation.
Sample code: load_flutter_web_128760
Is there anything Flutter Web does that prevents this? It seems to be a restriction on Android webivews that disallows loading local files as HTTP requests. Does fetch
work if you just load a plain HTML+JS page without Flutter Web?
Unfortunately, I get a similar result as my previous comment when using Flutter 3.7.0 (it's not worked on 3.7.0 as your result). Also, I see a similar error on desktop browser which also uses
file
scheme as mobile.Access to XMLHttpRequest at 'file:///Users/huynq/Desktop/file_scheme_128760/build/web/assets/FontManifest.json' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, isolated-app, chrome-extension, chrome, https, chrome-untrusted.
There is a difference between
XMLHttpRequest
andinternal resource
(my result)/Fetch API
(your result) in the error message.Based on what you share at #128760 (comment), it may be related to flutter/engine#39657. Keeping this issue open and labeling it for further investigation.
Sample code: load_flutter_web_128760
Our Android developer has reviewed your Sample code: load_flutter_web_128760, and has found that you need to change some WebView settings.
line 55
binding.btn.setOnClickListener {
when {
ContextCompat.checkSelfPermission(
requireActivity(),
android.Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED -> {
val outdir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
if (!outdir.exists()) {
outdir.mkdirs()
}
// eg: /storage/emulated/0/Download/
val path = File(outdir.absolutePath,"index.html").absoluteFile
Log.d("TAG", "is existed: ${path.exists()}")
val webSetting: WebSettings = binding.webview.getSettings()
webSetting.allowContentAccess = true
webSetting.javaScriptEnabled = true
webSetting.javaScriptCanOpenWindowsAutomatically = true
webSetting.allowFileAccess = true
webSetting.setSupportZoom(false)
webSetting.builtInZoomControls = true
webSetting.useWideViewPort = false //##千万不能用
webSetting.loadWithOverviewMode = true
webSetting.databaseEnabled = true
webSetting.domStorageEnabled = true
webSetting.setGeolocationEnabled(true)
webSetting.pluginState = WebSettings.PluginState.ON
webSetting.setRenderPriority(WebSettings.RenderPriority.HIGH)
webSetting.cacheMode = WebSettings.LOAD_DEFAULT
webSetting.allowFileAccessFromFileURLs = true
webSetting.allowUniversalAccessFromFileURLs = true
webSetting.savePassword = false
webSetting.mediaPlaybackRequiresUserGesture = false
WebView.setWebContentsDebuggingEnabled(true)
binding.webview.settings.allowContentAccess = true
binding.webview.settings.allowFileAccess = true
this.binding.webview.loadUrl("file://$path")
}
shouldShowRequestPermissionRationale(android.Manifest.permission.READ_EXTERNAL_STORAGE) -> {}
else -> {
requestPermissions(
arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE),
0x100)
}
}
}
BTW, you should comment out this line in the index.html file of the website source.
<head>
<!-- <base href="/"> -->
</head>
Is there anything Flutter Web does that prevents this? It seems to be a restriction on Android webivews that disallows loading local files as HTTP requests. Does
fetch
work if you just load a plain HTML+JS page without Flutter Web?
Fetching to load the file:// schema does not work on the Android WebView, but it works on the iOS WebView.
This is not part of the Flutter framework code. I think it's just an example that you can copy and paste into your project and then fix it to make it work. There's nothing the Flutter team can do to fix it.
Fetching to load the file:// schema does not work on the Android WebView, but it works on the iOS WebView.
I'm still not sure what we'd need to change in Flutter to make it work. Is there a different method for loading the manifest file that Android WebView would accept?
This is not part of the Flutter framework code. I think it's just an example that you can copy and paste into your project and then fix it to make it work. There's nothing the Flutter team can do to fix it.
The android part is just a demo for loading web source built from Flutter.
Fetching to load the file:// schema does not work on the Android WebView, but it works on the iOS WebView.
I'm still not sure what we'd need to change in Flutter to make it work. Is there a different method for loading the manifest file that Android WebView would accept?
https://github.com/flutter/flutter/issues/128760#issuecomment-1600034131
The same Android code that loads web source built with Flutter 3.7.x will work, but it will not work with Flutter 3.10.x.
I believe the 'main.dart.js' generated by the engine is different. Maybe the reason is that they changed XMLHttpRequest
to Fetch
.
One option is to monkey-patch fetch
to operate on top of XHR
such that the webview would accept it. I'm going to keep this issue in case we can find a volunteer to implement this.
Not sure how current this docs are, but here's some documentation about CORS, and the android web_view:
(It seems the file:
needs to be an asset
or a resource
of the app for this to work?)
One option is to monkey-patch
fetch
to operate on top ofXHR
such that the webview would accept it. I'm going to keep this issue in case we can find a volunteer to implement this. @yjbanov Why can't we roll back to using the old way to load the resources(FontManifest.json etc) that were used in Flutter 3.7.0?
(It seems the
file:
needs to be anasset
or aresource
of the app for this to work?)
@ditman
You are correct. We have added webSetting.allowFileAccessFromFileURLs = true
, so there is no CORS problem.
guys , any update on this issue ? I also encountered that ~_~
_"Access to script at 'file:///android_asset/flutter_assets/static/services/xxxxxx.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.", source: file:///android_asset/flutterassets/static/index.html (0)
Really appreciate if you comment , it's important for me , thanks
@JiaoLiu @yjbanov @ditman @huycozy
guys , any update on this issue ? I also encountered that ~_~
_"Access to script at 'file:///android_asset/flutter_assets/static/services/xxxxxx.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.", source: file:///android_asset/flutterassets/static/index.html (0)
Really appreciate if you comment , it's important for me , thanks
@JiaoLiu @yjbanov @ditman @huycozy
use flutter branch 3.7.0 to build web
@yjbanov Is there an update? Has the latest version of Flutter fixed this issue?
Is there an existing issue for this?
Steps to reproduce
Expected results
show the main.dart screen.
Actual results
inspect the device, found error "Fetch API cannot load file:///xxx/assets/FontManifest.json. URL scheme “file” is not supported" & blank screen.
build web under flutter 3.7.0 everything is ok. flutter 3.10.x error & not work.
Code sample
Code sample
```dart [Paste your code here] ```Screenshots or Video
Screenshots / Video demonstration
[Upload media here]Logs
Logs
```console [Paste your logs here] ```Flutter Doctor output
Doctor output
```console [Paste your output here] ```