Reputation: 171
I have a Blazor Server Hybrid app in .Net 7. I have my .razor componets built in a razor class library and I have two projects, one for web and one for Blazor MAUI. The Blazor MAUI app is pushing a build to my phone which is running Android. The app has a download image button, which takes a blob from a SQL table and pushes it to the user for downloading. I am using the NuGet package BlazorDownloadFile which works great for the web app - however it does not work on my Android device. They are both using the same .razor component - so the code is the same.
Any idea why this may happen. Could it be that I need to set some permissions on the mobile app to allow downloading of the file from an app (I thought it would prompt user if they want to download)? Or maybe something in my build for the mobile app version - allow this app to download files when using?
Any advice would be much appreciated as its my first mobile app
I also have the below permissions in my AndroidManifest.xml which all I think I need for my app to download a file from it self
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
I have looked at my Call Stack tab in Visual Studio after the button is clicked on my Android device. I cant see any type of error
I am running a phone that has Android 10, could this be the issue in that its old maybe? Is there anywhere else I should look for errors?
I have checked the Output tab and I think the issue is on line@ [libEGL] EGLNativeWindowType 0x6f4c0b8410 disconnect failed
Im not sure what this line is doing - any suggestions welcome. See below screen shot of full output
I have enabled the Diagnositic MSBuild Output, below is what I see.
I changed my download function to the below so it creates a new thread when doing the download but no joy. Same error msg
I added the code to my MainPage.xaml.cs file but I get an error when I try and build the app. It doesnt like the GetActivity method - see below. Any idea why this happens?
I used the updated MainPage.xaml.cs and it got rid of tge GetActivity() error which was great. But it still doesnt work on an Android device. I seem to be getting a Blob error now - see below?
My download button is in a Razor Class Library which is then shared between a Blazor Server project and also my Blazor Maui project, However when I created my Razor class library im not sure if I selected the "Support page and views" when I created the project. Could thsi be teh issue?
I have uploaded an example project which contains 3 projects:
I may have got a bit confused by it all but I am hoping you get the drift of it. You can see teh code that I tried to applied from yoru demo: https://github.com/ig-isg/DownloadTest3App
UPDATE: 11 Apr 2023 - I found that the below kind of worked, I had a button click that called the below:
private async Task DownloadFile(int DocumentID) { var d = await documentService.GetDocumentAsync(DocumentID);
string UploadPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "");
string fullFilename = Path.Combine(UploadPath, d.Filename);
using var writer = new BinaryWriter(File.OpenWrite(fullFilename));
writer.Write(d.FileData);
}
But I noticed it does not prompt the user that the file has downloaded. Also it difficult to see where the file is actually stored. On my Android device it stores it under:
/data/user/0/com.companyname.myappname/files
But the above folder is hard to find on my Android device. I would like it to download the file to my Gallary folder on my phone. Any ideas how I do this?
Upvotes: 0
Views: 1229
Reputation: 21
i make a downloadFileFromStreamToDataUrl function to convent blob to DataUrl, and put filename to url like data:text/{filename}
maui android use DataUrl2Bytes to save file.
my codes:
https://github.com/densen2014/BlazorMaui/blob/master/MauiApp_PdfReader/MainPage.xaml.cs
https://github.com/densen2014/BlazorMaui/blob/master/MauiApp_PdfReader/Pages/Downloads.razor
first
<PackageReference Include="BootstrapBlazor.WebAPI" Version="7.0.5" />
MainPage.xaml.cs
protected string UploadPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "uploads");
public MainPage()
{
InitializeComponent();
blazorWebView.BlazorWebViewInitialized += BlazorWebViewInitialized;
}
private void BlazorWebViewInitialized(object? sender, BlazorWebViewInitializedEventArgs e)
{
...
e.WebView.Download +=(async (s,e)=> await WebView_DownloadAsync(s,e));
...
}
#if ANDROID
private async Task WebView_DownloadAsync(object sender, DownloadEventArgs e)
{
Uri uri = new Uri(e.Url);
await DownloadAsync(uri, e.Mimetype);
}
#endif
private 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;
}
/// <summary>
/// 从 DataUrl 转换为 Stream
/// <para>Convert from a DataUrl to an Stream</para>
/// </summary>
/// <param name="base64encodedstring"></param>
/// <returns></returns>
public static byte[] DataUrl2Bytes(string base64encodedstring)
{
var base64Data = Regex.Match(base64encodedstring, @"data:text/(?<type>.+?),(?<data>.+)").Groups["data"].Value;
var bytes = Convert.FromBase64String(base64Data);
return bytes;
}
then razor
<DownloadBlob OnError="@OnError" @ref="DownloadBlob" />
<button class="btn btn-primary" @onclick="(async()=>await DownloadTest())">Download File From Stream</button>
@code{
protected string UploadPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "uploads");
string? Message { get; set; }
[System.Diagnostics.CodeAnalysis.NotNull]
DownloadBlob? DownloadBlob { get; set; }
#if ANDROID
bool isAndroid = true;
#else
bool isAndroid = false;
#endif
private Task OnError(string message)
{
this.Message = message;
StateHasChanged();
return Task.CompletedTask;
}
private async Task DownloadTest()
{
//生成随机文本内存流
var stream = new MemoryStream(System.Text.Encoding.Default.GetBytes($"Log from blazor {DateTime.Now:F}"));
var filename= $"test_{Guid.NewGuid()}.txt";
this.Message = await DownloadBlob.DownloadFileFromStream(filename, stream, isAndroid);
_ = Task.Run (async() =>
{
await Task.Delay(500);
await InvokeAsync(StateHasChanged);
});
}
}
Upvotes: 0