How to select a file in finder in Xamarin? - macos

I am trying to select a file in the Finder, that is not happening the method works well in Obj-C but in Xamarin Finder gets activated but the file is not getting selected.
Whereas if I use Xamarin command to open the file it opens.
Here is the snippet of code that I wrote. Guide me if I am doing something wrong or missing anything?
public override void DidFinishLaunching(NSNotification notification)
{
string fullPath = "/Users/anoopvaidya/Desktop/A/ClientInfoConfig.cs";
NSUrl url = NSUrl.FromString(fullPath);
NSUrl[] urls = { url };
NSWorkspace.SharedWorkspace.OpenFile(fullPath);
//works. But I only want to select in Finder
NSWorkspace.SharedWorkspace.ActivateFileViewer(urls);
//doesn't work
}
Is it related to OS version? I am using 10.13.6.

You need to use a file:// based url:
Example:
using (var url = new NSUrl("file", "localhost", "/Users/Sushi/Desktop/StackOverflow.png"))
{
NSWorkspace.SharedWorkspace.ActivateFileViewer(new NSUrl[] { url });
}

Related

Download path in Xamarin iOS

I am using Xamarin.Forms and written the code to download the file for the iOS
platform. It is downloading the file successfully without any error. But after downloading it, I am not able to find the downloaded file in my apple device.
During debugging I found that it is showing
/var/mobile/Containers/Data/Application/1234567A-B8CD-9EF9-C850-9G73587DC7C/Documents/XF_Downloads/hausmann_abcd.jpg
path. So at which location file get saved? below is the image for the same.
I have written below code for this
public class IosDownloader : IDownloader
{
public event EventHandler<DownloadEventArgs> OnFileDownloaded;
public void DownloadFile(string url, string folder)
{
string pathToNewFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), folder);
Directory.CreateDirectory(pathToNewFolder);
try
{
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
string pathToNewFile = Path.Combine(pathToNewFolder, Path.GetFileName(url));
webClient.DownloadFileAsync(new Uri(url), pathToNewFile);
}
catch (Exception ex)
{
if (OnFileDownloaded != null)
OnFileDownloaded.Invoke(this, new DownloadEventArgs(false));
}
}
private void Completed(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
if (OnFileDownloaded != null)
OnFileDownloaded.Invoke(this, new DownloadEventArgs(false));
}
else
{
if (OnFileDownloaded != null)
OnFileDownloaded.Invoke(this, new DownloadEventArgs(true));
}
}
}
When a file is saved on an application it is a temporary url within the app's sandbox. To make this image file be publicly accessible through Apple's Photos, You'll have to use native code to do a request to add a new PHImageAsset to the photos library.
In forms you would need to access the native frameworks and therefore run native code. There are plenty of examples of doing this online if you don't know how to already. But here is an introduction if you want to run native code within a shared code framework. https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/dependency-service/introduction
Here is a sample of taking that temp file URL and saving it to Photos Framework once you can code w/ native Xamarin.iOS frameworks:
public void AddImageUrlToPhotosLibrary(string urlToSaveToPhotos)
{
PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => {
//This is bound to native https://developer.apple.com/documentation/photokit/phassetchangerequest/1624060-creationrequestforasset
//Parameter is an NSURL of path to image.
PHAssetChangeRequest.FromImage(new NSUrl(urlToSaveToPhotos));
}, (completed, error) => {
if (completed)
{
if (error != null)
{
Console.WriteLine($"Failed saving image asset {error.LocalizedDescription}");
} else
{
Console.WriteLine($"Successfully saved image to photos library.");
}
}
});
}
I am not able to find the downloaded file in my apple device.
If you use a simulator, you can directly find the folder in the mac by entering the path in the
your mac --> select Finder --> Then open the Go menu --> Click Go to Folder as I described in this thread:
Where can I find the MyDocuments folder on iPhone Simulator?
If you installed the app in a real device. You can browse the file in
Xcode --> Devices and Simulators --> download container as described in this thread:
Browse the files created on a device by the iOS application I'm developing, after downloading the container, you can right click it and choose Show Package Contents. Then you can see the folders.
You can also access the file by the path in the project.

Define download path dotnetbrowser

I use dotnetbrowser to display a web browser on a old windows framework.
have you an idea to define the download path ?
My dotnetbroser is enable, i can show my webpage but i don't found in documentation or exemple how define this simple download path.
The only exemple that i've found is about the download event detection.
I use WPF in C#
Thanks.
The DotNetBrowser.DownloadItem.DestinationFile property is writable and can be used to configure the path to store the file.
To set this property in your application, you need to subclass the DotNetBrowser.DefaultDownloadHandler and implement its AllowDownload(DownloadItem) method. Then you need to configure your download handler as shown in the documentation article: File Download
You can also configure and use DotNetBrowser.WPF.WPFDefaultDownloadHandler instance to show file chooser and select the path to store the file.
This is a solution
Défine your browser like variable :
BrowserView myBrowserView;
Browser myBrowser;
Create the browser properly :
this.myBrowser = BrowserFactory.Create();
this.myBrowserView = new WPFBrowserView(this.myBrowser);
Create event detection for download
this.myDowloadHandler = new SampleDownloadHandler();
this.myBrowser.DownloadHandler = myDowloadHandler;
Add it to a container, here, a grid
grid_navigateur.Children.Add((UIElement)myBrowserView.GetComponent());
Now we are going to use our "SampleDownloadHandler" class
class SampleDownloadHandler : DownloadHandler
{
public bool AllowDownload(DownloadItem download)
{
download.DestinationFile = "exemple\of\path\whith\file\name";
download.DownloadEvent += delegate(object sender, DownloadEventArgs e)
{
DownloadItem downloadItem = e.Item;
if (downloadItem.Completed)
{
System.Windows.MessageBox.Show("Download complete");
}
};
return true;
}
My personalisated class define path and name of the file who is download and pop a message when is over.
(to found the file name, you do to cut the string download.DestinationFile after the last )

Xamarin.Forms App return data to calling App

So, either I am asking incorrectly, or it isn't possible, let's see which...
If my app (Xamarin.Forms) is launched from another app, in order to get a url from my app, how do I return that data to the calling app? I wrongly assumed SetResult and Finish, I also wrongly assumed StartActivityForResult, but there has to be a way to do this. I know how to get data INTO my app from another app, but not the same in return.
POSSIBLE PARTIAL SOLUTION -- UPDATE, FAILS
So I have to setup an interface in my PCL, and call the method from the listview item selected handler, in the Android app I can then do this:
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_url"));
setResult(Activity.RESULT_OK, result);
finish();
(source: https://developer.android.com/training/basics/intents/filters.html)
Is this looking right, and how would I implement the same thing on iOS?
END
I deleted my previous question because I couldn't explain the problem clearly, so here goes.
I have a Xamarin Forms app, I want to use a section of this app as a gallery. Currently I have images displayed in a list, and I have an Intent filter set that launches this page when you select the app as the source for an image (such as upload image on Facebook).
My issue is that I don't know how to return the data (the selected image) back to the app / webpage that made the request. In android I understand that you would use StartActivityForResult and OnActivityResult to handle this, but I am using Xamarin Forms (Android, iOS, UWP) and can't really find a solution that could be used cross-platform.
Just a link to documentation that covers this would be great, but if you have an example then even better.
Thanks
EDIT
Here is the code used to launch the app, I am interested in getting data back from the Intent.ActionPick after the user has selected an image from a ListView, which is in a ContentPage in the PCL.
[Activity(Label = "", Icon = "#drawable/icon", Theme = "#style/DefaultTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
[IntentFilter(new[] { Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = #"*/*")]
[IntentFilter(new[] { Intent.ActionView, Intent.ActionPick, Intent.ActionGetContent }, Categories = new[] { Intent.CategoryDefault, Intent.CategoryOpenable }, DataMimeType = #"*/*")]
public class MainActivity : FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
try
{
base.OnCreate(bundle);
CurrentPlatform.Init();
Xamarin.Forms.Forms.Init(this, bundle);
App _app = new App();
LoadApplication(_app);
if (Intent.Action == Intent.ActionSend)
{
var image = Intent.ClipData.GetItemAt(0);
var imageStream = ContentResolver.OpenInputStream(image.Uri);
var memOfImage = new System.IO.MemoryStream();
imageStream.CopyTo(memOfImage);
_app.UploadManager(memOfImage.ToArray()); //This allows me to upload images to my app
}
else if (Intent.Action == Intent.ActionPick)
{
_app.SelectManager(); //here is where I need help
}
else
{
_app.AuthManager(); //this is the default route
}
}
catch (Exception e)
{
}
}
It seems you cannot use remote URI to provide to calling app. Some posts I checked suggest to store the file locally and provide it's path to calling app. To avoid memory leak with many files stored I suggest to use the same file name then you will have only one file at any moment.
One more note. I tested this solution in facebook. Skype doesn't seem to accept that and, again, the posts I checked saying that Skype doesn't handle Intent properly (not sure what that means).
Now to solution. In main activity for example in OnCreate method add the follow.
ReturnImagePage is the name of my page class where I select an image
Xamarin.Forms.MessagingCenter.Subscribe<ReturnImagePage, string>(this, "imageUri", (sender, requestedUri) => {
Intent share = new Intent();
string uri = "file://" + requestedUri;
share.SetData(Android.Net.Uri.Parse(uri));
// OR
//Android.Net.Uri uri = Android.Net.Uri.Parse(requestedUri);
//Intent share = new Intent(Intent.ActionSend);
//share.PutExtra(Intent.ExtraStream, uri);
//share.SetType("image/*");
//share.AddFlags(ActivityFlags.GrantReadUriPermission);
SetResult(Result.Ok, share);
Finish();
});
Above will listen for the message when the image is selected.
Then in XFroms code when image is selected dowload it, store it, get path and send to Activity using it's path. Below is my test path
MessagingCenter.Send<ReturnImagePage, string>(this, "imageUri", "/storage/emulated/0/Android/data/ButtonRendererDemo.Droid/files/Pictures/temp/IMG_20170207_174559_21.jpg");
You can use static public class to save and access results like:
public static class StaticClass
{
public static int Result;
}

xamarin ios 10 open app store application programmatically in my app

i'm trying to open app store application programmatically in my app.
what i'm trying to do is that i'm calling a service to check at the current app version and if it needs update i should open app store application to let the user update the my app.
note: the app not published yet to the store, i'm still in coding phase.
i tried to use the following code in ViewDidLoad method, but it's not working (nothing happened):
var nsurl = new NSUrl("itms://itunes.apple.com");
UIApplication.SharedApplication.OpenUrl(nsurl);
A direct link via itms: will only work in an actual device, if you are testing on a simulator, use https://itunes.apple.com/us/genre/ios/id36?mt=8 instead.
I would recommend using itms:// link on the actual device as it prevents the redirects that user sees when using a https:// link to open iTunes.
bool isSimulator = Runtime.Arch == Arch.SIMULATOR;
NSUrl itunesLink;
if (isSimulator)
{
itunesLink = new NSUrl("https://itunes.apple.com/us/genre/ios/id36?mt=8");
}
else
{
itunesLink = new NSUrl("itms://itunes.apple.com");
}
UIApplication.SharedApplication.OpenUrl(itunesLink, new NSDictionary() { }, null);
Instead of opening the external Store app on the device, you might want to consider keeping the user inside of your app by using a SKStoreProductViewController:
bool isSimulator = Runtime.Arch == Arch.SIMULATOR;
if (!isSimulator)
{
var storeViewController = new SKStoreProductViewController();
storeViewController.Delegate = this;
var id = SKStoreProductParameterKey.ITunesItemIdentifier;
var productDictionaryKeys = new NSDictionary("SKStoreProductParameterITunesItemIdentifier", 123456789);
var parameters = new StoreProductParameters(productDictionaryKeys);
storeViewController.LoadProduct(parameters, (bool loaded, NSError error) =>
{
if ((error == null) && loaded)
{
this.PresentViewController(storeViewController, true, () =>
{
Console.WriteLine("SKStoreProductViewController Completed");
});
}
if (error != null)
{
throw new NSErrorException(error);
}
});
}
else
{
var itunesLink = new NSUrl("https://itunes.apple.com/us/genre/ios/id36?mt=8");
UIApplication.SharedApplication.OpenUrl(itunesLink, new NSDictionary() { }, null);
}
NSBundle.MainBundle.InfoDictionary["CFBundleVersion"]
Returns you the current app version.
To open the Apple Appstore just let the user navigate to the appstore link, Apple will automaticly detect that the user is using an iPhone and will open the Appstore for them.
Test yourself:
Open the following link in safari: Whatsapp in the Appstore
It will automatically open the appstore.
When you create app on iTunesConnect you can get url to your future app in AppStore even if you didn't release it yet. You can find it under App Information tab:
In your app you can just open it:
var nsurl = new NSUrl("https://itunes.apple.com/us/app/mygreatapp/id123456789");
UIApplication.SharedApplication.OpenUrl(nsurl);

Detecting the Location your cocoa swift application is running from

I'm trying but unable to find out if there is a way using swift to detect the path and name of the .app file that is running
ie if my app is selfupdater.app and its stored in ~username/applications
how can i get this information when selfupdater.app is launched as a string variable in swift
This is called your main bundle folder.
Swift 3 or later
extension URL {
var parentDirectory: URL? {
return (try? resourceValues(forKeys: [.parentDirectoryURLKey]))?.parentDirectory
}
}
let bundleURL = Bundle.main.bundleURL
if let path = bundleURL.parentDirectory?.path {
print(path)
}

Resources