GetFileFromApplicationUriAsync, CopyAsync, AsStreamForRead not implemented in Uno Platform. Workarounds? - uno-platform

I tried to use the following methods, but all of them appeared as not implemented in Uno (Android). What can I do?
Is there any Xamarin.Essentials alternative?
Or other NuGet package?
Or should I use native implementations on each platform?
And is it even possible to implement it in Uno directly?
var pdfFile = StorageFile.GetFileFromApplicationUriAsync(..);
pdfFile.CopyAsync(..);
(await pdfFile.OpenReadAsync()).AsStreamForRead(); // AsStreamForRead() not implemented
I'm using v1.45.0 of Uno.UI.

As David Oliver pointed out in his answer,
Uno hasn't implemented most of the Windows.StorageFile APIs, as for
the most part there are alternatives available in System.IO, which
will work cross-platform.
So...
To open file from the app package we can set its build action to Embedded Resource instead of Content. And instead of StorageFile.GetFileFromApplicationUriAsync() method we can use this code:
public Stream GetStreamFromResourceFile(string filename, Type callingType = null)
{
var assembly = (callingType ?? GetType()).Assembly;
string foundResourceName = assembly.GetManifestResourceNames().FirstOrDefault(r => r.EndsWith(filename, StringComparison.InvariantCultureIgnoreCase));
if (foundResourceName == null)
throw new FileNotFoundException("File was not found in application resources. Ensure that the filename is correct and its build action is set to 'Embedded Resource'.", filename);
return assembly.GetManifestResourceStream(foundResourceName);
}
to copy a file
await pdfFile.CopyAsync(..);
we change to:
await pdfFile.CopyToAsync(newFile);
and to get a stream for read
(await pdfFile.OpenReadAsync()).AsStreamForRead();
we use:
File.OpenRead(pdfFile);
So in the end we have:
string filename = "File.pdf";
var pdfFile = GetStreamFromResourceFile(filename, GetType());
string newFilePath = Path.Combine(ApplicationData.Current.LocalFolder.Path, filename);
using (var newFile = File.Create(newFilePath))
{
await pdfFile.CopyToAsync(newFile);
}
var fileStream = File.OpenRead(newFilePath);

Uno hasn't implemented most of the Windows.StorageFile APIs, as for the most part there are alternatives available in System.IO, which will work cross-platform.
If you're trying to display a pdf, however, there's no cross-platform option currently. On Android the best way to display a pdf is to launch an intent, on iOS it's possible to display the pdf in a WebView.
Partial example code for Android:
public async Task Read(CancellationToken ct, string filePath)
{
var intent = new Intent(Intent.ActionView);
var file = new Java.IO.File(filePath);
var contentUri = Android.Support.V4.Content.FileProvider.GetUriForFile(ContextHelper.Current, _fileProviderAuthority, file);
intent.SetFlags(ActivityFlags.GrantReadUriPermission);
intent.SetDataAndType(contentUri, "application/pdf");
StartActivity(intent);
}
Partial example code for iOS:
<ios:WebView
Source="{Binding FilePath}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />

Related

How do I get a link from FireBase? C#

I work with the C# language not java and do not yet know how to get a reference to an object in FireBaseStorage. I have the following code that should output a link from Fire Base Storage, but instead it outputs System.Threading.Tasks.Tast`1[The system.Line]
Tell me how do I get a link to a file from FireBaseStorage using FireSharp and FireBase libraries
here is my code: (C#)
FirebaseStorage storage = new FirebaseStorage("*******-****.appspot.com");
var starsRef = storage.Child("test.txt");
string link = starsRef.GetDownloadUrlAsync().ToString();
MessageBox.Show(link);
Don't know above C# that much, but whenever we do an asynchronous calls, don't we have to wait for result ? "await". Cause your ouput seems your thread is waiting for the result. System.Threading.Tasks.Tast`1[The system.Line]
Try using await before getting downloadUrl string link = await starsRef.GetDownloadUrlAsync().ToString(); and make your mehtod asynchronous in which you are writing your code.
C#
private void button28_ClickAsync(object sender, EventArgs e)
{
// Create a reference to the file we want to download
_ = getLinkAsync();
getLinkAsync();
}
public async Task getLinkAsync()
{
FirebaseStorage storage = new FirebaseStorage("firstbd-****.appspot.com");
var starsRef = storage.Child("test.txt");
string link = await starsRef.GetDownloadUrlAsync();
MessageBox.Show(link);
}

How to launch Apple wallet automatically for .pkpass file from Xamarin forms app

I have successfully created the .pkpass file and the api successfully returns the .pkpass file. In Xamarin forms I consume the API and try to add the .pkpass file into wallet but the wallet is not launching automatically.
The file which consumed from api via Xamarin app is working fine, there is no issue with the file. I have sent is as an email attachment and downloaded the attachment - the .pkpass file automatically opens with wallet app.
public async Task DigitalMembershipCardApple()
{
string accesstoken = _dataHelper.GetAccessTokenFromDBAsync().Result;
try
{
_oHttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accesstoken);
HttpResponseMessage response = await _oHttpClient.GetAsync(new Uri(Constants.Urls.DigitalMembershipCardApple + _dataHelper.GetPersonID()));
byte[] filebytes = await response.Content.ReadAsByteArrayAsync();
string filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), Constants.CISIMembershipCardFields.FileDownloadName);
if (File.Exists(filePath))
{
File.Delete(filePath);
File.WriteAllBytes(filePath, filebytes);
}
else
{
File.WriteAllBytes(filePath, filebytes);
}
await Launcher.OpenAsync(new OpenFileRequest
{
File = new ReadOnlyFile(filePath, Constants.CISIMembershipCardFields.MimeTypeApple)
});
}
catch (Exception ex)
{
Debug.WriteLine(ex.StackTrace);
throw ex;
}
}
I have also used the Xamarin essential launcher but that did not help.
Much appreciate a quick help
//Called from Xamarin Forms, now on iOS Project,
public async void AddToWallet(byte[] passByteArray)
{
NSData nsdata = NSData.FromArray(passByteArray);
NSError err = new NSError(new NSString("42"), -42);
PKPass newPass = new PKPass(nsdata, out err);
PKAddPassesViewController pkapvc = new PKAddPassesViewController(newPass);
await UIApplication.SharedApplication.KeyWindow.RootViewController.
PresentViewControllerAsync(pkapvc, true);
}
I don't use Apple wallet before while when I read document of PassKit in Xamarin.iOS, in the Adding Passes into Wallet section, it says:
Passes can be added to Wallet in the following ways:
Conduit Apps – These do not manipulate passes directly, they simply load pass files and present the user with the option of adding them to Wallet.
Companion Apps – These are written by providers to distribute passes and offer additional functionality to browse or edit them. Xamarin.iOS applications have complete access to the PassKit API to create and manipulate passes. Passes can then be added to Wallet using the PKAddPassesViewController. This process is described in more detail in the Companion Applications section of this document.
Mail is Conduit Application, it recognizes attachment as a Pass so the wallet app opens automatically .
Your xamarin app is Companion App, passes can then be added to Wallet using the PKAddPassesViewController. Read the file in your app won't open the wallet app.
My idea is you can download the file and follow the steps here to open the wallet app by using dependency-service in iOS project.
I used a different approach that show a popup to add multiple passes or review them.
Call this using a dependency service:
public async void AddAppleWalletPass(byte[] passByteArray)
{
if (PKPassLibrary.IsAvailable)
{
var library = new PKPassLibrary();
var passes = library.GetPasses();
NSData nsdata = NSData.FromArray(passByteArray);
NSError err = new NSError(new NSString("42"), -42);
PKPass newPass = new PKPass(nsdata, out err);
PKPass[] pKPasses = new PKPass[] { newPass };
await library.AddPassesAsync(pKPasses);
}
else
{
new UIAlertView("Alert", "Wallet is not available!", null, "Ok", null).Show();
}
}

Where to store tokens in a xamarin.form application

I have the class below that will be used in a xamarin.forms mobile application
to retrieve the token generated by OAuth(webapi). Once this is generated I need to store
in a place where I can access it again and not generating this all the time.
Where is the best place to store this in the Pcl? I will also want to be able to remove this once
the user logs off.
class LoginService
{
public async Task Login(string username, string password)
{
HttpWebRequest request = new HttpWebRequest(new Uri(String.Format("{0}Token", Constants.BaseAddress)));
request.Method = "POST";
string postString = String.Format("username={0}&password={1}&grant_type=password",
HttpUtility.HtmlEncode(username), HttpUtility.HtmlEncode(password));
byte[] bytes = Encoding.UTF8.GetBytes(postString);
using (Stream requestStream = await request.GetRequestStreamAsync())
{
requestStream.Write(bytes, 0, bytes.Length);
}
try
{
HttpWebResponse httpResponse = (HttpWebResponse)(await request.GetResponseAsync());
string json;
using (Stream responseStream = httpResponse.GetResponseStream())
{
json = new StreamReader(responseStream).ReadToEnd();
}
TokenResponseModel tokenResponse = JsonConvert.DeserializeObject(json);
return tokenResponse.AccessToken;
}
catch (Exception ex)
{
throw new SecurityException("Bad credentials", ex);
}
}
}
Token(s) being sensitive information, I would recommend storing them in a secure manner. Secure storage is available through Keychain services in iOS, and the KeyStore class in Android. Xamarin has a very good article on how to do that using Xamarin.Auth.
Other options available are:
BlobCache.Secure in Akavache
SecureStorage
Secure storage in XLabs
Just an update for anyone searching, as things have changed since this post was created. It is not advised to use the following any more:
Application.Current.Properties
To securely store things like access tokens etc you can use the Xamarin.Essentials SecureStorage static class.
Just add the Xamarin.Essentials nuget package if you don't already have it and use it like so:
using Xamarin.Essentials;
.
.
.
await SecureStorage.SetAsync("someKey", "someValue");
var myValue = await SecureStorage.GetAsync("someKey");
you also have the option to
SecureStorage.Remove("someKey");
//or
SecureStorage.RemoveAll();
Refer this for more documentation
Forms has a built in Properties dictionary where you can store small bits of persistent data.
Application.Current.Properties ["token"] = myToken;

Predefined database in windows phone 8.1 app

Where predefined database (.db) should add and how to use it in windows phone 8.1 app?
I am not using Silverlight in my app.
I was trying to do something like this
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
CopyDatabase();
}
private void CopyDatabase()
{
IsolatedStorageFile ISF = IsolatedStorageFile.GetUserStoreForApplication();
String DBFile = "myDB.sqlite";
if (!ISF.FileExists(DBFile)) CopyFromContentToStorage(ISF, "Assets/myDB.sqlite", DBFile);
}
It showing that the namespace name IsolatedStorageFile could not be found.
I found those codes in a sample database app for Windows-phone-8.0 and I was trying to do the same thing in Windows-phone-8.1 (without Silverlight).
As I see you try to copy the database from package to IsolatedStorage and you are targeting WinRT. The sample code can llok like this:
private async Task<bool> CopyDatabase()
{
StorageFolder packageFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFile file = await packageFolder.GetFileAsync("Assets/myDB.sqlite");
await file.CopyAsync(localFolder);
return true;
}
I've written this code from the top of my head, but should work or help you to find the solution. The above is also possible by Uri schemes:
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(#"ms-appx:///Assets/myDB.sqlite"));
More about Data and Files you will find at MSDN.

OpenStack Rackspace Cloud Files .net SDK

I am trying to save an XML file to a non CDN Container from Sydney:
public void Save(XDocument document)
{
using (MemoryStream ms = new MemoryStream())
{
document.Save(ms);
ms.Position = 0;
RackspaceCloudIdentity identity = new RackspaceCloudIdentity { Username = "username", APIKey = "xxxxxxxxxxx", CloudInstance = CloudInstance.Default };
CloudFilesProvider provider = new CloudFilesProvider(identity);
provider.CreateObject("XMLFiles", ms, "xmlFile1.xml", region: "syd");
}
}
For a 1MB file, it takes about 50 seconds to upload (very long).
And, trying to download the file back, returns an empty result:
public void Read()
{
RackspaceCloudIdentity identity = new RackspaceCloudIdentity { Username = "username", APIKey = "xxxxxxxxxxx", CloudInstance = CloudInstance.Default };
CloudFilesProvider provider = new CloudFilesProvider(identity);
using (MemoryStream ms = new MemoryStream())
{
provider.GetObject("XMLFiles", "xmlFile1.xml", ms, region: "syd");
// ms.Length is 0
}
}
I am doing something wrong?
Ugh. I introduced this bug in commit 799f37c (first released in v1.1.3.0). I'm looking into the best workaround right now.
Edit: There is no workaround, but I filed issue #116 for the issue, and after the pull request for it is merged, we'll release version 1.1.3.1 of the library to correct the problem.
Are you able to access your control panel at mycloud.rackspace.com?
I used my control panel to upload an XML file, then used your code, above, to download the XML file. It worked fine.
I'm going now use the upload code you posted.
Just wanted you to know I'm looking into this.

Resources