@@ -88,12 +88,17 @@ public static bool ShouldUseSAF
8888 return m_shouldUseSAF . Value ;
8989 }
9090 }
91+
92+ public static bool ShouldUseSAFForPath ( string path ) // true: path should be managed with AJC (native helper class for Storage Access Framework), false: path should be managed with System.IO
93+ {
94+ return ShouldUseSAF && ( string . IsNullOrEmpty ( path ) || path [ 0 ] != '/' ) ;
95+ }
9196#endif
9297
9398 public static bool FileExists ( string path )
9499 {
95100#if ! UNITY_EDITOR && UNITY_ANDROID
96- if ( ShouldUseSAF )
101+ if ( ShouldUseSAFForPath ( path ) )
97102 return AJC . CallStatic < bool > ( "SAFEntryExists" , Context , path , false ) ;
98103#endif
99104 return File . Exists ( path ) ;
@@ -102,16 +107,28 @@ public static bool FileExists( string path )
102107 public static bool DirectoryExists ( string path )
103108 {
104109#if ! UNITY_EDITOR && UNITY_ANDROID
105- if ( ShouldUseSAF )
110+ if ( ShouldUseSAFForPath ( path ) )
106111 return AJC . CallStatic < bool > ( "SAFEntryExists" , Context , path , true ) ;
112+ else if ( ShouldUseSAF ) // Directory.Exists returns true even for inaccessible directories on Android 10+, we need to check if the directory is accessible
113+ {
114+ try
115+ {
116+ Directory . GetFiles ( path , "testtesttest" ) ;
117+ return true ;
118+ }
119+ catch
120+ {
121+ return false ;
122+ }
123+ }
107124#endif
108125 return Directory . Exists ( path ) ;
109126 }
110127
111128 public static bool IsDirectory ( string path )
112129 {
113130#if ! UNITY_EDITOR && UNITY_ANDROID
114- if ( ShouldUseSAF )
131+ if ( ShouldUseSAFForPath ( path ) )
115132 return AJC . CallStatic < bool > ( "SAFEntryDirectory" , Context , path ) ;
116133#endif
117134 if ( Directory . Exists ( path ) )
@@ -126,7 +143,7 @@ public static bool IsDirectory( string path )
126143 public static string GetDirectoryName ( string path )
127144 {
128145#if ! UNITY_EDITOR && UNITY_ANDROID
129- if ( ShouldUseSAF )
146+ if ( ShouldUseSAFForPath ( path ) )
130147 return AJC . CallStatic < string > ( "GetParentDirectory" , Context , path ) ;
131148#endif
132149 return Path . GetDirectoryName ( path ) ;
@@ -135,7 +152,7 @@ public static string GetDirectoryName( string path )
135152 public static FileSystemEntry [ ] GetEntriesInDirectory ( string path , bool extractOnlyLastSuffixFromExtensions )
136153 {
137154#if ! UNITY_EDITOR && UNITY_ANDROID
138- if ( ShouldUseSAF )
155+ if ( ShouldUseSAFForPath ( path ) )
139156 {
140157 string resultRaw = AJC . CallStatic < string > ( "OpenSAFFolder" , Context , path ) ;
141158 int separatorIndex = resultRaw . IndexOf ( "<>" ) ;
@@ -235,7 +252,7 @@ public static FileSystemEntry[] GetEntriesInDirectory( string path, bool extract
235252 public static string CreateFileInDirectory ( string directoryPath , string filename )
236253 {
237254#if ! UNITY_EDITOR && UNITY_ANDROID
238- if ( ShouldUseSAF )
255+ if ( ShouldUseSAFForPath ( directoryPath ) )
239256 return AJC . CallStatic < string > ( "CreateSAFEntry" , Context , directoryPath , false , filename ) ;
240257#endif
241258
@@ -247,7 +264,7 @@ public static string CreateFileInDirectory( string directoryPath, string filenam
247264 public static string CreateFolderInDirectory ( string directoryPath , string folderName )
248265 {
249266#if ! UNITY_EDITOR && UNITY_ANDROID
250- if ( ShouldUseSAF )
267+ if ( ShouldUseSAFForPath ( directoryPath ) )
251268 return AJC . CallStatic < string > ( "CreateSAFEntry" , Context , directoryPath , true , folderName ) ;
252269#endif
253270
@@ -259,7 +276,7 @@ public static string CreateFolderInDirectory( string directoryPath, string folde
259276 public static void WriteBytesToFile ( string targetPath , byte [ ] bytes )
260277 {
261278#if ! UNITY_EDITOR && UNITY_ANDROID
262- if ( ShouldUseSAF )
279+ if ( ShouldUseSAFForPath ( targetPath ) )
263280 {
264281 File . WriteAllBytes ( TemporaryFilePath , bytes ) ;
265282 AJC . CallStatic ( "WriteToSAFEntry" , Context , targetPath , TemporaryFilePath , false ) ;
@@ -274,7 +291,7 @@ public static void WriteBytesToFile( string targetPath, byte[] bytes )
274291 public static void WriteTextToFile ( string targetPath , string text )
275292 {
276293#if ! UNITY_EDITOR && UNITY_ANDROID
277- if ( ShouldUseSAF )
294+ if ( ShouldUseSAFForPath ( targetPath ) )
278295 {
279296 File . WriteAllText ( TemporaryFilePath , text ) ;
280297 AJC . CallStatic ( "WriteToSAFEntry" , Context , targetPath , TemporaryFilePath , false ) ;
@@ -289,7 +306,7 @@ public static void WriteTextToFile( string targetPath, string text )
289306 public static void AppendBytesToFile ( string targetPath , byte [ ] bytes )
290307 {
291308#if ! UNITY_EDITOR && UNITY_ANDROID
292- if ( ShouldUseSAF )
309+ if ( ShouldUseSAFForPath ( targetPath ) )
293310 {
294311 File . WriteAllBytes ( TemporaryFilePath , bytes ) ;
295312 AJC . CallStatic ( "WriteToSAFEntry" , Context , targetPath , TemporaryFilePath , true ) ;
@@ -307,7 +324,7 @@ public static void AppendBytesToFile( string targetPath, byte[] bytes )
307324 public static void AppendTextToFile ( string targetPath , string text )
308325 {
309326#if ! UNITY_EDITOR && UNITY_ANDROID
310- if ( ShouldUseSAF )
327+ if ( ShouldUseSAFForPath ( targetPath ) )
311328 {
312329 File . WriteAllText ( TemporaryFilePath , text ) ;
313330 AJC . CallStatic ( "WriteToSAFEntry" , Context , targetPath , TemporaryFilePath , true ) ;
@@ -322,7 +339,7 @@ public static void AppendTextToFile( string targetPath, string text )
322339 private static void AppendFileToFile ( string targetPath , string sourceFileToAppend )
323340 {
324341#if ! UNITY_EDITOR && UNITY_ANDROID
325- if ( ShouldUseSAF )
342+ if ( ShouldUseSAFForPath ( targetPath ) )
326343 {
327344 AJC . CallStatic ( "WriteToSAFEntry" , Context , targetPath , sourceFileToAppend , true ) ;
328345 return ;
@@ -341,7 +358,7 @@ private static void AppendFileToFile( string targetPath, string sourceFileToAppe
341358 public static byte [ ] ReadBytesFromFile ( string sourcePath )
342359 {
343360#if ! UNITY_EDITOR && UNITY_ANDROID
344- if ( ShouldUseSAF )
361+ if ( ShouldUseSAFForPath ( sourcePath ) )
345362 {
346363 AJC . CallStatic ( "ReadFromSAFEntry" , Context , sourcePath , TemporaryFilePath ) ;
347364 byte [ ] result = File . ReadAllBytes ( TemporaryFilePath ) ;
@@ -355,7 +372,7 @@ public static byte[] ReadBytesFromFile( string sourcePath )
355372 public static string ReadTextFromFile ( string sourcePath )
356373 {
357374#if ! UNITY_EDITOR && UNITY_ANDROID
358- if ( ShouldUseSAF )
375+ if ( ShouldUseSAFForPath ( sourcePath ) )
359376 {
360377 AJC . CallStatic ( "ReadFromSAFEntry" , Context , sourcePath , TemporaryFilePath ) ;
361378 string result = File . ReadAllText ( TemporaryFilePath ) ;
@@ -369,7 +386,7 @@ public static string ReadTextFromFile( string sourcePath )
369386 public static void CopyFile ( string sourcePath , string destinationPath )
370387 {
371388#if ! UNITY_EDITOR && UNITY_ANDROID
372- if ( ShouldUseSAF )
389+ if ( ShouldUseSAF ) // No need to use ShouldUseSAFForPath because both SAF paths and raw file paths are handled on the native-side
373390 {
374391 AJC . CallStatic ( "CopyFile" , Context , sourcePath , destinationPath , false ) ;
375392 return ;
@@ -381,7 +398,7 @@ public static void CopyFile( string sourcePath, string destinationPath )
381398 public static void CopyDirectory ( string sourcePath , string destinationPath )
382399 {
383400#if ! UNITY_EDITOR && UNITY_ANDROID
384- if ( ShouldUseSAF )
401+ if ( ShouldUseSAF ) // No need to use ShouldUseSAFForPath because both SAF paths and raw directory paths are handled on the native-side
385402 {
386403 AJC . CallStatic ( "CopyDirectory" , Context , sourcePath , destinationPath , false ) ;
387404 return ;
@@ -406,7 +423,7 @@ private static void CopyDirectoryRecursively( DirectoryInfo sourceDirectory, str
406423 public static void MoveFile ( string sourcePath , string destinationPath )
407424 {
408425#if ! UNITY_EDITOR && UNITY_ANDROID
409- if ( ShouldUseSAF )
426+ if ( ShouldUseSAF ) // No need to use ShouldUseSAFForPath because both SAF paths and raw file paths are handled on the native-side
410427 {
411428 AJC . CallStatic ( "CopyFile" , Context , sourcePath , destinationPath , true ) ;
412429 return ;
@@ -418,7 +435,7 @@ public static void MoveFile( string sourcePath, string destinationPath )
418435 public static void MoveDirectory ( string sourcePath , string destinationPath )
419436 {
420437#if ! UNITY_EDITOR && UNITY_ANDROID
421- if ( ShouldUseSAF )
438+ if ( ShouldUseSAF ) // No need to use ShouldUseSAFForPath because both SAF paths and raw directory paths are handled on the native-side
422439 {
423440 AJC . CallStatic ( "CopyDirectory" , Context , sourcePath , destinationPath , true ) ;
424441 return ;
@@ -430,7 +447,7 @@ public static void MoveDirectory( string sourcePath, string destinationPath )
430447 public static string RenameFile ( string path , string newName )
431448 {
432449#if ! UNITY_EDITOR && UNITY_ANDROID
433- if ( ShouldUseSAF )
450+ if ( ShouldUseSAFForPath ( path ) )
434451 return AJC . CallStatic < string > ( "RenameSAFEntry" , Context , path , newName ) ;
435452#endif
436453 string newPath = Path . Combine ( Path . GetDirectoryName ( path ) , newName ) ;
@@ -442,7 +459,7 @@ public static string RenameFile( string path, string newName )
442459 public static string RenameDirectory ( string path , string newName )
443460 {
444461#if ! UNITY_EDITOR && UNITY_ANDROID
445- if ( ShouldUseSAF )
462+ if ( ShouldUseSAFForPath ( path ) )
446463 return AJC . CallStatic < string > ( "RenameSAFEntry" , Context , path , newName ) ;
447464#endif
448465 string newPath = Path . Combine ( new DirectoryInfo ( path ) . Parent . FullName , newName ) ;
@@ -454,7 +471,7 @@ public static string RenameDirectory( string path, string newName )
454471 public static void DeleteFile ( string path )
455472 {
456473#if ! UNITY_EDITOR && UNITY_ANDROID
457- if ( ShouldUseSAF )
474+ if ( ShouldUseSAFForPath ( path ) )
458475 {
459476 AJC . CallStatic < bool > ( "DeleteSAFEntry" , Context , path ) ;
460477 return ;
@@ -466,7 +483,7 @@ public static void DeleteFile( string path )
466483 public static void DeleteDirectory ( string path )
467484 {
468485#if ! UNITY_EDITOR && UNITY_ANDROID
469- if ( ShouldUseSAF )
486+ if ( ShouldUseSAFForPath ( path ) )
470487 {
471488 AJC . CallStatic < bool > ( "DeleteSAFEntry" , Context , path ) ;
472489 return ;
@@ -478,7 +495,7 @@ public static void DeleteDirectory( string path )
478495 public static string GetFilename ( string path )
479496 {
480497#if ! UNITY_EDITOR && UNITY_ANDROID
481- if ( ShouldUseSAF )
498+ if ( ShouldUseSAFForPath ( path ) )
482499 return AJC . CallStatic < string > ( "SAFEntryName" , Context , path ) ;
483500#endif
484501 return Path . GetFileName ( path ) ;
@@ -487,7 +504,7 @@ public static string GetFilename( string path )
487504 public static long GetFilesize ( string path )
488505 {
489506#if ! UNITY_EDITOR && UNITY_ANDROID
490- if ( ShouldUseSAF )
507+ if ( ShouldUseSAFForPath ( path ) )
491508 return AJC . CallStatic < long > ( "SAFEntrySize" , Context , path ) ;
492509#endif
493510 return new FileInfo ( path ) . Length ;
@@ -497,7 +514,7 @@ public static System.DateTime GetLastModifiedDate( string path )
497514 {
498515#if ! UNITY_EDITOR && UNITY_ANDROID
499516 // Credit: https://stackoverflow.com/a/28504416/2373034
500- if ( ShouldUseSAF )
517+ if ( ShouldUseSAFForPath ( path ) )
501518 return new System . DateTime ( 1970 , 1 , 1 , 0 , 0 , 0 ) . AddMilliseconds ( AJC . CallStatic < long > ( "SAFEntryLastModified" , Context , path ) ) ;
502519#endif
503520 return new FileInfo ( path ) . LastWriteTime ;
0 commit comments