Xamarin read a file in shared Project - xamarin

I'm trying to read a File in my Shared Project.
var currentPath = Environment.CurrentDirectory;
var filename = Path.Combine(currentPath, "File.txt");
var content = File.ReadAllText(filename);
return content;
If i start my application in iOS this works fine, but in Android i get the FileNotFound exception.

The file system structure and the underlying APIs vary from platform to platform. Environment.CurrentDirectory exists on iOS, but it does not exist on Android nor on UWP, so it will have a null value, and therefore it won't be able to find the file.
Because the file system is so different between platforms it is recommended you abstract environment level file accessing code to platform specific projects instead of shared ones - although you could make it work with compiler directives.
#if __ANDROID__
var currentPath = Environment.DataDirectory;
#endif
Alternatively, you can experiment getting the current directory from the Directory.GetCurrentDirectory(); method (in the System.IO namespace)

Related

.NET MAUI FileProvider on Android does not work in release mode

I am attempting to install an apk file using .NET MAUI on an Android device like so:
var bytes = DownloadApkFile();
var file = Path.Combine(FileSystem.Current.CacheDirectory, "app.apk");
File.WriteAllBytes(file, bytes);
var context = Android.App.Application.Context;
Java.IO.File file = new Java.IO.File(path);
using (Android.Content.Intent install = new Android.Content.Intent(Android.Content.Intent.ActionView))
{
var uri = Microsoft.Maui.Storage.FileProvider.GetUriForFile(context, context.ApplicationContext.PackageName + ".fileProvider", file);
install.SetDataAndType(uri, "application/vnd.android.package-archive");
install.AddFlags(Android.Content.ActivityFlags.NewTask);
install.AddFlags(Android.Content.ActivityFlags.GrantReadUriPermission);
install.AddFlags(Android.Content.ActivityFlags.ClearTop);
install.PutExtra(Android.Content.Intent.ExtraNotUnknownSource, true);
Platform.CurrentActivity.StartActivity(install);
}
This works perfectly in debug mode, but in release mode I get the following exception: Java.Lang.IllegalArgumentException: Couldn't find meta-data for provider with authority com.mycompany.mobile.fileProvider
I thought maybe I needed to add a [ContentProvider] attribute to the application, but then it no longer builds because of duplicate content providers for androidx.core.content.FileProvider, so I assume MAUI is including this content provider automatically?
The Android/iOS linkers are removing chunks of the assemblies of your app due to the heavy use of reflection. You can verify this by adding code as follows in the csproj file as follows :
<PropertyGroup>
<AndroidLinkMode>None</AndroidLinkMode>
</PropertyGroup>
And you can also instruct the linker to keep some of the important assemblies .
The steps are as follows: :
Add an XML file named Linker.xml to your Android project.
Right click Linker.xml in your Solution Explorer then select Properties.
Change Build Action to LinkDescription.
There is a simimar thread,you can check it here Linker.

C++ Windows Forms application icon exception

I want to set an icon for my Windows Form application. My actions step by step:
I created an 'icon.ico' (256x256) and put it into my project folder
In my 'Form1.h [Design]' I chose this file using Properties
This code appeared in 'Form1.h'
void InitializeComponent(void)
{ ...
this->Icon = (cli::safe_cast<System::Drawing::Icon^>(resources->GetObject(L"$this.Icon")));
... }
The object '$this.Icon' appeared in 'Form1.resx'
I rebuilt the whole project -> no errors
During execution the line 'this->Icon = ...' causes an exception: System.Resources.MissingManifestResourceException: 'Could not find any resources appropriate for the specified culture or the neutral culture. Make sure "WinForm.Form1.resources" was correctly embedded or linked into assembly "MyProject" at compile time, or that all the satellite assemblies required are loadable and fully signed.'
Here I found numerous advices, such as remove/add icon or set some custom properties for 'Form1.resx', but none of them works for me
Just like above, change line to:
this->Icon = gcnew System::Drawing::Icon(L"ICON_NAME.ico");
You might get error/exception while opening form creator but you shouldn't lose any data.
Been there, done that :)
Place the Icon you want to connect to your Form in the project directory.
Then replace the line above with the following:
this->Icon = gcnew System::Drawing::Icon(L"app.ico");
This should neutralize the bug that Microsoft has not fixed.
If you are using visual studio 2019 , you need to change the name of namespace in Form1 the same as your project name, i did it and it works
and make sure you change it in main :
[STAThread]
int main() {
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
Application::Run(gcnew your_namespace_name::Form1());
return 0;
}

Xamarin ArcGISRuntime .net System.IO.FileLoadException: 'File exception: The supplied file path contains directories that do not exist.'

https://github.com/Esri/arcgis-runtime-samples-dotnet samples
I am exploring the xamarin samples that are available through the link above. One sample that is called Generate geodatabase here shows how to generate a geodatabase and store it locally on the device.
Problem:
I am running the sample for UWP app and it breaks showing this.
System.IO.FileLoadException: 'File exception: The supplied file path contains directories that do not exist.'
I have investigated the issue and here are my findings:
The file path "_gdbPath" supplied to
_generateGdbJob = _gdbSyncTask.GenerateGeodatabase(generateParams, _gdbPath);
is obtained using the following method:
private string GetGdbPath()
{
// Set the platform-specific path for storing the geodatabase
String folder = "";
#if NETFX_CORE //UWP
folder = Windows.Storage.ApplicationData.Current.LocalFolder.Path.ToString();
#elif __IOS__
folder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
#elif __ANDROID__
folder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
#endif
// Set the final path
return Path.Combine(folder, "wildfire.geodatabase");
}
Now, the GbdPath location is on the devise and it is correct. I physically went opening the path and also I have tried creating a file in the path/folder like the following:
async void WriteTimestamp()
{
Windows.Globalization.DateTimeFormatting.DateTimeFormatter formatter =
new Windows.Globalization.DateTimeFormatting.DateTimeFormatter("longtime");
StorageFile sampleFile = await localFolder.CreateFileAsync("wildfire.geodatabase",
CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(sampleFile, formatter.Format(DateTime.Now));
}
It worked and the file was successfully created. So, the file system is accessible.
Also, I tried it on Android with a little modification/change, I made it work here the change.
Question:
What's wrong with UWP platform in my case (I have not tested IOS)?
Update:
I have done further research and found that there might be a bug (that I will report) in GeodatabaseSyncTask class GenerateGeodatabase method. It cannot find the LocalState folder in case of Windows 10 configured to store new content in another location (other than on default c: drive) like in my case
see here . So, if windows 10 is configured to store app content on another drive (like in my case) the class mentioned above cannot see it (based on observation only, I did not decompile it). Windows 10 stores the content on another drive in WpSystem... folder. System will create a shortcut called LocalState junction, if you explore the default location using command prompt cmd, that point to the custom location.
I do not know what would be the best work around till it is fixed.

"Run Custom Tool" for resx files in MVC2 project (from an external application/script)

I am trying to get the localization for my MVC project working with our existing infrastructure for editing string resources. We store all our resource string in database tables and have a front end web UI to edit them with, and an export application which generated the .resx files. This all works great, but I am having a little difficulty with a new project using MVC2 and VS2010.
I have asked another question on this, the answer to which almost got me there, but not quite.
I have now changed the resources to be in a Resources folder (instead of App_GlobalResources), as recommended by a number of people. And have the following settings against my .resx files ...
Build Action = Embedded Resource
Copy to Output Directory = Do not copy
Custom Tool = PublicResXFileCodeGenerator
Custom Tool Namespace = Resources
File Name = MyApp.resx
I have changed my export application to run the resgen.exe tool with the following parameters ...
string args = string.Format("/publicClass \"{0}\" /str:cs,Resources,{1},\"{2}\"", resourceFile, Path.GetFileNameWithoutExtension(resourceFile), csFilename);
... which generates an almost identical .designer.cs file as I get when I add the .resx file to my project initially. The only difference is the
The generated .designer.cs file differs slightly from the file I get when I run the resgen.exe tool from within my export application.
This is the code generated by VS2010 when I first add the .resx file to my Resources folder ...
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Resources.MyApp", typeof(MyApp).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
... the difference when I run the resgen.exe tool is that is prefixs MyCompany.MyApp to the namespace in the constructor to ResourceManager
new global::System.Resources.ResourceManager("MyCompany.MyApp.Resources.MyApp", typeof(MyApp).Assembly);
Now, this to me seems to be a bug in the resgen.exe tool, because I've told it that the Namespace for my resources is Resources, not MyCompany.MyApp.Resources.
So, is there a fix/work-around for this problem?
The only thing I can think to do at the moment is to post-process the generated .designer.cs file with powershell and fix it!
Finally, I have solved the problem.
I decided to simplify things a bit by breaking my resources out in to a new assembly called Resources. I then added my resx files and set the properties for them as below ...
Build Action = Embedded Resource
Copy to Output Directory = Do not copy
Custom Tool = PublicResXFileCodeGenerator
Custom Tool Namespace = Resources
File Name = MyApp.resx
I then changed my export application to run ...
resgen MyApp.resx /str:c#,Resources,MyApp,MyApp.designer.cs /publicClass
... and to delete *.resources from the folder (created by the resgen.exe utility, but not needed)
This got rid of the prefix on the constructor to ResourceManager, and then i just added a reference to my new Resources assembly to my web application.
I've run a few tests to make sure all is good, including going in to the .designer.cs file and deleting one of the properties to cause a compiler error. Then re-ran my export app, and everything worked again.
So, I am a happy bunny!

XNA Framework Importers

I am working on a game using the XNA framework. My game has several levels which I am storing the data in a plain old text file. In VS 2008 when I add the level file to the project and compile, I receive the following error message.
Error 1 Cannot autodetect which importer to use for "Levels\0.txt". There are no importers which handle this file type. Specify the importer that handles this file type in your project. F:\Projects\BrickBreaker\BrickBreaker\Content\Levels\0.txt BrickBreaker
The reason I am bringing this out is because if I change on of my levels and run the game, the level is not updated. I have found that the level is not updated because VS runs the game from the bin\debug folder and since the level files are not included in the project, they are not copied when they change. I also found that the platform sample that comes with the framework includes the level data in the project, that's where I got the technique from.
So, should I use a different file format or just deal with having to manually copy the new level files over?
Resolution - After digging into the answers on this post I found a solution. I added the text files to the project and set the build property to none. The error no longer occurs when compiling and the file is included in the project.
You can have Visual Studio just copy over the files if you want to the output directory. Under the properties of the text file in the project, choose Build Action: None and change the copy to output directory to as needed.
You can also check out the platformer sample. They use text files as their level format.
There is no content importer for text files. Ignore the content pipeline and just read the file in just as you would any other normal text file.
string line = string.empty;
using(StreamReader sr = new StreamReader("filename")){
while((line = sr.ReadLine()) != null){
//reads line by line until eof
//do whatever you want with the text
}
}
I had similar problem, and found it easier to have the files added to content project, and build action set to none, than to skip content pipeline altogether.

Resources