Closed pkar70 closed 2 years ago
Make sure to validate first with this sample application: https://github.com/unoplatform/Uno.Samples/tree/master/UI/PackageResources
GitHub
A collection of code samples for the Uno Platform. Contribute to unoplatform/Uno.Samples development by creating an account on GitHub.
Sample has no files in Assets folder, so it is not related. Android head should work same as UWP head, and UWP head works.
Thanks. This is likely this Visual Studio issue, as this has been working in Uno for a while. Apply the workaround, and make sure to upvote the VS issue so it gets fixed.
Also, when you're creating issues, don't point to your full app repository, make sure to create a small sample to attach to the issue.
That seams to be the same problem with the unit tests for PR https://github.com/unoplatform/uno/pull/8370 The PR itself is ok, correcting the issues #5453 and #7288. The tests passed only on iOS / macOS and the reason why is the GetFileFromApplicationUriAsync not loading Assets. The exception is exactly the same on Android.
One more check: files are present in .apk file: X\KrakTram\KrakTram_Uno\KrakTram_Uno.Droid\bin\Debug\pkar.KrakTram.apk\res\drawable-nodpi-v4__1950.gif
@pkar70 did you try with the workaround? Does it change anything?
No... a) I have no VS 2022 Preview b) files ARE in apk c) after Android R, accessing resources is changed (see below) d) I would test some things by debugging :)
(After Build.VERSION_CODES#R, Resources must be obtained by Activity or Context created with Context.createWindowContext(int, Bundle). [Application#getResources()](https://developer.android.com/reference/android/content/ContextWrapper#getResources()) may report wrong values in multi-window or on secondary displays.
Thanks. Files are in the APK but with an invalid path / file name, which points to a similar shared project related issue.
After trying workaround - same. Java.IO.FileNotFoundException.
And files are still in same folder within apk: X\KrakTram\KrakTram_Uno\KrakTram_Uno.Droid\bin\Debug\pkar.KrakTram.apk\res\drawable-nodpi-v4\__1950.gif
This reminds me that images are not handled the same way as other file types. If you want images to be read by GetFileFromApplicationUriAsync
, you need to include them as AndroidAsset
not AndroidResource
. This is not something we'll be able to change, as android mangles the file names when included with nesting.
I have workaround...
1) copy files from Uno\Shared\Assets\ folder to Uno\Droid\Assets folder This step is required, as files in Uno\Shared\Assets\ are placed (by build process) in res folder, without directory tree.
2) use this as Android replacement for GetFileFromApplicationUri()
:
private async System.Threading.Tasks.Task<Windows.Storage.StorageFile> AndroidGetFileFromApplicationUri(Uri uri)
{
// "ms-appx:///Assets/" + iRok + ".gif"
// "__" + iRok + ".gif" w pkar.KrakTram.apk\res\drawable-nodpi-v4\
if (uri.Scheme != "ms-appx")
{ // we don't handle "ms-appdata://" prefix (app root folder inside user) - limit of this implementation
throw new InvalidOperationException("Uri is not using the ms-appx scheme");
}
string sFilename = uri.ToString();
if (!sFilename.StartsWith("ms-appx:///Assets/"))
{ // limit of this implementation
throw new InvalidOperationException("Uri is not ms-appx:///Assets/");
}
sFilename = sFilename.Substring("ms-appx:///Assets/".Length);
var assetMan = Android.App.Application.Context.Assets;
if (assetMan is null)
{
throw new InvalidOperationException("Cannot get AssetManager");
}
var outputCachePath = System.IO.Path.Combine(Android.App.Application.Context.CacheDir.AbsolutePath, sFilename);
if (!System.IO.File.Exists(outputCachePath))
{
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(outputCachePath));
using System.IO.Stream fileInApk = assetMan.Open(sFilename);
using var output = System.IO.File.OpenWrite(outputCachePath);
await fileInApk.CopyToAsync(output);
}
return await Windows.Storage.StorageFile.GetFileFromPathAsync(outputCachePath);
}
I don't know WHAT places files from Shared\Assets to Droid\res, and how to prevent it.
There's currently no way to change this:
The only workaround to handle this is to add the items as AndroidAssets
manually, like this:
<ItemGroup>
<AndroidAsset Include="../MyProject.Shared/Assets/**" />
</ItemGroup>
GitHub
Build Mobile, Desktop and WebAssembly apps with C# and XAML. Today. Open source and professionally supported. - uno/RetargetAssets.cs at master · unoplatform/uno
So, if I add this AndroidAsset
to csproj
in Uno.Droid, files from Uno.Shared\Assets
would be visible inside apk
under assets
folder?
It should be yes, let us know if that helps.
Hummmm Following the outputCachePath var, I did a shot in the dark, changing the value of PATH in:
from 'Assets/myfile.jpeg' to only 'myfile.jpeg' and "voilà"! Android could load perfectly the image.
I don't know why path has the 'Assets/' since we are using outputCachePath as well.
@jeromelaban
@iury-kc yes, that's what it's supposed to be doing somehow, but the problem is the handling of conflicts in file names. We've been trying to adjust this for a while (https://github.com/unoplatform/uno/pull/7328) but it's quite tricky.
But what if I have such structure: Assets +- Digital | +- 10.png | +- 20.png +- Analog | +- 10.png | +- 20.png
similar to https://github.com/pkar70/ZegarSloneczny/tree/master/ZegarSloneczny/pic
'Flattening' dirtree is bad.
GitHub
Contribute to pkar70/ZegarSloneczny development by creating an account on GitHub.
Flattening is what android does with resources, it's not something we can change. Assets don't have that problem, when using AndroidAsset
solution I provided above.
Still.. I have UWP app with pictures inside Assets, and GetFileFromApplicationUriAsync() doesn't work for this (on Android).
Uri oPicUri = new Uri("ms-appx:///Assets/" + iRok + ".gif");
Windows.Storage.StorageFile oFile;
oFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(oPicUri);
Windows.UI.Xaml.Media.Imaging.BitmapImage oBmp = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
oBmp.UriSource = oPicUri;
And I cannot use such code for Android. Because build moves files from Uno.Shared\Assets to \res, and GetFileFromApplicationUriAsync throws exception that file is not found.
I can replace this code with "special code for Android", but code should work correctly (or show Uno0001 warning that it is unimplemented). Maybe, in this case, there should be e.g. "Uno0002 Limited implementation for Android, works only for non-picture files, and only for ms-appx (not ms-appdata)" ? And same in all other places where Uno's implementation is somehow limited (e.g., because target platform has limits).
Can you add a simple repro for your scenario here please (not one from your github) ? We'll make modifications to it and see what's needed.
Simple repro:
1) add picture to Uno.Shared/Assets folder, e.g. 1950.gif
2) add code to e.g. MainPage.Loaded
Uri oPicUri = new Uri("ms-appx:///Assets/1950.gif");
var oFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(oPicUri);
This is what I mean by adding a simple repro: Test8618.zip.
The workaround for this is to add the following to the android project:
<ItemGroup>
<AndroidAsset Include="..\Test8618.Shared\Assets\**" Link="Assets\Assets\%(RecursiveDir)\%(FileName)%(Extension)" />
</ItemGroup>
Take a look at the repro to see it in action.
Thanks. In next app version, I will use this.
Current behavior
Exception
**Java.IO.FileNotFoundException:**
is thrown.Expected behavior
File should be 'openable'.
How to reproduce it (as minimally and precisely as possible)
Exception:
**Java.IO.FileNotFoundException:** 'Assets/__1950.gif'
Part of: https://github.com/pkar70/KrakTram
GIF files are present, e.g. X\KrakTram\KrakTram_Uno\KrakTram_Uno.Shared\Assets\1950.gif On build, they are copied to X\KrakTram\KrakTram_Uno\KrakTram_Uno.Droid\obj\Debug\120\res\drawable-nodpi__1950.gif
Workaround
None known.
Works on UWP/WinUI
Yes
Environment
Uno.UI / Uno.UI.WebAssembly / Uno.UI.Skia
NuGet package version(s)
UnoUI 4.2.6
Affected platforms
Android
IDE
Visual Studio 2022
IDE version
17.0.5
Relevant plugins
No response
Anything else we need to know?
No response