Available on Asset Store: https://assetstore.unity.com/packages/tools/gui/runtime-file-browser-113006
Forum Thread: https://forum.unity.com/threads/simple-file-browser-open-source.441908/
- Behaves similar to Windows file chooser
- Ability to search by name or filter by type
- Quick links
- Simple user interface
- Draggable and resizable
- Ability to choose folders instead of files
- Supports selecting multiple files/folders
- Supports runtime permissions on Android M+ and Storage Access Framework on Android Q+
- Optimized using a recycled list view (makes Instantiate calls sparingly)
NOTE: Universal Windows Platform (UWP) and WebGL platforms aren't supported!
There are 5 ways to install this plugin:
- import SimpleFileBrowser.unitypackage via Assets-Import Package
- clone/download this repository and move the Plugins folder to your Unity project's Assets folder
- import it from Asset Store
- (via Package Manager) add the following line to Packages/manifest.json:
"com.yasirkula.simplefilebrowser": "https://github.com/yasirkula/UnitySimpleFileBrowser.git",
- (via OpenUPM) after installing openupm-cli, run the following command:
openupm add com.yasirkula.simplefilebrowser
- Can't show the file browser on Android, it says "java.lang.ClassNotFoundException: com.yasirkula.unity.FileBrowserPermissionReceiver" in Logcat
If your project uses ProGuard, try adding the following line to ProGuard filters: -keep class com.yasirkula.unity.* { *; }
- File browser doesn't show any files on Android 10+
File browser uses Storage Access Framework on these Android versions and users must first click the Pick Folder button in the quick links section
- RequestPermission returns Permission.Denied on Android
Declare the WRITE_EXTERNAL_STORAGE
permission manually in your Plugins/Android/AndroidManifest.xml file with the tools:node="replace"
attribute as follows: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="replace"/>
(you'll need to add the xmlns:tools="http://schemas.android.com/tools"
attribute to the <manifest ...>
element).
NOTE: On Android Q (10) or later, it is impossible to work with File APIs. On these devices, SimpleFileBrowser uses Storage Access Framework (SAF) to browse the files. However, paths returned by SAF are not File API compatible. To simulate the behaviour of the File API on all devices (including SAF), you can check out the FileBrowserHelpers functions. For reference, here is an example SAF path: content://com.android.externalstorage.documents/tree/primary%3A/document/primary%3APictures
First, add using SimpleFileBrowser;
to your script.
The file browser can be shown either as a save dialog or a load dialog. In load mode, the returned path(s) always lead to existing files or folders. In save mode, the returned path(s) can point to non-existing files, as well. You can use the following functions to show the file browser:
public static bool ShowSaveDialog( OnSuccess onSuccess, OnCancel onCancel, PickMode pickMode, bool allowMultiSelection = false, string initialPath = null, string initialFilename = null, string title = "Save", string saveButtonText = "Save" );
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" );
public delegate void OnSuccess( string[] paths );
public delegate void OnCancel();
There can only be one dialog active at a time. These functions will return true if the dialog is shown successfully (if no other dialog is active), false otherwise. You can query the FileBrowser.IsOpen property to see if there is an active dialog at the moment.
If user presses the Cancel button, onCancel callback is called. Otherwise, onSuccess callback is called with the paths of the selected files/folders as parameter. pickMode can be Files, Folders or FilesAndFolders. Setting allowMultiSelection to true will allow picking multiple files/folders.
There are also coroutine variants of these functions that will yield while the dialog is active:
public static IEnumerator WaitForSaveDialog( PickMode pickMode, bool allowMultiSelection = false, string initialPath = null, string initialFilename = null, string title = "Save", string saveButtonText = "Save" );
public static IEnumerator WaitForLoadDialog( PickMode pickMode, bool allowMultiSelection = false, string initialPath = null, string initialFilename = null, string title = "Load", string loadButtonText = "Select" );
After the dialog is closed, you can check the FileBrowser.Success property to see whether the user has selected some files/folders or cancelled the operation and if FileBrowser.Success is set to true, you can use the FileBrowser.Result property to get the paths of the selected files/folders.
You can force close an open dialog using the following function:
public static void HideDialog( bool invokeCancelCallback = false );
If there is an open dialog and the invokeCancelCallback parameter is set to true, the onCancel callback of the dialog will be invoked. This function can also be used to initialize the file browser ahead of time, which in turn will reduce the lag when you first open a dialog.
To add a quick link to the browser, you can use the following function:
public static bool AddQuickLink( string name, string path, Sprite icon = null );
When icon parameter is left as null, the quick link will have a folder icon.
By default, the file browser doesn't show files with .lnk or .tmp extensions. You can extend this list or remove this restriction altogether using the following function:
public static void SetExcludedExtensions( params string[] excludedExtensions );
Lastly, you can use the following functions to set the file filters (filters should include the period, e.g. ".jpg" instead of "jpg"):
public static void SetFilters( bool showAllFilesFilter, IEnumerable<string> filters );
public static void SetFilters( bool showAllFilesFilter, params string[] filters );
public static void SetFilters( bool showAllFilesFilter, IEnumerable<FileBrowser.Filter> filters );
public static void SetFilters( bool showAllFilesFilter, params FileBrowser.Filter[] filters );
When showAllFilesFilter is set to true, a filter by the name "All Files (.*)" will appear that will show all the files when selected. To select a default filter, use the following function:
public static bool SetDefaultFilter( string defaultFilter );
To open files or directories in the file browser with a single click (instead of double clicking), you can set FileBrowser.SingleClickMode to true.
On Android, file browser requires external storage access to function properly. You can use the following function to check if we have runtime permission to access the external storage:
public static FileBrowser.Permission CheckPermission();
FileBrowser.Permission is an enum that can take 3 values:
- Granted: we have the permission to access the external storage
- ShouldAsk: we don't have permission yet, but we can ask the user for permission via RequestPermission function (see below). As long as the user doesn't select "Don't ask again" while denying the permission, ShouldAsk is returned
- Denied: we don't have permission and we can't ask the user for permission. In this case, user has to give the permission from Settings. This happens when user selects "Don't ask again" while denying the permission or when user is not allowed to give that permission (parental controls etc.)
To request permission to access the external storage, use the following function:
public static FileBrowser.Permission RequestPermission();
Note that FileBrowser automatically calls RequestPermission before opening a dialog. If you want, you can turn this feature off by setting FileBrowser.AskPermissions to false.
The following file manipulation functions work on all platforms (including Storage Access Framework (SAF) on Android 10+). These functions should be called with the paths returned by the FileBrowser functions only:
public static bool FileBrowserHelpers.FileExists( string path );
public static bool FileBrowserHelpers.DirectoryExists( string path );
public static bool FileBrowserHelpers.IsDirectory( string path );
public static FileSystemEntry[] FileBrowserHelpers.GetEntriesInDirectory( string path ); // Returns all files and folders in a directory
public static string FileBrowserHelpers.CreateFileInDirectory( string directoryPath, string filename ); // Returns the created file's path
public static string FileBrowserHelpers.CreateFolderInDirectory( string directoryPath, string folderName ); // Returns the created folder's path
public static void FileBrowserHelpers.WriteBytesToFile( string targetPath, byte[] bytes );
public static void FileBrowserHelpers.WriteTextToFile( string targetPath, string text );
public static void FileBrowserHelpers.WriteCopyToFile( string targetPath, string sourceFile ); // Copies the contents of sourceFile to target file. Here, sourceFile must be a file path (i.e. don't use a SAF path as sourceFile)
public static void FileBrowserHelpers.AppendBytesToFile( string targetPath, byte[] bytes );
public static void FileBrowserHelpers.AppendTextToFile( string targetPath, string text );
public static void FileBrowserHelpers.AppendCopyToFile( string targetPath, string sourceFile ); // Appends the contents of sourceFile to target file. Here, sourceFile must be a file path
public static byte[] FileBrowserHelpers.ReadBytesFromFile( string sourcePath );
public static string FileBrowserHelpers.ReadTextFromFile( string sourcePath );
public static void FileBrowserHelpers.ReadCopyFromFile( string sourcePath, string destinationFile ); // Copies the contents of source to destinationFile. Here, destinationFile must be a file path
public static string FileBrowserHelpers.RenameFile( string path, string newName ); // Returns the new path of the file
public static string FileBrowserHelpers.RenameDirectory( string path, string newName ); // Returns the new path of the directory
public static void FileBrowserHelpers.DeleteFile( string path );
public static void FileBrowserHelpers.DeleteDirectory( string path );
public static string FileBrowserHelpers.GetFilename( string path );
public static long FileBrowserHelpers.GetFilesize( string path );
public static DateTime FileBrowserHelpers.GetLastModifiedDate( string path );
using UnityEngine;
using System.Collections;
using SimpleFileBrowser;
public class FileBrowserTest : MonoBehaviour
{
// Warning: paths returned by FileBrowser dialogs do not contain a trailing '\' character
// Warning: FileBrowser can only show 1 dialog at a time
void Start()
{
// Set filters (optional)
// It is sufficient to set the filters just once (instead of each time before showing the file browser dialog),
// if all the dialogs will be using the same filters
FileBrowser.SetFilters( true, new FileBrowser.Filter( "Images", ".jpg", ".png" ), new FileBrowser.Filter( "Text Files", ".txt", ".pdf" ) );
// Set default filter that is selected when the dialog is shown (optional)
// Returns true if the default filter is set successfully
// In this case, set Images filter as the default filter
FileBrowser.SetDefaultFilter( ".jpg" );
// Set excluded file extensions (optional) (by default, .lnk and .tmp extensions are excluded)
// Note that when you use this function, .lnk and .tmp extensions will no longer be
// excluded unless you explicitly add them as parameters to the function
FileBrowser.SetExcludedExtensions( ".lnk", ".tmp", ".zip", ".rar", ".exe" );
// Add a new quick link to the browser (optional) (returns true if quick link is added successfully)
// It is sufficient to add a quick link just once
// Name: Users
// Path: C:\Users
// Icon: default (folder icon)
FileBrowser.AddQuickLink( "Users", "C:\\Users", null );
// Show a save file dialog
// onSuccess event: not registered (which means this dialog is pretty useless)
// onCancel event: not registered
// Save file/folder: file, Allow multiple selection: false
// Initial path: "C:\", Initial filename: "Screenshot.png"
// Title: "Save As", Submit button text: "Save"
// FileBrowser.ShowSaveDialog( null, null, FileBrowser.PickMode.Files, false, "C:\\", "Screenshot.png", "Save As", "Save" );
// Show a select folder dialog
// onSuccess event: print the selected folder's path
// onCancel event: print "Canceled"
// Load file/folder: folder, Allow multiple selection: false
// Initial path: default (Documents), Initial filename: empty
// Title: "Select Folder", Submit button text: "Select"
// FileBrowser.ShowLoadDialog( ( paths ) => { Debug.Log( "Selected: " + paths[0] ); },
// () => { Debug.Log( "Canceled" ); },
// FileBrowser.PickMode.Folders, false, null, null, "Select Folder", "Select" );
// Coroutine example
StartCoroutine( ShowLoadDialogCoroutine() );
}
IEnumerator ShowLoadDialogCoroutine()
{
// Show a load file dialog and wait for a response from user
// Load file/folder: both, Allow multiple selection: true
// Initial path: default (Documents), Initial filename: empty
// Title: "Load File", Submit button text: "Load"
yield return FileBrowser.WaitForLoadDialog( FileBrowser.PickMode.FilesAndFolders, true, null, null, "Load Files and Folders", "Load" );
// Dialog is closed
// Print whether the user has selected some files/folders or cancelled the operation (FileBrowser.Success)
Debug.Log( FileBrowser.Success );
if( FileBrowser.Success )
{
// Print paths of the selected files (FileBrowser.Result) (null, if FileBrowser.Success is false)
for( int i = 0; i < FileBrowser.Result.Length; i++ )
Debug.Log( FileBrowser.Result[i] );
// Read the bytes of the first file via FileBrowserHelpers
// Contrary to File.ReadAllBytes, this function works on Android 10+, as well
byte[] bytes = FileBrowserHelpers.ReadBytesFromFile( FileBrowser.Result[0] );
}
}
}