maui
maui copied to clipboard
BlazorWebView doesn't download files
Description
We have an article about file downloads in Blazor Server or Wasm application https://learn.microsoft.com/en-us/aspnet/core/blazor/file-downloads?view=aspnetcore-7.0.
None of the mentioned approaches work in BlazorWebView for Android/macOS/iOS. Perfectly working in WebView2 on windows.
Steps to Reproduce
- Run application
- Click any link or button for download
Expected behavior: Files are downloaded on any platform
Actual behavior: Files are not downloaded on Android/iOS/macOS
Link to public reproduction project repository
https://github.com/konstantin-karpukhin/BlazorWebViewDownload/tree/main
Version with bug
7.0.49
Last version that worked well
Unknown/Other
Affected platforms
iOS, Android, macOS
Affected platform versions
all
Did you find any workaround?
Uncomment '// WORKAROUND' lines in source project.
- Modify microsoft article code: add document.body.appendChild(anchorElement); before anchorElement.click();
- Download blob/file and convert it to data url using window.onClick in javascript.
- Call c# code to save file manually.
It works in case you have access to source code. Didn't find available workaround in case you are using third-party libraries or load external web sites.
Relevant log output
No response
I don't believe this is a MAUI, Blazor, or MAUI Blazor bug. This is the default behavior of the underlying WebViews for these platforms.
https://github.com/drasticactions/MauiRepros/tree/main/BlazorTests
I've created a reproduction project to show this. It's a Blazor WASM app and a series of native .NET apps with WebViews (The same MAUI uses for its webview). Taking your code and running it here, you can see the exact same behavior. Moreover, nearly all of your code is straight JavaScript inside of the index.html. That's unrelated to Blazor or MAUI, you're just using JavaScript, you can reproduce this with straight HTML inside a generic webview with no Blazor at all.
A WebView is not the same as full blown Browser window (Like Safari or Chrome, etc). WebView2 does support baseline downloading support but Android and iOS/Catalyst WKWebView require extra configuration (https://github.com/dotnet/maui/discussions/15322) and that's not in scope for the MAUI WebView at the moment.
@Eilon Does this track?
@konstantin-karpukhin because the application runs on the same device already where from does your example tries to download the content? Presumable that content is already on the same device. Can you clarify this please?
If, however, your "download source" is indeed hosted on an external server, it may be due to app configuration / permissions, as pointed out in the above comment by @drasticactions.
Hi @konstantin-karpukhin. We have added the "s/needs-info" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.
@mkArtakMSFT
I am a component library developer for creating, viewing/editing, and downloading documents/reports. We download files as described in Microsoft documentation. Reports are generated dynamically and are relatively small, so we download them via blob url.
Our customers encountered an issue with sharing code between different Blazor hosting models. The code works well for Blazor Server/WASM/Hybrid(Windows) applications, but not for non-Windows Blazor MAUI.
I understand that only opening http links is a platform web views limitation. I found some ways to handle downloads by accessing platform WebView (BlazorWebView.WebView) and using android.webkit.webview.download for android and blazorwebview.urlloading for iOS/macOS. It works similarly to (https://github.com/dotnet/maui/discussions/15322), because it uses the same entry point in platform web views (desicionHandler for iOS/macOS or shouldOverrideUrlLoading/setDownloadListener for Android).
However, none of the configurations allow me to preserve the file name for data url or download blob url.
The same issue also occurs for any other data/blob url on an external page.
Downloading files is a basic functionality of web applications and I didn't find any mention of this limitation in Blazor Hybrid documentation. It would be helpful if BlazorWebView were handling downloads by itself for consistency with other platforms. Or if there was a Download event for BlazorWebView similar to android.webkit.webview.download but without limitations above. At the very least, this limitation should be well-documented with recommended workarounds.
Our customers encountered an issue with sharing code between different Blazor hosting models. The code works well for Blazor Server/WASM/Hybrid(Windows) applications, but not for non-Windows Blazor MAUI.
It's not Blazor MAUI. Your issue is fundamental to WebViews (As in, outside of .NET, the actual WebView code) on these platforms. If your customers ran your code in an Android, iOS, or Catalyst webview either with .NET or native, they would see the same issue. Likewise, as I said above, your Javascript code has nothing to do with Blazor.
That said, as I pointed to in my reply and as you saw yourself, there are APIs within those native webviews where file links could be handled in some way. You could implement them yourself to handle those usecases right now, and It's not impossible for us to someday create a wrapper around it for MAUI's WebView or BlazorWebView, but that's a feature request.
IMO this is not a bug. The native webviews for iOS/Android don't handle file download links by default, and that behavior is the same between Xamarin.Forms and MAUI, which did not try and create APIs around them. It is possible to do so, but that's a feature.
do somethig like this
https://github.com/densen2014/BlazorMaui/blob/master/BlazorMaui/MainPage.xaml.cs
_blazorWebView.UrlLoading +=
(sender, urlLoadingEventArgs) =>
{
if (urlLoadingEventArgs.Url.Host != "0.0.0.0")
{
//外部链接WebView内打开,例如pdf浏览器
Console.WriteLine(urlLoadingEventArgs.Url);
urlLoadingEventArgs.UrlLoadingStrategy =
UrlLoadingStrategy.OpenInWebView;
//拦截可处理 IOS || MACCATALYST 下载文件, 简单测试一下
if (urlLoadingEventArgs.Url.ToString().EndsWith(".exe"))
{
Task.Run(async () => await DownloadAsync(urlLoadingEventArgs.Url));
}
}
};
#if ANDROID
public virtual async Task WebView_DownloadAsync(object? sender, DownloadEventArgs e)
{
Uri uri = new Uri(e.Url!);
await DownloadAsync(uri, e.Mimetype);
}
#endif
public virtual async Task DownloadAsync(string url, string? mimeType = null)
{
Uri uri = new Uri(url);
await DownloadAsync(uri, mimeType);
}
public virtual async Task DownloadAsync(Uri uri, string? mimeType = null)
{
string fileName = Path.GetFileName(uri.LocalPath);
var httpClient = new HttpClient();
var filePath = Path.Combine(UploadPath, fileName);
#if ANDROID
if (uri.Scheme == "data")
{
fileName = DataUrl2Filename(uri.OriginalString);
filePath = Path.Combine(UploadPath, $"{DateTime.Now.ToString("yyyy-MM-dd-hhmmss")}-{fileName}");
var bytes = DataUrl2Bytes(uri.OriginalString);
File.WriteAllBytes(filePath, bytes);
await DisplayAlert("提示", $"下载文件完成 {fileName}", "OK");
return;
}
#endif
byte[] fileBytes = await httpClient.GetByteArrayAsync(uri);
File.WriteAllBytes(filePath, fileBytes);
await DisplayAlert("提示", $"下载文件完成 {fileName}", "OK");
}
public static string DataUrl2Filename(string base64encodedstring)
{
var filename = Regex.Match(base64encodedstring, @"data:text/(?<filename>.+?);(?<type2>.+?),(?<data>.+)").Groups["filename"].Value;
return filename;
}
We've added this issue to our backlog, and we will work to address it as time and resources allow. If you have any additional information or questions about this issue, please leave a comment. For additional info about issue management, please read our Triage Process.
Any news regarding this?
No updates yet, but it might be possible if we implement this feature request: https://github.com/dotnet/maui/issues/11382
Verified this issue with Visual Studio Enterprise 17.9.0 Preview 2. Can repro on android platform with sample project. https://github.com/konstantin-karpukhin/BlazorWebViewDownload/tree/main