Handling a file, "Open with" or "Share" options

Hi, I have an application that needs to handle different kind of files (Images,Videos,PDF,DOC,etc). Now I'd like to have a list that contains different kind of files.
When I select a voice i'd like to open the view "open with" like android or iOS where you can choose the application that will open that file. How can I achieve this?

Best Answers

Answers

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    There is a topic about open pdf file on android that present a solution to this problem. Try to search it in the forum

  • DquaglioDquaglio ITMember

    @AlessandroCaliaro Are you referring to this? Because there are some solutions, but I'd like to open the default control. Is the control that let you choose which app should open that file a system control? or each app need to create it's own?

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    Ciao
    Yes if you take a look to the last post it's a solution. If there is only an app that can open the file, android use it, otherwise it ask to you what app to use. There is also something for iOS I have post in the forum. For wp sorry but I have nothing

  • DquaglioDquaglio ITMember

    @RaphaelSchindler @AlessandroCaliaro So the view where I have to choose which app, is not a system one, but I need to create my own right? By the way thanks for the code and help, tomorrow I'll give it a deep look but it seems exactly what I needed.

  • DquaglioDquaglio ITMember
    edited October 2015

    @RaphaelSchindler What is that QLPreviewController?
    @AlessandroCaliaro From what I see from the iOS code seems like you need to create your own view. The one where you have to choose which app will open that file.

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @Dquaglio I have to dig in this code again, as I haven't looked at it a long time. I'll post an update.

  • DquaglioDquaglio ITMember

    @RaphaelSchindler @AlessandroCaliaro I'm having some problems with this, it seems like the dependencyService is not able to get this classes. Is there any other particular option to enable this feature? I'm testing on iOS for now

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @Dquaglio Which classes exactly. If you make that clear I can dig in the code again and help you

  • DquaglioDquaglio ITMember

    @RaphaelSchindler Ok found it, on the implementation of IDocumentViewer is needed a constructor without parameters.

  • DquaglioDquaglio ITMember

    @RaphaelSchindler I'm now testing Android, mimeType what should be like?

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @Dquaglio Depends on what you're trying to display. I have a Helper class were I define the mime types for any file. Since they are stored in a weird way in our database.

    public class MimeTypes
    {
        public string Png => "image/png";
    
        public string Docx => "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
    
        public string Doc => "application/word";
    
        public string Csv => "text/csv";
    
        public string Txt => "text/plain";
    
        public string Mp3 => "audio/mpeg";
    
        public string Jpeg => "image/jpeg";
    
        public string Pdf => "application/pdf";
    
        public string Xls => "application/vnd.ms-excel";
    
        public string Xlsx => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    }
    
  • DquaglioDquaglio ITMember

    @RaphaelSchindler I'm not able to open files with android, for pdf it try to open it with google drive and then says impossible to open file, with a txt it show some programs but I can't open it.
    Here is the code that I'm using to save the file:

    if (!string.IsNullOrEmpty (fileName)) { var ws = IoC.Resolve<IWebServicesFactory> ().Create (); var result = await ws.GetImageStream (fileName, folderName); string folderPath = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData); var path = Path.Combine (folderPath, fileName); File.WriteAllBytes (path, result); var docService = DependencyService.Get<IDocumentViewer>(); var extension = Path.GetExtension(path); docService.ShowDocumentFile(path,MimeTypes.GetMimeType(extension)); }

    then tried your code and tried to change something but nothing, here is the current code that I'm trying :
    public void ShowDocumentFile(string filepath, string mimeType) { //var uri = global::Android.Net.Uri.Parse ("file://" + filepath); var intent = new Intent(Intent.ActionView); var file = new Java.IO.File(filepath); file.SetReadable(true); var uri = global::Android.Net.Uri.FromFile(file); //intent.SetData (uri); //intent.SetType (mimeType); intent.SetDataAndType(uri, mimeType); intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask); intent.AddFlags (ActivityFlags.GrantReadUriPermission); intent.AddFlags (ActivityFlags.GrantWriteUriPermission); try { Forms.Context.StartActivity(Intent.CreateChooser(intent, "Select App")); } catch(Exception ex) { //Let the user know when something went wrong } }

  • JulienRosenJulienRosen CAMember ✭✭✭✭
    edited December 2015

    I am using the following code to attempt to download a PDF and open it.

    try
    {
        using (var httpClient = new HttpClient(new NativeMessageHandler()))
        {
            using (var pdfBytes = await httpClient.GetStreamAsync("https://ios-dev.infotracsolutions.com/infotracmobileapi/beta/datadsm/samplepdf.pdf"))
            {
                var rootFolder = FileSystem.Current.LocalStorage;
                var file = await rootFolder.CreateFileAsync("samplepdf.pdf", CreationCollisionOption.ReplaceExisting);
    
                using (var outputStream = await file.OpenAsync(FileAccess.ReadAndWrite))
                {
                    pdfBytes.CopyTo(outputStream);
                }
            }
        }
    
        var documentViewer = Resolver.Resolve<IDocumentViewer>();
        var path = System.IO.Path.Combine(FileSystem.Current.LocalStorage.Path, "samplepdf.pdf");
        documentViewer.ShowDocumentFile(path, "application/pdf");
    }
    catch (Exception ex)
    {
        var temp = ex.Message;
    }
    

    The code does not error, but it just says it can't display the PDF, I am guessing because my paths are somehow wrong?

    Can someone maybe point out what I am doing wrong?

    Edit: this works on iOS, but not Android

  • ManishpManishp USMember ✭✭
    edited December 2016

    Hi @RaphaelSchindler ,

    Code is worked for android but not for iOS.
    FindNavigationController() method always return null.

    private UINavigationController FindNavigationController() { foreach(var window in UIApplication.SharedApplication.Windows) { if(window.RootViewController.NavigationController != null) { return window.RootViewController.NavigationController; } else { UINavigationController value = CheckSubs(window.RootViewController.ChildViewControllers); if(value != null) { return value; } } } }
    Please suggest.

    Thanks.

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @Manishp What iOS Version? My Code is for iOS 8 or 9 if I remember correctly.

  • ManishpManishp USMember ✭✭

    @RaphaelSchindler I am using iOS 9.

  • ManishpManishp USMember ✭✭

    Any other solution to 'open with' for images/video in iOS?

  • ManishpManishp USMember ✭✭

    Actually I have stored file data in form of byte array I believe I need to first write a file using byte array and then pass the path of file to your method would work. Can you help me to know how can I write byte array in a file in iOS ?

  • kavya16kavya16 USMember ✭✭

    @JulienRosen : Please can you help me with "Resolver.Resolve();" ... unable to understand this "Resolver.Resolve". Kindly help me with this.

  • MIFMIF USMember ✭✭

    @RaphaelSchindler
    Thanks for the code, it works for me. I just want to add 2 cents from myself.
    You can use MimeTypeMap (Android.Webkit namespace) and ignore mimeType parameter altogether:

      var fileExtension = System.IO.Path.GetExtension(filePath);
      string mimeType = null;
      if (!string.IsNullOrWhiteSpace(fileExtension))
      {
        fileExtension = fileExtension.Trim('.', ' ');
        mimeType = MimeTypeMap.Singleton.GetMimeTypeFromExtension(fileExtension);
      }
    
  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭
    edited June 2017

    @MIF Thanks, I wasn't aware of this. Does this work on iOS too? Or do you even need it in iOS? I'm really not sure anymore^^

  • MIFMIF USMember ✭✭

    In code you provided mimeType parameter is not used at all :)

  • BenjaminFunkBenjaminFunk USMember ✭✭

    iOS doesn't need the mimeType but Android does, otherwise for me it tries to load everything in the PDF viewer, which doesn't work for non-PDFs. This works great for me in iOS, too.

    This solution works perfectly for me on both platforms. Coming from a platform that relatively few people use and even fewer people talk about online (Genero Mobile), I'm finding Xamarin Forms to be a breath of fresh air.

  • shivindershivinder USMember ✭✭
    edited October 2017

    I am able to open the file successfully using the provided code, but if my file has a link to a website or email and i click on the link, the app just kind of freezes. Anyone have any idea why that would be happening?

  • thanhtongthanhtong VNMember ✭✭

    @Manishp said:
    Hi @RaphaelSchindler ,

    Code is worked for android but not for iOS.
    FindNavigationController() method always return null.

    private UINavigationController FindNavigationController() { foreach(var window in UIApplication.SharedApplication.Windows) { if(window.RootViewController.NavigationController != null) { return window.RootViewController.NavigationController; } else { UINavigationController value = CheckSubs(window.RootViewController.ChildViewControllers); if(value != null) { return value; } } } }
    Please suggest.

    Thanks.

    I have the same problem. Did you solved it?

    @RaphaelSchindler I tested on Simulator iPhone 8 (iOS 11.2)
    FindNavigationController() method always return null.
    Do you have any advice for this problem?

  • ManoNagarajanManoNagarajan USMember ✭✭

    @thanhtong

    private UINavigationController CheckSubs(UIViewController[] controllers)
    {
    foreach(var controller in controllers)
    {
    if(controller.NavigationController != null)
    {
    return controller.NavigationController;
    }
    else
    {
    UINavigationController value = CheckSubs(controller.ChildViewControllers)
    if(value != null)
    {
    return value;
    }
    }

                return null;
            }
        }
    

    Remove return null from this function. Refer below function

    public UINavigationController CheckSubs(UIViewController[] controllers)
    {
    UINavigationController v=null;
    foreach (var controller in controllers)
    {
    if (controller.NavigationController != null)
    {
    v= controller.NavigationController;
    }
    else
    {
    UINavigationController value = CheckSubs(controller.ChildViewControllers);
    if (value != null)
    {
    v= value;
    }
    }

               // v= null;
            }
            return v;
        }
    
  • ManoNagarajanManoNagarajan USMember ✭✭

    How to handle done button click event?

  • aeodeveloperaeodeveloper Member ✭✭

    @RaphaelSchindler are your solution still work in current xamarin version or am I miss something? Help me please... :neutral:

  • VieGarcianoVieGarciano Member ✭✭

    @RaphaelSchindler said:
    @Dquaglio You have to use a DependecyService for this. Here's my solution:

    //Interface in PCL
    public interface IDocumentViewer
    {
        void ShowDocumentFile(string filepaht, string mimeType);
    }
    
    //Android
    [assembly: Dependency(typeof(DocumentViewer_Droid))]
    
    namespace YourApp.Droid
    {
        public class DocumentViewer_Droid : IDocumentViewer
        {
            public void ShowDocumentFile(string filepath, string mimeType
            {
                var uri = Android.Net.Uri.Parse("file://" + filepath);
                var intent = new Intent(Intent.ActionView);
                intent.SetDataAndType(uri, mimeType);
                intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);
    
                try
                {
                    Forms.Context.StartActivity(Intent.CreateChooser(intent, "Select App"));
                }
                catch(Exception ex)
                {
                    //Let the user know when something went wrong
                }
            }
        }
    }
    
    //iOS
    [assembly: Dependency(typeof(DocumentViewer_iOS))]
    
    namespace.YourApp.iOS
    {
        public class DocumentViewer_iOS : IDocumentViewer
        {
            public void ShowDocumentFile(string filepath, string mimeType)
            {
                var fileinfo = new FileInfo(filepath);
                var previewController = new QLPreviewController();
                previewController.DataSource = new PreviewControllerDataSource(fileinfo.FullName, fileinfo.Name);
    
                UINavigationController controller = FindNavigationController();
                
                if(controller != null)
                {
                    controller.PresentViewController((UIViewController)previewController, true, (Action)null);
                }
            }
    
            private UINavigationController FindNavigationController()
            {
                foreach(var window in UIApplication.SharedApplication.Windows)
                {
                    if(window.RootViewController.NavigationController != null)
                    {
                        return window.RootViewController.NavigationController;
                    }
                    else
                    {
                        UINavigationController value = CheckSubs(window.RootViewController.ChildViewControllers);
                        if(value != null)
                        {
                            return value;
                        }
                    }
                }
            }
    
            private UINavigationController CheckSubs(UIViewController[] controllers)
            {
                foreach(var controller in controllers)
                {
                    if(controller.NavigationController != null)
                    {
                        return controller.NavigationController;
                    }
                    else
                    {
                        UINavigationController value = CheckSubs(controller.ChildViewControllers)
                        if(value != null)
                        {
                            return value;
                        }
                    }
    
                    return null;
                }
            }
        }
    
        public class DocumentItem : QLPreviewItem
        {
            private string _title;
            private string _uri;
    
            public DocumentItem(string title, string uri)
            {
                _title = title;
                _uri = uri;
            }
    
            public override string ItemTitle
            { get { return _title; } }
    
            public override NSUrl ItemUrl
            { get { return NSUrl.FromFilename(_uri)); } }            
        }
    
        public class PreviewControllerDataSource : QLPreviewControllerDataSource
        {
            private string _url;
            private string _filename;
    
            public PreviewControllerDataSource(string url, string filename)
            {
                _url = url;
                _filename = filename;
            }
    
            public override IQLPreviewItem GetPreviewItem(QLPreviewController controller, nint index)
            {
                return (IQLPreviewItem)new DocumentItem(_filename, _url);
            }
    
            public override nint PreviewItemCount(QLPreviewController controller)
            { return (nint)1; }
        }
    }
    

    Can I still use this code now? I am getting errors. Please refer to the screenshot

Sign In or Register to comment.