Search Unity

  1. Looking for a job or to hire someone for a project? Check out the re-opened job forums.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

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,076
    If changing Start to OnEnable has no effect, you should put a Debug.Log at the top of LoadMapCoroutine and see if it is getting called. You should be able to use Android Logcat package to see logs. Alternatively, this plugin can help: https://github.com/yasirkula/UnityIngameDebugConsole
     
  2. gizmo87898

    gizmo87898

    Joined:
    Mar 11, 2021
    Posts:
    8
    Thank you again, it works now. I can see the root of my quest and it is showing the correct file format i want to load. but i seems like i cant select any files from the menu. The way i have it set up the ray from the controller should turn white when it is on a valid object and on all the files it does not turn white. All the other buttons, and the resize buttons turn the ray white and work perfect. is there a "touchscreen" mode for this i did not enable? thanks
     
  3. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    There isn't. What does this raycaster look for when determining whether or not something is clickable?
     
  4. gizmo87898

    gizmo87898

    Joined:
    Mar 11, 2021
    Posts:
    8
    It is the regular XR Rig ray interactor. Heres a screenshot of its components:
     

    Attached Files:

  5. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    I've investigated XR Ray Interactor's source code for a bit. It seems to handle IPointerDownHandler, IPointerUpHandler and IPointerClickHandlers properly and the FileBrowserItems in my plugin also implement these interfaces. So I couldn't figure out the cause of the issue, unfortunately. If your XR Interactions package isn't up-to-date, you can try updating it but I'm not very hopeful about the results.
     
  6. joelkuehle

    joelkuehle

    Joined:
    May 30, 2020
    Posts:
    2
    Hello,
    just stumpled over this, looks great. But I have one Question: I am currently using a to unity imported version of Windows Forms open file dialog. How does your's differ from that or is this a "unity verified" version of a file dialog?

    Btw. I am using your Runtime Preview Generator for a long time now. Works perfectly, already left 5 Stars and shared it with all of my programming friends. Keep up the great work.
     
  7. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    Thank you for your kind words. My plugins aren't Unity verified. SimpleFileBrowser uses UI system and works on all standalone platforms (except UWP) as well as Android. WinForms dialogs can't work on mobile platforms and may not work on some Linux versions.
     
  8. Joinzee

    Joinzee

    Joined:
    Mar 7, 2019
    Posts:
    2
    Hello! I've faced problems...
    This old code works, but now I'm trying to delete MANAGE_EXTERNAL_STORAGE and android:requestLegacyExternalStorage as Google asked.
    Code (CSharp):
    1. string appPath = "jar:file://" + Application.dataPath + "!/assets/" + fileName;
    2.         WWW wwwFile = new WWW(appPath);
    3.         while (!wwwFile.isDone) { }
    4.         Debug.Log("appPath: " + appPath);
    5.        
    6.                 if (!Directory.Exists(Application.persistentDataPath))
    7.         {
    8.             Directory.CreateDirectory(Application.persistentDataPath);
    9.             Debug.Log("Directory created: " + Application.persistentDataPath);
    10.         }
    11.         if (!Directory.Exists(GetDownloadFolder() + "/" + pathDeviceBonus))
    12.         {
    13.             Directory.CreateDirectory(GetDownloadFolder() + "/" + pathDeviceBonus);
    14.             Debug.Log("Directory created: " + GetDownloadFolder() + "/" + pathDeviceBonus);
    15.         }
    16.         File.WriteAllBytes(persistentDataPath, wwwFile.bytes);
    17. }
    18. public static string GetDownloadFolder()
    19.     {
    20.         string[] temp = (Application.persistentDataPath.Replace("Android", "")).Split(new string[] { "//" }, System.StringSplitOptions.None);
    21.  
    22.         return (temp[0] + "/Download");
    23.     }
    But the same appPath throws FileNotFoundException when I put it into ShowSaveDialog function:
    Code (CSharp):
    1. FileBrowser.ShowSaveDialog((paths) => { FileBrowserHelpers.CopyFile(appPath, paths[0]); }, () => { Debug.Log("Canceled"); }, FileBrowser.PickMode.Files, false, null, fileName, "Save", "Save");
    Anybody have any ideas?
     
  9. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    SimpleFileBrowser doesn't use or need MANAGE_EXTERNAL_STORAGE permission. If you haven't declared it yourself, you don't need any changes. And requestLegacyExternalStorage won't cause your app to be removed from Google Play.

    The issue in your code is that you are using a "jar://" path as appPath. It has never been supported. In the first code you've posted, you're extracting the file from appPath to persistentDataPath, which is good. You should pass persistentDataPath instead of appPath to FileBrowserHelpers.CopyFile.
     
    Joinzee likes this.
  10. Joinzee

    Joinzee

    Joined:
    Mar 7, 2019
    Posts:
    2
    Wow, thank you for so fast answer!
    Script with this "jar://" path has been working for me for 2 years =)
    Ok, so I have to copy my file to persistentDataPath and then pass it to the FileBrowserHelpers.CopyFile?

    UPDATED: Seems like it's working... I have to check all on other phones :)
    But I can't understand, must I delete android:requestLegacyExternalStorage or it can be. Will GP punish for that or not...
     
    Last edited: Apr 21, 2021
  11. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    Reddit users have concluded that we don't have to. However, SimpleFileBrowser will continue to function if you delete it. So it's really up to you. That attribute allows access to full filesystem on Android 10 devices. If it is removed, those devices will fallback to Storage Access Framework like Android 11 devices.
     
    Joinzee likes this.
  12. razaali4939

    razaali4939

    Joined:
    Mar 6, 2020
    Posts:
    2
    How to use showSaveDialog, I am using as SimpleFileBrowser.ShowSaveDialog(openFolder, null, true, null " ", " " ) it is giving me error.
     
  13. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
  14. aryanrai2001

    aryanrai2001

    Joined:
    Jul 13, 2019
    Posts:
    9
    I'm new to this high-level stuff, but I am using this asset for my game to add external music support and it worked perfectly in the editor but as soon as I exported the final build to Android it stopped working. With a little bit of digging, I discovered that it had something to do with SAF so being less experienced I planted a bunch of Debug.Log() statements around every file browser function and looked at logcat. It turns out that for Android 11, FileBrowserHelpers functions are not compatible with Application.persistentDataPath. So my question is, how can I read and write files in Application.persistentDataPath moreover, is there a way to do this that is universal and works on every version of Android. Sorry if this issue is already solved but I looked for it everywhere and found nothing.
     
  15. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    While working with persistentDataPath or temporaryCachePath, always use File API. While working with paths returned via file browser (or copying a file from a returned path to persistentDataPath or vice versa), always use FileBrowserHelpers functions.
     
  16. MartinOrtiz

    MartinOrtiz

    Joined:
    Apr 12, 2018
    Posts:
    103
    One question, how do I make FileBrowser.ShowLoadDialog load the dialog as a modal dialog?

    I tried calling it without using "yield", and it would still return immediately.
     
  17. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    I wish there was a way for it but there isn't because the dialog uses Unity's UI system which runs on the main thread. You need to use a native file browser plugin for it.
     
  18. aryanrai2001

    aryanrai2001

    Joined:
    Jul 13, 2019
    Posts:
    9
    But what if I just want to create
    Thanks, that worked...That was my bad, I forgot that I still had the option to use File API for persistentDataPath, Android 10 messed with my brain...Anyways thanks again, I tweaked the aesthetics of the asset to make it work with my game, not the most beautiful thing, but at least it's consistent, have a look!! Customized Explorer.png
     
    yasirkula likes this.
  19. vincyber

    vincyber

    Joined:
    Apr 1, 2017
    Posts:
    2
    Hi, I'm a motion graphic designer, I don't know the programming language very well, I often use playmaker but I have seen your plugin and what I have to do is open the file browser and load a local path (windows, Mac) in the component videoplayer url , so every time I open the file browser I can load different video paths. can someone help me please, can you do it? and how should i do it? I tried to use the example file but I couldn't.
     
  20. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    I don't use PlayMaker but I tried to create an action by looking at other actions' source codes:
    Code (CSharp):
    1. using SimpleFileBrowser;
    2.  
    3. namespace HutongGames.PlayMaker.Actions
    4. {
    5.     [ActionCategory( "yasirkula" )]
    6.     [PlayMaker.Tooltip( "Shows a file selection dialog" )]
    7.     public class SelectFileAction : FsmStateAction
    8.     {
    9.         public FsmString title;
    10.         public FsmString selectFileButtonText;
    11.  
    12.         public FsmBool showAllFilesFilter;
    13.         public FsmString filterName;
    14.         public FsmString[] filterExtensions;
    15.  
    16.         [ActionSection( "Outputs" )]
    17.         [UIHint( UIHint.Variable )]
    18.         [RequiredField]
    19.         public FsmString selectedFilePath;
    20.  
    21.         public FsmEvent onFileSelected;
    22.         public FsmEvent onCancel;
    23.  
    24.         public override void Reset()
    25.         {
    26.             base.Reset();
    27.  
    28.             title = "Select File";
    29.             selectFileButtonText = "Select";
    30.             showAllFilesFilter = true;
    31.             filterName = null;
    32.             filterExtensions = new FsmString[0];
    33.             selectedFilePath = null;
    34.             onFileSelected = null;
    35.             onCancel = null;
    36.         }
    37.  
    38.         public override void OnEnter()
    39.         {
    40.             if( string.IsNullOrEmpty( filterName.Value ) || filterExtensions.Length == 0 )
    41.                 FileBrowser.SetFilters( true, (string[]) null );
    42.             else
    43.             {
    44.                 string[] _filterExtensions = new string[filterExtensions.Length];
    45.                 for( int i = 0; i < filterExtensions.Length; i++ )
    46.                     _filterExtensions[i] = filterExtensions[i].Value;
    47.  
    48.                 FileBrowser.SetFilters( showAllFilesFilter.Value, new FileBrowser.Filter( filterName.Value, _filterExtensions ) );
    49.             }
    50.  
    51.             FileBrowser.ShowLoadDialog( ( paths ) =>
    52.             {
    53.                 selectedFilePath.Value = paths[0];
    54.                 Fsm.Event( onFileSelected );
    55.             },
    56.             () =>
    57.             {
    58.                 Fsm.Event( onCancel );
    59.             }, FileBrowser.PickMode.Files, false, null, null, title.Value, selectFileButtonText.Value );
    60.         }
    61.     }
    62. }
     
    vincyber likes this.
  21. vincyber

    vincyber

    Joined:
    Apr 1, 2017
    Posts:
    2
    thanks thanks thanks, it works. you have been very kind and helpful.
     
    yasirkula likes this.
  22. hussien72u

    hussien72u

    Joined:
    Sep 2, 2019
    Posts:
    1
    is there any video i can check to be able to use this?
     
  23. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
  24. blevok

    blevok

    Joined:
    Feb 16, 2017
    Posts:
    65
    Hello again. I've been using this for a year and it's great, but my users on android 11 are reporting that they can't see the SD card in the file browser.
    I'm currently using requestLegacyExternalStorage and everything is working good on android 10, but i know that's ignored in android 11.
    I haven't updated the asset in 6-8 months because i've made major changes to the look and added some custom buttons.
    Is there anything in newer versions that takes care of this issue, or is targeting api 30 and using MANAGE_EXTERNAL_STORAGE the way to go?
     
  25. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    Android 11 users will see a "Browse..." option in quick links section. This button will let them interact with the file system using Storage Access Framework. They just need to click it.
     
  26. blevok

    blevok

    Joined:
    Feb 16, 2017
    Posts:
    65
    Okay sounds like i do need to update then, because i just tried out the new android 11 emulator, and i don't see the browse button, only "primary drive".
    Thanks for the quick response.
     
  27. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    You shouldn't see "Primary Drive" on Android 11. Does uninstalling the game and then reinstalling it have any effect?
     
  28. aryanrai2001

    aryanrai2001

    Joined:
    Jul 13, 2019
    Posts:
    9
    Hey man, sorry to bother you again but now that everything is working fine, I discovered another bug. On exporting to android when my game initially loads, everything works fine (including the browser), but as soon as I load another scene and come back to the main scene, the browser loads and works but it is rendered very dark...I have no idea if it is something related to your asset or something wrong with my project setup, cause other menus are totally fine. You can compare it to another screenshot of my modified menu I posted a while back to see how much it actually changes WhatsApp Image 2021-05-02 at 7.31.28 PM.jpeg
     
  29. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
  30. aryanrai2001

    aryanrai2001

    Joined:
    Jul 13, 2019
    Posts:
    9
    Thanks for the asset suggestion, I know it's going to save me a lot of time in the future. But for now, I discovered that setting the SimpleFileBrowserCanvas to Screen Space - Overlay causes this issue for some reason...while debugging using a remote debugger I switched it to Screen Space - Camera, and that fixed the colors, but how do I make this change permanent?
     
  31. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    Before doing that, can you verify that at least one of your active cameras in the problematic scene has its Clear Flags set to either Solid Color or Skybox?
     
  32. blevok

    blevok

    Joined:
    Feb 16, 2017
    Posts:
    65
    No effect. Tried uninstalling and reinstalling, tried clearing app cache and data, and also tried revoking storage permission and granting again.

    It seems like ShouldUseSAF isn't working, because i see this in FileBrowser.cs, but i do still see the up button.
    Code (CSharp):
    1.             if( FileBrowserHelpers.ShouldUseSAF )
    2.             {
    3.                 // These UI elements have no use in Storage Access Framework mode (Android 10+)
    4.                 upButton.gameObject.SetActive( false );
    5.                 pathInputField.gameObject.SetActive( false );
    6.                 showHiddenFilesToggle.gameObject.SetActive( false );
    7.             }

    Also, i grepped the whole \Assets\Plugins\SimpleFileBrowser directory for "browse" and it didn't return any instance of that word that wasn't actually "browser", so it looks to me like the browse button doesn't exist.

    This is what i see on android 11, which is no different from what i see on previous OS versions.



    I can't find any indication of a version number in the asset files, but it seems like it's recent enough since the ShouldUseSAF bool exists.
    I'm on Unity 2019.4.8f1 in case it matters.

    edit: Also, the app is currently targeting API 29 and includes read/write external storage permissions in the manifest.
     

    Attached Files:

    Last edited: May 2, 2021 at 9:13 PM
  33. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    You are using a slightly older version of the plugin (reference) but that shouldn't matter IMO. After building the game, can you see requestLegacyExternalStorage attribute in PROJECT_PATH/Temp/StagingArea/AndroidManifest.xml?
     
  34. blevok

    blevok

    Joined:
    Feb 16, 2017
    Posts:
    65
    I'll have to do another build to check, since i didn't build today and the temp folder gets deleted when i close unity. But i assume it is indeed there, for 2 reasons. First, another feature that i built wasn't working on android 10, and then i learned about requestLegacyExternalStorage, and the feature started working after i added it. And second, the google dev console is detecting it and telling me i need to do something else because it will be ignored on android 11. I don't know if that means it's being ignored now, or that it will be ignored soon.

    The line you referenced in FileBrowser.cs is not in the version i have, so yeah i'm pretty out of date. I'm just dreading having to make all my modifications again, so i was hoping to discover a simple mistake i made or a tweak to get it working, but i'll do whatever it takes.

    I think tomorrow i'll start a fresh project just to quickly test the file browser on android 11, and if it works how you described, then i'll know that updating is the solution.

    I'll report back tomorrow to let you know how it went. Thanks
     
  35. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    If you encounter the same issue on a new project with requestLegacyExternalStorage, then I'd recommend you to modify FileBrowserHelpers.ShouldUseSAF so that it returns true if Android version is >= 30.

    P.S. I wonder if DriveInfo.GetDrives returns all storage paths on Android 11.
     
  36. aryanrai2001

    aryanrai2001

    Joined:
    Jul 13, 2019
    Posts:
    9
    Yes, I have one main camera and it has its clear flags set to Solid Color, but I don't know why that would be an issue because the problematic scene (Menu) works fine when I launch the game, the colors are all accurate, but when I play the game (i.e. load the Game scene) and come back to Menu scene, then the SimpleFileBrowserCanvas is shown darker, all the other UI elements that are in my main canvas are completely fine.
     
  37. aryanrai2001

    aryanrai2001

    Joined:
    Jul 13, 2019
    Posts:
    9
    I fixed it, albeit in a hacky and non-recommended way...By adding these lines to the FileBrowser script - Screenshot (1).png

    Also, my bad, the reason it worked fine on the initial load was that I had this problem earlier and figured out that it was because of ScreenSpace - Overlay, so I tried to fix it by adding these lines inside the if block instead and it seemed to work (because I did not check for scene change). But obviously, that was a wrong fix because as soon as I load another scene the camera is no more referenced, and coming back to the original scene it doesn't set it back to the main camera because m_instance is no longer null. Now it works fine as far as I can see...but if you have a better way of doing this, please share.
     
  38. blevok

    blevok

    Joined:
    Feb 16, 2017
    Posts:
    65
    Hmm, very interesting thought. I'll still try the new project first, because i also want to see the other improvements that i'm missing, but then before i go messing with updating the real project, i think i'm going to try this and see what happens. If the only issue is that it's never becoming true for whatever reason, then maybe it's just that simple. It could be the easy tweak i was hoping to find.

    Good question. I was rather confused by some of the specifics of the scoped storage documentation, but it kinda sounded to me like the SD card would only be available either with broad storage access, or as a mediastore abstraction. If i have any problems tomorrow then i'll probably do some debugging to see what's really going on.

    On a side note, the arm emulation in the newest android 11 image does actually work properly now. I was quite surprised to see that it didn't even choke on multidex. And using ADB is just as painless as a real device. It's the 10+ image on the recommended tab of the AVD manager in android studio. I don't know why it doesn't just say 11, but it is indeed api 30, which shows up after downloading the image. The blog post i read also says the newest android 9 image should also work just as well, but it just doesn't.
     
  39. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    @aryanrai2001 If your scene uses post-processing, Screen Space - Camera canvases are affected from it whereas Overlay canvases aren't. Can it be the case that your Screen Space - Camera canvases look brighter because they are brightened by a post-processing effect that is DontDestroyOnLoad'ed in the other scene?

    @blevok I no longer question when something doesn't work as intended in Android ecosystem :oops:
     
  40. aryanrai2001

    aryanrai2001

    Joined:
    Jul 13, 2019
    Posts:
    9
    No, I don't use post-processing, and colors can't trick me because I have designed the UI and everything myself in Photoshop, so I know what color is right and what is wrong...This might be a problem with unity where multiple canvases cause this kind of problem...Either way, the problem is solved so I'm satisfied. I think you should add a way to allow Screen Space - Camera because it's not as specific of a use-case as you think, Many people require it and it's very likely that they will already have a canvas if they're gonna open a browser, which is a UI, I don't think it's that difficult, should I do it and then send a pull request? (I can at least try)
     
  41. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    For World Space and Screen Space - Camera canvases, users can put the SimpleFileBrowserCanvas prefab to the scene as they wish and deactivate it from a user script on Start. Or they can make Instance property public and modify the file browser via it. I'm not planning to add a specific option for Screen Space - Camera canvases but thanks for offering a pull request.
     
  42. aryanrai2001

    aryanrai2001

    Joined:
    Jul 13, 2019
    Posts:
    9
    I guess that's one way, probably even better than what I did
    In any way thanks for the quick replies!
     
    yasirkula likes this.
  43. blevok

    blevok

    Joined:
    Feb 16, 2017
    Posts:
    65
    Okay so i started a fresh project, added the file browser and necessary code, and built an apk to test in the android 11 emulator.
    I did still see the "Primary Drive" link, so ShouldUseSAF is not returning true on android 11.

    After forcing it to return true, i did then see the browse button, which opens a native dialog to choose a folder. That's unfortunate for VR since it will require the user to take off the headset, but the folder access does persist between sessions, so they'll only have to do it once if they add the top level directory of internal storage and the SD card. Clicking the hamburger opens a menu where i can switch between internal storage and the SD card, and then pressing the select folder button adds the directory to the file browser quick links.
    Finding the SD card is not super intuitive though. I clicked through folders for minute before i started investigating other buttons in the native dialog.

    I'm assuming most android 11 users will already be used to the convoluted behavior of the new storage APIs from using other apps that don't have broad storage access, but i feel like i should make a video for my users that shows the procedure.

    I tested some of the helper functions, such as GetDirectoryName, GetFilename, GetEntriesInDirectory, and i stored all entries in the directory in a FileSystemEntry array, and then printed the path of each file, which seems to be just the file name and not a content URI. I'm not sure how that's going to play out when i try to feed it into AVPro or UnityWebRequestTexture though. I can of course copy images to the persistent data path and work with it from there, but i won't be able to do that with videos that could be several GB. I assume that just concatenating the directory and name won't work, but i'll jump off that bridge when i come to it.

    And to answer the question of what DriveInfo.GetDrives() returns, this is the result.
    Note that 1CEA-2A1B is the SD card.

    Code (CSharp):
    1. /
    2. /mnt/installer/0/emulated
    3. /mnt/installer/0/emulated/0/Android/data
    4. /mnt/installer/0/emulated/0/Android/obb
    5. /mnt/installer/0/1CEA-2A1B
    6. /mnt/androidwritable/0/emulated
    7. /mnt/androidwritable/0/emulated/0/Android/data
    8. /mnt/androidwritable/0/emulated/0/Android/obb
    9. /mnt/androidwritable/0/1CEA-2A1B
    10. /mnt/user/0/emulated
    11. /mnt/user/0/emulated/0/Android/data
    12. /mnt/user/0/emulated/0/Android/obb
    13. /mnt/pass_through/0/emulated
    14. /mnt/media_rw/1CEA-2A1B
    15. /mnt/user/0/1CEA-2A1B
    16. /mnt/pass_through/0/1CEA-2A1B
    17. /metadata
    18. /vendor
    19. /product
    20. /system_ext
    21. /apex/com.android.adbd@300900700
    22. /apex/com.android.adbd
    23. /apex/com.android.tethering@300900700
    24. /apex/com.android.tethering
    25. /apex/com.android.resolv@300900700
    26. /apex/com.android.resolv
    27. /apex/com.android.wifi@300900711
    28. /apex/com.android.wifi
    29. /apex/com.android.telephony@1
    30. /apex/com.android.telephony
    31. /apex/com.android.media.swcodec@300900714
    32. /apex/com.android.media.swcodec
    33. /apex/com.android.apex.cts.shim@1
    34. /apex/com.android.apex.cts.shim
    35. /apex/com.android.i18n@1
    36. /apex/com.android.i18n
    37. /apex/com.android.mediaprovider@300900719
    38. /apex/com.android.mediaprovider
    39. /apex/com.android.ipsec@300900700
    40. /apex/com.android.ipsec
    41. /apex/com.android.extservices@300900700
    42. /apex/com.android.extservices
    43. /apex/com.android.art@1
    44. /apex/com.android.art
    45. /apex/com.android.neuralnetworks@300900700
    46. /apex/com.android.neuralnetworks
    47. /apex/com.android.permission@300900706
    48. /apex/com.android.permission
    49. /apex/com.android.sdkext@300900700
    50. /apex/com.android.sdkext
    51. /apex/com.android.runtime@1
    52. /apex/com.android.runtime
    53. /apex/com.android.os.statsd@300900700
    54. /apex/com.android.os.statsd
    55. /apex/com.android.media@300900700
    56. /apex/com.android.media
    57. /apex/com.android.conscrypt@300900703
    58. /apex/com.android.conscrypt
    59. /apex/com.android.cellbroadcast@300900720
    60. /apex/com.android.cellbroadcast
    61. /apex/com.android.vndk.v30@1
    62. /apex/com.android.vndk.v30
    63. /apex/com.android.tzdata@300900700
    64. /apex/com.android.tzdata
    65. /data
    66. /data/user/0
    67. /data_mirror/data_ce/null
    68. /data_mirror/data_ce/null/0
    69. /data_mirror/data_de/null
    70. /data_mirror/cur_profiles
    71. /storage/emulated
    72. /storage/emulated/0/Android/data
    73. /storage/emulated/0/Android/obb
    74. /storage/1CEA-2A1B
    75. /proc/cpuinfo

    So for now it seems that the only issue with the file browser on android 10+ is that it's not using SAF when it should be, but it was simple enough to fix by checking the API level, which i did like this:

    Code (CSharp):
    1.         // On Android 10+, filesystem can be accessed via Storage Access Framework only
    2.         private static bool? m_shouldUseSAF = null;
    3.         public static bool ShouldUseSAF
    4.         {
    5.             get
    6.             {
    7.                 //if (m_shouldUseSAF == null)
    8.                 //    m_shouldUseSAF = AJC.CallStatic<bool>("CheckSAF");
    9.  
    10.                 //return m_shouldUseSAF.Value;
    11.                
    12.                 if (getSDKInt() >= 29)
    13.                 {
    14.                     return true;
    15.                 }
    16.                 else
    17.                 {
    18.                     return false;
    19.                 }
    20.             }
    21.         }
    22.  
    23.         static int getSDKInt()
    24.         {
    25.             using (var version = new AndroidJavaClass("android.os.Build$VERSION"))
    26.             {
    27.                 return version.GetStatic<int>("SDK_INT");
    28.             }
    29.         }
     
  44. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    - Did you have requestLegacyExternalStorage attribute when SAF wasn't picked on Android 11?
    - You'll have to copy the entire video to temporaryCachePath to play it, you are right. SAF doesn't operate on raw file paths and AFAIK VideoPlayer only accepts raw file paths, not SAF paths.
    - Can you put the attached jar file to Plugins/Android (remove .zip extension first) and tell me what the following code outputs:
    Code (CSharp):
    1. #if !UNITY_EDITOR && UNITY_ANDROID
    2. using( AndroidJavaClass ajc = new AndroidJavaClass( "com.yasirkula.unity.FileSystemTest" ) )
    3. {
    4.     string drivesList1 = FileBrowserHelpers.AJC.CallStatic<string>( "GetExternalDrives" );
    5.     string drivesList2 = ajc.CallStatic<string>( "GetExternalDrives" );
    6.     string drivesList3 = ajc.CallStatic<string>( "GetExternalDrives2" );
    7.     string drivesList4 = ajc.CallStatic<string>( "GetExternalDrives3" );
    8.  
    9.     Debug.Log( "RESULT1:\n" + drivesList1 );
    10.     Debug.Log( "RESULT2:\n" + drivesList2 );
    11.     Debug.Log( "RESULT3:\n" + drivesList3 );
    12.     Debug.Log( "RESULT4:\n" + drivesList4 );
    13. }
    14. #endif
     

    Attached Files:

  45. blevok

    blevok

    Joined:
    Feb 16, 2017
    Posts:
    65
    No, i haven't touched the manifest at all in this test project. The play dev console has been force feeding me this message everywhere i turn, so my intention is to remove it, assuming i can get everything working without it.

    A few months ago i did some experiments with converting raw paths to content URIs and back again. The video player was able to load a video from a URI string, so i think if i can somehow use the file browser result to get the URI to the file from the OS then there should be no issue.
    I don't think copying videos to local storage is going to be a good idea. My users are watching 4K 3D videos that can be several gigabytes or even larger, and i'm nervous about showing "insufficient internal storage space" messages when a user tries to open a video from the SD card.
    I think if i can't come up with a way to get the URI of the file itself, then my only option might be to try to get approved for MANAGE_EXTERNAL_STORAGE permission. But that might be difficult since the app doesn't cleanly fit into one of their noted exceptions.


    Here's the output, though i'm guessing this isn't what you were expecting since it's not making it to the debug lines. I see "untrusted_app" in there, so i should probably mention that i didn't sign this apk, but after approving it during the first install, it hasn't asked me again. I don't know if it could be related to the error though. Or perhaps there's something else i neglected. Aside from importing the file browser and writing some debug code, all i did was switch platform to android and build.

    Code (CSharp):
    1. 05-04 04:58:20.464  5047  5047 W UnityMain: type=1400 audit(0.0:154): avc: denied { read } for name="sdcard" dev="tmpfs" ino=7538 scontext=u:r:untrusted_app_29:s0:c163,c256,c512,c768 tcontext=u:object_r:mnt_sdcard_file:s0 tclass=lnk_file permissive=0 app=com.DefaultCompany.FileBrowserTest
    2. 05-04 04:58:20.540  5047  5091 E Unity   : AndroidJavaException: java.lang.NoSuchMethodError: no static method with name='GetExternalDrives2' signature='()Ljava/lang/String;' in class Lcom.yasirkula.unity.FileSystemTest;
    3. 05-04 04:58:20.540  5047  5091 E Unity   : java.lang.NoSuchMethodError: no static method with name='GetExternalDrives2' signature='()Ljava/lang/String;' in class Lcom.yasirkula.unity.FileSystemTest;
    4. 05-04 04:58:20.540  5047  5091 E Unity   :      at com.unity3d.player.ReflectionHelper.getMethodID(Unknown Source:167)
    5. 05-04 04:58:20.540  5047  5091 E Unity   :      at com.unity3d.player.UnityPlayer.nativeRender(Native Method)
    6. 05-04 04:58:20.540  5047  5091 E Unity   :      at com.unity3d.player.UnityPlayer.access$300(Unknown Source:0)
    7. 05-04 04:58:20.540  5047  5091 E Unity   :      at com.unity3d.player.UnityPlayer$e$1.handleMessage(Unknown Source:95)
    8. 05-04 04:58:20.540  5047  5091 E Unity   :      at android.os.Handler.dispatchMessage(Handler.java:102)
    9. 05-04 04:58:20.540  5047  5091 E Unity   :      at android.os.Looper.loop(Looper.java:223)
    10. 05-04 04:58:20.540  5047  5091 E Unity   :      at com.unity3d.player.UnityPlayer$e.run(Unknown Source:20)
    11. 05-04 04:58:20.540  5047  5091 E Unity   :   at UnityEngine._AndroidJNIHelper.GetMethodID (System.IntPtr jclass, System.String methodName, System.String signature, System.Boolean isStatic) [0x0003c] in <3c22a197ab60454cb70124c69f2248be>:0
    12. 05-04 04:58:20.540  5047  5091 E Unity   :   at UnityEngine.AndroidJNIHelper.GetMethodID (System.IntPtr
    13. 05-04 04:58:20.464  5047  5047 W UnityMain: type=1400 audit(0.0:157): avc: denied { getattr } for path="/mnt/product" dev="tmpfs" ino=7165 scontext=u:r:untrusted_app_29:s0:c163,c256,c512,c768 tcontext=u:object_r:mnt_product_file:s0 tclass=dir permissive=0 app=com.DefaultCompany.FileBrowserTest
     
  46. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    - I forgot that you've used the latest version of the plugin in your test project, my mistake. The plugin adds requestLegacyExternalStorage so you did test with that attribute without knowing it.
    - The path returned by file browser is the raw SAF path/URI when SAF is used.
    - I forgot to add some parameters to the code:
    Code (CSharp):
    1. string drivesList3 = ajc.CallStatic<string>( "GetExternalDrives2", FileBrowserHelpers.Context );
    2. string drivesList4 = ajc.CallStatic<string>( "GetExternalDrives3", FileBrowserHelpers.Context );
     
  47. blevok

    blevok

    Joined:
    Feb 16, 2017
    Posts:
    65
    Oh i didn't realize. But i guess it's worth keeping anyway, since that's probably what's keeping users on android 10 from having to deal with the SAF nonsense.

    Yep you're right. At 4am i started confusing what i was getting from helper functions with what was coming out of FileSystemEntry fileInfo. I see now that the path does include the file itself.

    Okay here's the real output.
    Code (CSharp):
    1. 05-04 15:30:20.653  3429  3492 I Unity   : RESULT1:
    2. 05-04 15:30:20.653  3429  3492 I Unity   : /storage/emulated/0:
    3. 05-04 15:30:20.653  3429  3492 I Unity   : (Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
    4. 05-04 15:30:20.653  3429  3492 I Unity   :
    5. 05-04 15:30:20.653  3429  3492 I Unity   : RESULT2:
    6. 05-04 15:30:20.653  3429  3492 I Unity   : /storage/emulated/0:C__/mnt/sdcard:C__/mnt/runtime:C__/mnt/appfuse:C__/mnt/expand:C__/mnt/pass_through:C__/mnt/media_rw:C__/mnt/obb:C__/mnt/asec:C__/mnt/secure:C__/mnt/androidwritable:C__/mnt/installer:C__/mnt/user:C__/mnt/product:C__/mnt/vendor:
    7. 05-04 15:30:20.653  3429  3492 I Unity   : (Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
    8. 05-04 15:30:20.653  3429  3492 I Unity   :
    9. 05-04 15:30:20.654  3429  3492 I Unity   : RESULT3:
    10. 05-04 15:30:20.654  3429  3492 I Unity   : /storage/emulated/0/Android/data/com.DefaultCompany.FileBrowserTest/cache:/storage/1CEA-2A1B/Android/data/com.DefaultCompany.FileBrowserTest/cache:
    11. 05-04 15:30:20.654  3429  3492 I Unity   : (Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
    12. 05-04 15:30:20.654  3429  3492 I Unity   :
    13. 05-04 15:30:20.654  3429  3492 I Unity   : RESULT4:
    14. 05-04 15:30:20.654  3429  3492 I Unity   : /storage/emulated/0:/storage/1CEA-2A1B:
    15. 05-04 15:30:20.654  3429  3492 I Unity   : (Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
    16. 05-04 15:30:20.654  3429  3492 I Unity   :
     
  48. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    RESULT4 looks very promising. I'll focus on it and get back to you, thanks!
     
    blevok likes this.
  49. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,076
    @blevok If the attached unitypackage works on the empty project for Android 11, then you can move SimpleFileBrowser.aar from it to your actual project. Then, you need to change this line as follows:
    string drivesList = FileBrowserHelpers.AJC.CallStatic<string>( "GetExternalDrives", FileBrowserHelpers.Context );


    If something goes wrong, you may unfortunately have to either update your plugin or continue using the SAF hack.
     

    Attached Files:

  50. blevok

    blevok

    Joined:
    Feb 16, 2017
    Posts:
    65
    Awesome, i'll give it a try. The .aar file replaces the .jar file, correct?
     
unityunity