Search Unity

Simple File Browser [Open Source]

Discussion in 'Assets and Asset Store' started by yasirkula, Nov 19, 2016.

  1. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    This asset uses Assembly Definition Files. You need to add SteamVR's Assembly Definition Files as reference to SimpleFileBrowser.Runtime.asmdef.
     
  2. hermetic

    hermetic

    Joined:
    Jan 24, 2018
    Posts:
    11
    Hi thanks for that asset. In Unity all works, but when I try to compile it for XR (android, Quest), it seems like I run into manifest problems. I have edited the manifest like you wrote on github. Also removed the <application..> in manifast on aar, but it stops the build with:

    NullReferenceException: Object reference not set to an instance of an object
    UnityEditor.AndroidXmlDocument.AppendElement (System.Xml.XmlNode node, System.String tag, System.String attribute, System.String attributeValue) (at <2975258ba72b4441a1487a1bed69dfb8>:0)
    UnityEditor.AndroidManifest.AppendAndroidNameTag (System.Xml.XmlElement element, System.String tag, System.String value, System.Collections.Generic.List`1[T] attributes) (at <2975258ba72b4441a1487a1bed69dfb8>:0)
    UnityEditor.AndroidManifest.AppendApplicationAndroidNameTag (System.Xml.XmlElement element, System.String tag, System.String value, System.Collections.Generic.List`1[T] attributes) (at <2975258ba72b4441a1487a1bed69dfb8>:0)

    Any idea what causes that?
     
  3. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    If you didn't get the error "
    attribute android:requestLegacyExternalStorage not found
    ", don't modify AndroidManifest. If the error occurred, the final version of AndroidManifest.xml inside SimpleFileBrowser.aar should look like this:
    Code (CSharp):
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.yasirkula.unity">
    3.     <uses-sdk android:targetSdkVersion="4" />
    4.     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:node="replace" />
    5.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="replace" />
    6. </manifest>
     
  4. hermetic

    hermetic

    Joined:
    Jan 24, 2018
    Posts:
    11
    Thanks for reply. yes I had to remove the <application..> cause if not, I get the ExternalStorage error (62 errors) in graddle phase and like you say on github, 'if not used andr.10', 'sdk 23', which I don't have yet. So with <application..> removed, I get only the 2 errors above.
    To reproduce:
    On the scene I use the UnityHub, 'VR' default (empty) scene on 2019.4... Switched to Android on 'player-settings', XR-Plug-in Management, with oculus on. Added a simple blue cube with your script on it. Manifest is yours on Assets/Plugins/Android/AndroidManifest.xml.
    Compile is on android 7.0.

    Strange thing is, even if I remove like you tell in github on /Temp/StagingArea/aar/SimpleFileBrowser.aar the <application...> line it's again there after unsucessful compile.
     
  5. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You should modify the AndroidManifest.xml inside Assets/Plugins/SimpleFileBrowser/Android/SimpleFileBrowser.aar, NOT Assets/Plugins/Android/AndroidManifest.xml. You should revert your changes to Assets/Plugins/Android/AndroidManifest.xml and then open SimpleFileBrowser.aar with WinRAR or 7-zip to modify its AndroidManifest.
     
  6. hermetic

    hermetic

    Joined:
    Jan 24, 2018
    Posts:
    11
    Thanks, it compiles/links now, but loads forever when started in headset and can't be stopped without restart headset. But this might be nailed out maybe. Thank you for being patient and your help!
     
  7. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Hmm, does the app work fine after removing the plugin? If it does, can you show the file browser upon a button click instead of showing it on Start in order to see if showing the file browser causes this issue? If Storage permission appears at app startup, deny the permission. Let file browser ask the permission. If there are no issues, reinstall the app and then accept the permission at app startup. If there are still no issues, show the file browser back in Start and see logcat logs.
     
  8. hermetic

    hermetic

    Joined:
    Jan 24, 2018
    Posts:
    11
    Hi, yup, all works normal without plugin. But no probs, I thought it like you, to make the filebrowser on a button too. And guess I have to change the canvas-screen for XR, maybe the input too. But as long it's into Unity, and not the Manifest-behavior, I should be able to find a way. Yup, storage permission is asked correct. When I disable your script I also can see the XR-enviroment, but input is locked. Will post when I get things working.
    A question: I have read that the manifest people link with android studio and that Unity has probs with it generally, is that the cause why you have it in an .arr?
     
    Last edited: Mar 17, 2021
  9. hermetic

    hermetic

    Joined:
    Jan 24, 2018
    Posts:
    11
    Update: After change of canvas-screen and resize, lock is gone and filebrowser shows up. But guess still need some work on the buttons, so XR-hands/ray can do functions. Anyway, all nice so far!
     
    yasirkula likes this.
  10. larry2013z

    larry2013z

    Joined:
    Apr 14, 2020
    Posts:
    36
    When the Save Dialog opens up I am getting the following warning "There are 2 event systems in the scene. Please ensure there is always exactly one event system in the scene"

    I have an Event System already in the Scene for my UI, I can see that SimpleFileBrowser is also creating one for the Save dialog box as a child of SimpleFileBrowserCanvas(Clone). How can I properly get rid of this warning message? Do I somehow disable my Event System or can I just ignore the warning?
     
    Last edited: Mar 28, 2021
  11. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You can remove EventSystem component from SimpleFileBrowserCanvas.
     
  12. larry2013z

    larry2013z

    Joined:
    Apr 14, 2020
    Posts:
    36
    Makes sense. Thanks. If anyone else has this issue. The canvas prefab can be found here: Assets\Plugins\SimpleFileBrowser\Resources\SimpleFileBrowserCanvas.prefab
     
    yasirkula likes this.
  13. TonismoGames

    TonismoGames

    Joined:
    Jun 12, 2018
    Posts:
    111
    @yasirkula Thank You so much for making this great asset. I am glad you added support for Android 11. Regarding Android 11,will I be using same path format like /storage/download/ ? Or will I have to use SAF format for path?
     
  14. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    File browser will return SAF paths on Android 11+, normal file paths won't work. FileBrowserHelpers functions work with SAF paths on those Android versions so you don't really need to know raw file path of the user's selection. You simply need to pass that path to FileBrowserHelpers functions you need. The one exception is, CopyFile, CopyDirectory, MoveFile and MoveDirectory functions accept one SAF path and one raw file path (order doesn't matter) because otherwise they wouldn't be useful lol. Your app will need to have access to that raw file path, though (e.g. persistentDataPath).

    Adsız.png
     
    TonismoGames likes this.
  15. TonismoGames

    TonismoGames

    Joined:
    Jun 12, 2018
    Posts:
    111
    So passing FileBrowserHelpers.CopyFile(Application.persistentDataPath,"/sdcard/Downloads"); will not work? Will you be posting more documentions or examples regarding SAF on your github? Google is forcing us to use SAF, big headache.
     
  16. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Yes, it won't work. I don't have any other SAF plugins in mind.
     
    TonismoGames likes this.
  17. jg3d

    jg3d

    Joined:
    Jan 13, 2014
    Posts:
    17
    hey, @yasirkula- thanks for all your work on these native plugins! They've been really useful on my current project. I did have question about the FileBrowserHelper functions.The documentation states "These functions should be called with the paths returned by the FileBrowser functions only." is that because they use SAF URIs or are you using a different system? What I'm trying to do is receive an SAF URL from an intent (which I can get) and then copy the file at that path to the persistentDataPath. From your message this morning, it seems like we could "CopyFile(<SAFPath>,Application.persistentDataPath)." Should that work? Thanks!
     
  18. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I guess it would work. If it doesn't, you can post the SAF path and the logcat error logs here. I'm curious.
     
  19. jg3d

    jg3d

    Joined:
    Jan 13, 2014
    Posts:
    17
    I tried it, but the error it throws is:
    FileNotFoundException: content://com.estrongs.files/storage/emulated/0/AzRecorderFree/20201216_134848.mp4 does not exist
    .

    I did some tests - it seems like the FileBrowser returns "/storage/emulated/0/AzRecorderFree/20201216_134848.mp4" when a file is selected. CopyFile works when I strip "content://com.estrongs.files." from the source path, but that means it's not using SAF, right?
     
  20. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    File browser uses SAF only on Android 11 and later (uses File API on earlier Android versions). You can add the following function to FileBrowserHelpers and call it but I didn't test these functions on earlier versions so I can't guarantee a result:

    Code (CSharp):
    1. public static void CopyFileSAF( string sourcePath, string destinationPath )
    2. {
    3. #if !UNITY_EDITOR && UNITY_ANDROID
    4.     AJC.CallStatic( "CopyFile", Context, sourcePath, destinationPath, false );
    5. #else
    6.     File.Copy( sourcePath, destinationPath, true );
    7. #endif
    8. }
     
  21. jg3d

    jg3d

    Joined:
    Jan 13, 2014
    Posts:
    17
    That did it! Thanks! Do you think that function will make it into the public repo? I'm pointing Package Manager at it and wondering if I should manage it another way.
     
  22. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You can copy the function to your own class together with AJC and Context properties. Providing SAF paths from outside on earlier Android versions is a too specific use-case so I don't want to create functions for this use-case.
     
  23. jg3d

    jg3d

    Joined:
    Jan 13, 2014
    Posts:
    17
    Thanks so much! Works great!
     
    yasirkula likes this.
  24. AnThienLong

    AnThienLong

    Joined:
    Jul 16, 2020
    Posts:
    6
    Hello yasirkula and all,
    I'm a newbie of learning Unity. Please give me a video clip to instructions for using this powerful assets. Thanks in advanced!
    ATL
     
  25. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Hi! Currently, the only documentation is the written one. The online documentation contains example code but if you have little experience with C# scripting, you may have to gain a bit more experience before using this plugin.
     
    AnThienLong likes this.
  26. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    There are no platform specific differences. Example code applies to all supported platforms.
     
    AnThienLong likes this.
  27. AnThienLong

    AnThienLong

    Joined:
    Jul 16, 2020
    Posts:
    6
    Sorry Pro, I forgot to extend license of unity. Done and thanks a lot!
     
  28. AnThienLong

    AnThienLong

    Joined:
    Jul 16, 2020
    Posts:
    6
    Hello Yasirkula,
    After pop up folders I want to get and show a picture to a certain sprite. May you tell me how? Thanks a lot!
     
  29. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Can you elaborate a little more?
     
    AnThienLong likes this.
  30. AnThienLong

    AnThienLong

    Joined:
    Jul 16, 2020
    Posts:
    6
    Yeah,
    After browse my picture folder, I'll select a PNG then click Load button. Here I want to show this PNG into a sprite. But I don't know how to use scripts to do that more. I'm a really newbie with program. Kindly teach me!!!
     
  31. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Code (CSharp):
    1. public void LoadImage()
    2. {
    3.     FileBrowser.SetFilters( false, new FileBrowser.Filter( "Images", ".png", ".jpg", ".jpeg" ) );
    4.     FileBrowser.ShowLoadDialog( ( paths ) =>
    5.     {
    6.         // Creating a Texture2D from picked image
    7.         Texture2D texture = new Texture2D( 2, 2 );
    8.         texture.LoadImage( File.ReadAllBytes( paths[0] ) );
    9.  
    10.         // Creating a Sprite from Texture2D
    11.         Sprite sprite = Sprite.Create( texture, new Rect( 0f, 0f, texture.width, texture.height ), new Vector2( 0.5f, 0.5f ) );
    12.  
    13.         // Calling AssignSpriteToObject with that Sprite
    14.         AssignSpriteToObject( sprite );
    15.     }, null, FileBrowser.PickMode.Files );
    16. }
    17.  
    18. public void AssignSpriteToObject( Sprite sprite )
    19. {
    20.     // Assign Sprite to SpriteRenderer or Image here
    21. }
    Note that until active scene is changed, these procedurally generated Sprites will consume RAM even after you stop using them. If you create a lot of procedural Sprites and your game crashes due to insufficient memory, you'll have to manually Destroy the unused Sprites' textures. This is a more advanced topic but I wanted to give you a heads up.
     
  32. AnThienLong

    AnThienLong

    Joined:
    Jul 16, 2020
    Posts:
    6
    OMG! You're so Pro! They're very short and simple! Thanks again!
     
    yasirkula likes this.
  33. unity_fcR95LTMy8E1LA

    unity_fcR95LTMy8E1LA

    Joined:
    Apr 1, 2020
    Posts:
    5
    Hello!! I need help. I made this in my code:

    browser = SimpleFileBrowser.FileBrowser.ShowLoadDialog((path) => { Direction(path); }, null, true, null, "Load", "Select");

    to open the file browser and works fine in unity 2019.3.7f but when I update it to 2020.3.2f1 an error appear in this line:
    error CS1503: Argument 1: cannot convert from 'string[]' to 'string'

    I don't understand what is the problem here. Any help it wolud be great! Thank you!
     
  34. NocSchecter

    NocSchecter

    Joined:
    Aug 19, 2015
    Posts:
    33
    Hi yasirkula,

    I love the new version where you added a context menu. I have a doubt and I hope you can enlighten me because I can not find how to solve it, is regarding the active state of the context menu, I see that you use a method called Hide that disables the component when you give a left click, but this is not referenced in the Pointer click method to be disabled. The click method is called in 6 places as references but I do not find it in the Pointer click method of the mouse, could you tell me how to deactivate it?

    Thanks!
     
  35. TonismoGames

    TonismoGames

    Joined:
    Jun 12, 2018
    Posts:
    111
    New SimpleBrowser update on success returns an array of string and not just a string, I don't know why he did that. Your Direction(path) should be changed to Direction(string[]path) and access the path via path[0]
     
    unity_fcR95LTMy8E1LA likes this.
  36. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    @unity_fcR95LTMy8E1LA File browser supports picking multiple files and thus, returns a string[] array. Function's signature has also changed a bit. Please see the new signature:
    Code (CSharp):
    1. public static bool ShowLoadDialog( OnSuccess onSuccess, OnCancel onCancel, PickMode pickMode, bool allowMultiSelection = false, string initialPath = null, string initialFilename = null, string title = "Load", string loadButtonText = "Select" );
    @NocSchecter Hide function is also registered to SimpleFileBrowserCanvas/ContextMenu/RaycastBlocker/EventTrigger/PointerDown event.
     
    unity_fcR95LTMy8E1LA likes this.
  37. unity_fcR95LTMy8E1LA

    unity_fcR95LTMy8E1LA

    Joined:
    Apr 1, 2020
    Posts:
    5
    Thank you!! It works perfectly
     
  38. unity_fcR95LTMy8E1LA

    unity_fcR95LTMy8E1LA

    Joined:
    Apr 1, 2020
    Posts:
    5
    Thank you @yasirkula I read your "read me" jaja and now everything works well
     
    yasirkula likes this.
  39. gizmo87898

    gizmo87898

    Joined:
    Mar 11, 2021
    Posts:
    10
    hi, is there an example on how to get this to work correctly in vr? no matter what i try it just never shows up. thanks
     
  40. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I haven't tried it on VR myself but you can try changing SimpleFileBrowserCanvas prefab's Render Mode to World Space and position it as you wish. If it is still not visible, check logcat for error messages.
     
  41. gizmo87898

    gizmo87898

    Joined:
    Mar 11, 2021
    Posts:
    10
    I just changed the rendering mode to world space and it is still not visible, i checked logcat for errors and i found: "SimpleFileBrowserCanvas(Clone)" with a render mode of ScreenSpaceOverlay is being used while VR is also enabled. This Canvas will continue to incur a rendering cost, but will not be visible while in VR. Is this intentional?" Sorry for being dumb i am still very new to unity lol

    edit: turns out i just didnt push the new build onto my quest lmao. now it is still not visible but there are no errors related to the file browser in logcat, only a few warnings about not having permissions to read /mnt/product.

    Heres the code i am using to load my files, if it helps.
    Code (CSharp):
    1.     void Start() {
    2.         StartCoroutine(ShowLoadDialogCoroutine());
    3.     }
    4.     IEnumerator ShowLoadDialogCoroutine()
    5.     {
    6.         BSPLoader.Settings settings = new BSPLoader.Settings();
    7.         settings.entityCreatedCallback = OnEntityCreated;
    8.         FileBrowser.SetFilters(true, new FileBrowser.Filter( "BSP Maps", ".bsp" ));
    9.         FileBrowser.SetDefaultFilter( ".bsp" );
    10.         FileBrowser.AddQuickLink( "Maps", Directory.GetCurrentDirectory() + "\\Maps\\", null );
    11.         yield return FileBrowser.WaitForLoadDialog(FileBrowser.PickMode.Files, false, null, null, "Load BSP Map", "Load" );
    12.         settings.texturePath = Directory.GetCurrentDirectory() + "\\Assets\\Textures\\";
    13.         settings.materialPath = Directory.GetCurrentDirectory() + "\\Assets\\Materials\\";
    14.         Debug.Log( FileBrowser.Success );
    15.         if( FileBrowser.Success )
    16.         {
    17.             for( int i = 0; i < FileBrowser.Result.Length; i++ )
    18.                 Debug.Log( FileBrowser.Result[i] );
    19.                 settings.path = FileBrowser.Result[0];
    20.             byte[] bytes = FileBrowserHelpers.ReadBytesFromFile( FileBrowser.Result[0] );
    21.             string destinationPath = Path.Combine( Application.persistentDataPath, FileBrowserHelpers.GetFilename( FileBrowser.Result[0] ) );
    22.             FileBrowserHelpers.CopyFile( FileBrowser.Result[0], destinationPath );
    23.         }
    24.         BSPLoader loader = new BSPLoader();
    25.         loader.settings = settings;
    26.         loader.LoadBSP();
    27.     }
     
    Last edited: Apr 12, 2021
  42. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I suspect the file browser is very far away from camera. It won't automatically follow the camera. You need to set its position manually. For this, you can drag&drop the SimpleFileBrowserCanvas prefab to your scene and position it as you wish. Then, deactivate that GameObject from your code when game starts to hide it at startup.
     
  43. gizmo87898

    gizmo87898

    Joined:
    Mar 11, 2021
    Posts:
    10
    hi, i think i get the prefab part to work now, but it doesnt display correctly in play mode. All the buttons shrink and the file browser does not display. I would upload an image if i knew how lol. In edit mode it displays normal and how i would want it to. is this a common thing? thanks
     
  44. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You can upload a screenshot with Upload a File button at bottom right corner. Some screenshots would help, yeah :p
     
  45. gizmo87898

    gizmo87898

    Joined:
    Mar 11, 2021
    Posts:
    10
    found it, lol. capture2 is what it looks like during edit mode,and capture is when its in play mode.
     

    Attached Files:

  46. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I see. File browser dialog (SimpleFileBrowserWindow) is always enveloped by the canvas (SimpleFileBrowserCanvas). In this case, I believe the canvas is tiny whereas the dialog is huge. As a result, dialog is shrinked to fit inside the tiny canvas. Simply increase SimpleFileBrowserCanvas' Width and Height values. You can use Rect tool (T key) in Scene view to see the canvas' boundaries.
     
  47. gizmo87898

    gizmo87898

    Joined:
    Mar 11, 2021
    Posts:
    10
    Thank you so much, it works perfect now. :D
     
    yasirkula likes this.
  48. AnThienLong

    AnThienLong

    Joined:
    Jul 16, 2020
    Posts:
    6
    Hello YasirKula,
    May I make friend with you via Facebook or WhatsApp or any chat app ...? Then we can chat quicker and more. Hope hear from you soon!
    Have a nice day!
     
  49. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Hey, I'd prefer using the Unity forums instead. If I had a Discord server, I'd redirect you to there but I don't. You can send me private message on Unity forums, I check the forums quite often.
     
  50. gizmo87898

    gizmo87898

    Joined:
    Mar 11, 2021
    Posts:
    10
    hi, sorry to ask so many questions, but im still confused on how to get this to work correctly. Right now, the window works in vr and i can open/close/resize/move it. It is the regular canvas prefab. This is the code i am using, and i have it attached to the main Window gameobject. but, when i click on the menu to open the file browser, there is no files or browse icon in the quick links. am i supposed to be creating the window entirely from the code? thanks
    Code (CSharp):
    1. void Start() {
    2.         StartCoroutine(LoadMapCoroutine());
    3.     }
    4.    
    5.     IEnumerator LoadMapCoroutine()
    6.     {
    7.         BSPLoader.Settings settings = new BSPLoader.Settings();
    8.         settings.entityCreatedCallback = OnEntityCreated;
    9.         FileBrowser.SetFilters(true, new FileBrowser.Filter( "BSP Maps", ".bsp" ));
    10.         FileBrowser.SetDefaultFilter( ".bsp" );
    11.         FileBrowser.AddQuickLink( "Maps", Directory.GetCurrentDirectory() + "\\Maps\\", null );
    12.         yield return FileBrowser.WaitForLoadDialog(FileBrowser.PickMode.Files, false, null, null, "Load BSP Map", "Load" );
    13.         settings.texturePath = Directory.GetCurrentDirectory() + "\\Assets\\Textures\\";
    14.         settings.materialPath = Directory.GetCurrentDirectory() + "\\Assets\\Materials\\";
    15.         Debug.Log(FileBrowser.Success);
    16.         if(FileBrowser.Success) {
    17.             if(FileBrowser.Result.Length > 1) {
    18.                 Debug.Log("Multiple files selected, using first one!");
    19.             }
    20.             settings.path = FileBrowser.Result[0];
    21.             //byte[] bytes = FileBrowserHelpers.ReadBytesFromFile( FileBrowser.Result[0] );
    22.             //string destinationPath = Path.Combine( Application.persistentDataPath, FileBrowserHelpers.GetFilename( FileBrowser.Result[0] ) );
    23.             //FileBrowserHelpers.CopyFile( FileBrowser.Result[0], destinationPath );
    24.         }
    25.         else {
    26.             Debug.Log("File browser dialog cancelled");
    27.  
    28.             //make the buttons for main menu re-appear
    29.         }
    30.         BSPLoader loader = new BSPLoader();
    31.         loader.settings = settings;
    32.         loader.LoadBSP();
    33.     }
    34.    
    35. }
    36.