From fd69fa2ee62b3bc85ee87eda01ded7af5de76915 Mon Sep 17 00:00:00 2001 From: yasirkula Date: Wed, 12 Jul 2023 17:46:39 +0300 Subject: [PATCH] Added async variants of RequestPermission function that don't freeze the app unnecessarily --- .github/README.md | 13 ++ .../NativeGallery/Android/NGCallbackHelper.cs | 13 +- .../Android/NGMediaReceiveCallbackAndroid.cs | 36 +---- .../Android/NGPermissionCallbackAndroid.cs | 17 ++ Plugins/NativeGallery/NativeGallery.cs | 43 ++++- Plugins/NativeGallery/README.txt | 7 +- .../iOS/NGPermissionCallbackiOS.cs | 34 ++++ .../iOS/NGPermissionCallbackiOS.cs.meta | 12 ++ Plugins/NativeGallery/iOS/NativeGallery.mm | 153 ++++++++++++------ package.json | 2 +- 10 files changed, 232 insertions(+), 98 deletions(-) create mode 100644 Plugins/NativeGallery/iOS/NGPermissionCallbackiOS.cs create mode 100644 Plugins/NativeGallery/iOS/NGPermissionCallbackiOS.cs.meta diff --git a/.github/README.md b/.github/README.md index dde9da5..aff618a 100644 --- a/.github/README.md +++ b/.github/README.md @@ -131,6 +131,11 @@ There are two functions to handle permissions with this plugin: `NativeGallery.Permission NativeGallery.RequestPermission( PermissionType permissionType, MediaType mediaTypes )`: requests permission to access Gallery/Photos from the user and returns the result. It is recommended to show a brief explanation before asking the permission so that user understands why the permission is needed and doesn't click Deny or worse, "Don't ask again". Note that the SaveImageToGallery/SaveVideoToGallery and GetImageFromGallery/GetVideoFromGallery functions call RequestPermission internally and execute only if the permission is granted (the result of RequestPermission is also returned). +`void NativeGallery.RequestPermissionAsync( PermissionCallback callback, PermissionType permissionType, MediaType mediaTypes )`: Asynchronous variant of *RequestPermission*. Unlike RequestPermission, this function doesn't freeze the app unnecessarily before the permission dialog is displayed. So it's recommended to call this function instead. +- **PermissionCallback** takes `NativeGallery.Permission permission` parameter + +`Task NativeGallery.RequestPermissionAsync( PermissionType permissionType, MediaType mediaTypes )`: Another asynchronous variant of *RequestPermission* (requires Unity 2018.4 or later). + `NativeGallery.OpenSettings()`: opens the settings for this app, from where the user can manually grant permission in case current permission state is *Permission.Denied* (on Android, the necessary permission is named *Storage* and on iOS, the necessary permission is named *Photos*). `bool NativeGallery.CanOpenSettings()`: on iOS versions prior to 8.0, opening settings from within app is not possible and in this case, this function returns *false*. Otherwise, it returns *true*. @@ -197,6 +202,14 @@ void Update() } } +// Example code doesn't use this function but it is here for reference. It's recommended to ask for permissions manually using the +// RequestPermissionAsync methods prior to calling NativeGallery functions +private async void RequestPermissionAsynchronously( NativeGallery.PermissionType permissionType, NativeGallery.MediaType mediaTypes ) +{ + NativeGallery.Permission permission = await NativeGallery.RequestPermissionAsync( permissionType, mediaTypes ); + Debug.Log( "Permission result: " + permission ); +} + private IEnumerator TakeScreenshotAndSave() { yield return new WaitForEndOfFrame(); diff --git a/Plugins/NativeGallery/Android/NGCallbackHelper.cs b/Plugins/NativeGallery/Android/NGCallbackHelper.cs index c25c9a1..bf79515 100644 --- a/Plugins/NativeGallery/Android/NGCallbackHelper.cs +++ b/Plugins/NativeGallery/Android/NGCallbackHelper.cs @@ -16,9 +16,16 @@ private void Update() { if( mainThreadAction != null ) { - System.Action temp = mainThreadAction; - mainThreadAction = null; - temp(); + try + { + System.Action temp = mainThreadAction; + mainThreadAction = null; + temp(); + } + finally + { + Destroy( gameObject ); + } } } diff --git a/Plugins/NativeGallery/Android/NGMediaReceiveCallbackAndroid.cs b/Plugins/NativeGallery/Android/NGMediaReceiveCallbackAndroid.cs index b48a4d8..853d6ed 100644 --- a/Plugins/NativeGallery/Android/NGMediaReceiveCallbackAndroid.cs +++ b/Plugins/NativeGallery/Android/NGMediaReceiveCallbackAndroid.cs @@ -19,7 +19,7 @@ public NGMediaReceiveCallbackAndroid( NativeGallery.MediaPickCallback callback, public void OnMediaReceived( string path ) { - callbackHelper.CallOnMainThread( () => MediaReceiveCallback( path ) ); + callbackHelper.CallOnMainThread( () => callback( !string.IsNullOrEmpty( path ) ? path : null ) ); } public void OnMultipleMediaReceived( string paths ) @@ -53,39 +53,7 @@ public void OnMultipleMediaReceived( string paths ) result = pathsSplit; } - callbackHelper.CallOnMainThread( () => MediaReceiveMultipleCallback( result ) ); - } - - private void MediaReceiveCallback( string path ) - { - if( string.IsNullOrEmpty( path ) ) - path = null; - - try - { - if( callback != null ) - callback( path ); - } - finally - { - Object.Destroy( callbackHelper.gameObject ); - } - } - - private void MediaReceiveMultipleCallback( string[] paths ) - { - if( paths != null && paths.Length == 0 ) - paths = null; - - try - { - if( callbackMultiple != null ) - callbackMultiple( paths ); - } - finally - { - Object.Destroy( callbackHelper.gameObject ); - } + callbackHelper.CallOnMainThread( () => callbackMultiple( ( result != null && result.Length > 0 ) ? result : null ) ); } } } diff --git a/Plugins/NativeGallery/Android/NGPermissionCallbackAndroid.cs b/Plugins/NativeGallery/Android/NGPermissionCallbackAndroid.cs index 0c906e9..3255a48 100644 --- a/Plugins/NativeGallery/Android/NGPermissionCallbackAndroid.cs +++ b/Plugins/NativeGallery/Android/NGPermissionCallbackAndroid.cs @@ -25,5 +25,22 @@ public void OnPermissionResult( int result ) } } } + + public class NGPermissionCallbackAsyncAndroid : AndroidJavaProxy + { + private readonly NativeGallery.PermissionCallback callback; + private readonly NGCallbackHelper callbackHelper; + + public NGPermissionCallbackAsyncAndroid( NativeGallery.PermissionCallback callback ) : base( "com.yasirkula.unity.NativeGalleryPermissionReceiver" ) + { + this.callback = callback; + callbackHelper = new GameObject( "NGCallbackHelper" ).AddComponent(); + } + + public void OnPermissionResult( int result ) + { + callbackHelper.CallOnMainThread( () => callback( (NativeGallery.Permission) result ) ); + } + } } #endif \ No newline at end of file diff --git a/Plugins/NativeGallery/NativeGallery.cs b/Plugins/NativeGallery/NativeGallery.cs index 28bdd0f..574e139 100644 --- a/Plugins/NativeGallery/NativeGallery.cs +++ b/Plugins/NativeGallery/NativeGallery.cs @@ -55,6 +55,7 @@ public enum MediaType { Image = 1, Video = 2, Audio = 4 }; // EXIF orientation: http://sylvana.net/jpegcrop/exif_orientation.html (indices are reordered) public enum ImageOrientation { Unknown = -1, Normal = 0, Rotate90 = 1, Rotate180 = 2, Rotate270 = 3, FlipHorizontal = 4, Transpose = 5, FlipVertical = 6, Transverse = 7 }; + public delegate void PermissionCallback( Permission permission ); public delegate void MediaSaveCallback( bool success, string path ); public delegate void MediaPickCallback( string path ); public delegate void MediaPickMultipleCallback( string[] paths ); @@ -94,7 +95,7 @@ private static AndroidJavaObject Context private static extern int _NativeGallery_CheckPermission( int readPermission, int permissionFreeMode ); [System.Runtime.InteropServices.DllImport( "__Internal" )] - private static extern int _NativeGallery_RequestPermission( int readPermission, int permissionFreeMode ); + private static extern int _NativeGallery_RequestPermission( int readPermission, int permissionFreeMode, int asyncMode ); [System.Runtime.InteropServices.DllImport( "__Internal" )] private static extern void _NativeGallery_ShowLimitedLibraryPicker(); @@ -186,9 +187,7 @@ public static Permission CheckPermission( PermissionType permissionType, MediaTy return result; #elif !UNITY_EDITOR && UNITY_IOS - // result == 3: LimitedAccess permission on iOS, no need to handle it when PermissionFreeMode is set to true - int result = _NativeGallery_CheckPermission( permissionType == PermissionType.Read ? 1 : 0, PermissionFreeMode ? 1 : 0 ); - return result == 3 ? Permission.Granted : (Permission) result; + return ProcessPermission( (Permission) _NativeGallery_CheckPermission( permissionType == PermissionType.Read ? 1 : 0, PermissionFreeMode ? 1 : 0 ) ); #else return Permission.Granted; #endif @@ -196,6 +195,10 @@ public static Permission CheckPermission( PermissionType permissionType, MediaTy public static Permission RequestPermission( PermissionType permissionType, MediaType mediaTypes ) { + // Don't block the main thread if the permission is already granted + if( CheckPermission( permissionType, mediaTypes ) == Permission.Granted ) + return Permission.Granted; + #if !UNITY_EDITOR && UNITY_ANDROID object threadLock = new object(); lock( threadLock ) @@ -216,14 +219,40 @@ public static Permission RequestPermission( PermissionType permissionType, Media return (Permission) nativeCallback.Result; } #elif !UNITY_EDITOR && UNITY_IOS - // result == 3: LimitedAccess permission on iOS, no need to handle it when PermissionFreeMode is set to true - int result = _NativeGallery_RequestPermission( permissionType == PermissionType.Read ? 1 : 0, PermissionFreeMode ? 1 : 0 ); - return result == 3 ? Permission.Granted : (Permission) result; + return ProcessPermission( (Permission) _NativeGallery_RequestPermission( permissionType == PermissionType.Read ? 1 : 0, PermissionFreeMode ? 1 : 0, 0 ) ); #else return Permission.Granted; #endif } + public static void RequestPermissionAsync( PermissionCallback callback, PermissionType permissionType, MediaType mediaTypes ) + { +#if !UNITY_EDITOR && UNITY_ANDROID + NGPermissionCallbackAsyncAndroid nativeCallback = new NGPermissionCallbackAsyncAndroid( callback ); + AJC.CallStatic( "RequestPermission", Context, nativeCallback, permissionType == PermissionType.Read, (int) mediaTypes, (int) Permission.ShouldAsk ); +#elif !UNITY_EDITOR && UNITY_IOS + NGPermissionCallbackiOS.Initialize( ( result ) => callback( ProcessPermission( result ) ) ); + _NativeGallery_RequestPermission( permissionType == PermissionType.Read ? 1 : 0, PermissionFreeMode ? 1 : 0, 1 ); +#else + callback( Permission.Granted ); +#endif + } + +#if UNITY_2018_4_OR_NEWER && !NATIVE_GALLERY_DISABLE_ASYNC_FUNCTIONS + public static Task RequestPermissionAsync( PermissionType permissionType, MediaType mediaTypes ) + { + TaskCompletionSource tcs = new TaskCompletionSource(); + RequestPermissionAsync( ( permission ) => tcs.SetResult( permission ), permissionType, mediaTypes ); + return tcs.Task; + } +#endif + + private static Permission ProcessPermission( Permission permission ) + { + // result == 3: LimitedAccess permission on iOS, no need to handle it when PermissionFreeMode is set to true + return ( PermissionFreeMode && (int) permission == 3 ) ? Permission.Granted : permission; + } + // This function isn't needed when PermissionFreeMode is set to true private static void TryExtendLimitedAccessPermission() { diff --git a/Plugins/NativeGallery/README.txt b/Plugins/NativeGallery/README.txt index a7f1da6..1bb19af 100644 --- a/Plugins/NativeGallery/README.txt +++ b/Plugins/NativeGallery/README.txt @@ -1,4 +1,4 @@ -= Native Gallery for Android & iOS (v1.7.3) = += Native Gallery for Android & iOS (v1.7.4) = Online documentation & example code available at: https://github.com/yasirkula/UnityNativeGallery E-mail: yasirkula@gmail.com @@ -57,6 +57,7 @@ enum NativeGallery.Permission { Denied = 0, Granted = 1, ShouldAsk = 2 }; enum NativeGallery.ImageOrientation { Unknown = -1, Normal = 0, Rotate90 = 1, Rotate180 = 2, Rotate270 = 3, FlipHorizontal = 4, Transpose = 5, FlipVertical = 6, Transverse = 7 }; // EXIF orientation: http://sylvana.net/jpegcrop/exif_orientation.html (indices are reordered) enum MediaType { Image = 1, Video = 2, Audio = 4 }; +delegate void PermissionCallback( NativeGallery.Permission permission ); delegate void MediaSaveCallback( bool success, string path ); delegate void NativeGallery.MediaPickCallback( string path ); delegate void MediaPickMultipleCallback( string[] paths ); @@ -113,6 +114,10 @@ bool NativeGallery.IsMediaPickerBusy(); NativeGallery.Permission NativeGallery.CheckPermission( PermissionType permissionType, MediaType mediaTypes ); NativeGallery.Permission NativeGallery.RequestPermission( PermissionType permissionType, MediaType mediaTypes ); +// Asynchronous variants of RequestPermission. Unlike RequestPermission, these functions don't freeze the app unnecessarily before the permission dialog is displayed. So it's recommended to call these functions instead +void NativeGallery.RequestPermissionAsync( PermissionCallback callback, PermissionType permissionType, MediaType mediaTypes ); +Task NativeGallery.RequestPermissionAsync( PermissionType permissionType, MediaType mediaTypes ); + // If permission state is Permission.Denied, user must grant the necessary permission (Storage on Android and Photos on iOS) manually from the Settings. These functions help you open the Settings directly from within the app void NativeGallery.OpenSettings(); bool NativeGallery.CanOpenSettings(); diff --git a/Plugins/NativeGallery/iOS/NGPermissionCallbackiOS.cs b/Plugins/NativeGallery/iOS/NGPermissionCallbackiOS.cs new file mode 100644 index 0000000..ec26487 --- /dev/null +++ b/Plugins/NativeGallery/iOS/NGPermissionCallbackiOS.cs @@ -0,0 +1,34 @@ +#if UNITY_EDITOR || UNITY_IOS +using UnityEngine; + +namespace NativeGalleryNamespace +{ + public class NGPermissionCallbackiOS : MonoBehaviour + { + private static NGPermissionCallbackiOS instance; + private NativeGallery.PermissionCallback callback; + + public static void Initialize( NativeGallery.PermissionCallback callback ) + { + if( instance == null ) + { + instance = new GameObject( "NGPermissionCallbackiOS" ).AddComponent(); + DontDestroyOnLoad( instance.gameObject ); + } + else if( instance.callback != null ) + instance.callback( NativeGallery.Permission.ShouldAsk ); + + instance.callback = callback; + } + + public void OnPermissionRequested( string message ) + { + NativeGallery.PermissionCallback _callback = callback; + callback = null; + + if( _callback != null ) + _callback( (NativeGallery.Permission) int.Parse( message ) ); + } + } +} +#endif \ No newline at end of file diff --git a/Plugins/NativeGallery/iOS/NGPermissionCallbackiOS.cs.meta b/Plugins/NativeGallery/iOS/NGPermissionCallbackiOS.cs.meta new file mode 100644 index 0000000..ea8489a --- /dev/null +++ b/Plugins/NativeGallery/iOS/NGPermissionCallbackiOS.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: bc6d7fa0a99114a45b1a6800097c6eb1 +timeCreated: 1519060539 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Plugins/NativeGallery/iOS/NativeGallery.mm b/Plugins/NativeGallery/iOS/NativeGallery.mm index 53bfd51..adc837b 100644 --- a/Plugins/NativeGallery/iOS/NativeGallery.mm +++ b/Plugins/NativeGallery/iOS/NativeGallery.mm @@ -20,7 +20,7 @@ @interface UNativeGallery:NSObject + (int)checkPermission:(BOOL)readPermission permissionFreeMode:(BOOL)permissionFreeMode; -+ (int)requestPermission:(BOOL)readPermission permissionFreeMode:(BOOL)permissionFreeMode; ++ (int)requestPermission:(BOOL)readPermission permissionFreeMode:(BOOL)permissionFreeMode asyncMode:(BOOL)asyncMode; + (void)showLimitedLibraryPicker; + (int)canOpenSettings; + (void)openSettings; @@ -106,8 +106,9 @@ + (int)checkPermission:(BOOL)readPermission permissionFreeMode:(BOOL)permissionF } #pragma clang diagnostic pop -+ (int)requestPermission:(BOOL)readPermission permissionFreeMode:(BOOL)permissionFreeMode ++ (int)requestPermission:(BOOL)readPermission permissionFreeMode:(BOOL)permissionFreeMode asyncMode:(BOOL)asyncMode { + int result; #if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 if( CHECK_IOS_VERSION( @"8.0" ) ) { @@ -116,10 +117,9 @@ + (int)requestPermission:(BOOL)readPermission permissionFreeMode:(BOOL)permissio // On iOS 11 and later, permission isn't mandatory to fetch media from Photos if( readPermission && permissionFreeMode && CHECK_IOS_VERSION( @"11.0" ) ) - return 1; - + result = 1; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 - if( CHECK_IOS_VERSION( @"14.0" ) ) + else if( CHECK_IOS_VERSION( @"14.0" ) ) { // Photos permissions has changed on iOS 14. There are 2 permission dialogs now: // - AddOnly permission dialog: has 2 options: "Allow" and "Don't Allow". This dialog grants permission for save operations only. Unfortunately, @@ -128,18 +128,23 @@ + (int)requestPermission:(BOOL)readPermission permissionFreeMode:(BOOL)permissio // "Don't Allow". To be able to save media to a custom album, user must grant Full Photos permission. Thus, even when readPermission is false, // this dialog will be used if PermissionFreeMode is set to false. So, PermissionFreeMode determines whether or not saving to a custom album is // be supported - return [self requestPermissionNewest:( readPermission || !permissionFreeMode )]; + result = [self requestPermissionNewest:( readPermission || !permissionFreeMode ) asyncMode:asyncMode]; } - else #endif - return [self requestPermissionNew]; + else + result = [self requestPermissionNew:asyncMode]; #if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 } else { // version < iOS 8: request permission using AssetsLibrary framework (Photos framework not available) - return [self requestPermissionOld]; + result = [self requestPermissionOld:asyncMode]; } + + if( asyncMode && result >= 0 ) // Result returned immediately, forward it + UnitySendMessage( "NGPermissionCallbackiOS", "OnPermissionRequested", [self getCString:[NSString stringWithFormat:@"%d", result]] ); + + return result; #endif } @@ -147,7 +152,7 @@ + (int)requestPermission:(BOOL)readPermission permissionFreeMode:(BOOL)permissio // Credit: https://stackoverflow.com/a/26933380/2373034 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" -+ (int)requestPermissionOld ++ (int)requestPermissionOld:(BOOL)asyncMode { ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus]; @@ -155,23 +160,38 @@ + (int)requestPermissionOld return 1; else if( status == ALAuthorizationStatusNotDetermined ) { - __block BOOL authorized = NO; - ALAssetsLibrary *lib = [[ALAssetsLibrary alloc] init]; - - dispatch_semaphore_t sema = dispatch_semaphore_create( 0 ); - [lib enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^( ALAssetsGroup *group, BOOL *stop ) + if( asyncMode ) { - *stop = YES; - authorized = YES; - dispatch_semaphore_signal( sema ); + [[[ALAssetsLibrary alloc] init] enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^( ALAssetsGroup *group, BOOL *stop ) + { + *stop = YES; + UnitySendMessage( "NGPermissionCallbackiOS", "OnPermissionRequested", "1" ); + } + failureBlock:^( NSError *error ) + { + UnitySendMessage( "NGPermissionCallbackiOS", "OnPermissionRequested", "0" ); + }]; + + return -1; } - failureBlock:^( NSError *error ) + else { - dispatch_semaphore_signal( sema ); - }]; - dispatch_semaphore_wait( sema, DISPATCH_TIME_FOREVER ); - - return authorized ? 1 : 0; + __block BOOL authorized = NO; + dispatch_semaphore_t sema = dispatch_semaphore_create( 0 ); + [[[ALAssetsLibrary alloc] init] enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^( ALAssetsGroup *group, BOOL *stop ) + { + *stop = YES; + authorized = YES; + dispatch_semaphore_signal( sema ); + } + failureBlock:^( NSError *error ) + { + dispatch_semaphore_signal( sema ); + }]; + dispatch_semaphore_wait( sema, DISPATCH_TIME_FOREVER ); + + return authorized ? 1 : 0; + } } return 0; @@ -180,7 +200,7 @@ + (int)requestPermissionOld #endif // Credit: https://stackoverflow.com/a/32989022/2373034 -+ (int)requestPermissionNew ++ (int)requestPermissionNew:(BOOL)asyncMode { PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; @@ -188,24 +208,36 @@ + (int)requestPermissionNew return 1; else if( status == PHAuthorizationStatusNotDetermined ) { - __block BOOL authorized = NO; - - dispatch_semaphore_t sema = dispatch_semaphore_create( 0 ); - [PHPhotoLibrary requestAuthorization:^( PHAuthorizationStatus status ) + if( asyncMode ) { - authorized = ( status == PHAuthorizationStatusAuthorized ); - dispatch_semaphore_signal( sema ); - }]; - dispatch_semaphore_wait( sema, DISPATCH_TIME_FOREVER ); - - return authorized ? 1 : 0; + [PHPhotoLibrary requestAuthorization:^( PHAuthorizationStatus status ) + { + UnitySendMessage( "NGPermissionCallbackiOS", "OnPermissionRequested", ( status == PHAuthorizationStatusAuthorized ) ? "1" : "0" ); + }]; + + return -1; + } + else + { + __block BOOL authorized = NO; + + dispatch_semaphore_t sema = dispatch_semaphore_create( 0 ); + [PHPhotoLibrary requestAuthorization:^( PHAuthorizationStatus status ) + { + authorized = ( status == PHAuthorizationStatusAuthorized ); + dispatch_semaphore_signal( sema ); + }]; + dispatch_semaphore_wait( sema, DISPATCH_TIME_FOREVER ); + + return authorized ? 1 : 0; + } } return 0; } #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 -+ (int)requestPermissionNewest:(BOOL)readPermission ++ (int)requestPermissionNewest:(BOOL)readPermission asyncMode:(BOOL)asyncMode { PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatusForAccessLevel:( readPermission ? PHAccessLevelReadWrite : PHAccessLevelAddOnly )]; @@ -215,21 +247,38 @@ + (int)requestPermissionNewest:(BOOL)readPermission return 3; else if( status == PHAuthorizationStatusNotDetermined ) { - __block int authorized = 0; - - dispatch_semaphore_t sema = dispatch_semaphore_create( 0 ); - [PHPhotoLibrary requestAuthorizationForAccessLevel:( readPermission ? PHAccessLevelReadWrite : PHAccessLevelAddOnly ) handler:^( PHAuthorizationStatus status ) + if( asyncMode ) { - if( status == PHAuthorizationStatusAuthorized ) - authorized = 1; - else if( status == PHAuthorizationStatusRestricted ) - authorized = 3; + [PHPhotoLibrary requestAuthorizationForAccessLevel:( readPermission ? PHAccessLevelReadWrite : PHAccessLevelAddOnly ) handler:^( PHAuthorizationStatus status ) + { + if( status == PHAuthorizationStatusAuthorized ) + UnitySendMessage( "NGPermissionCallbackiOS", "OnPermissionRequested", "1" ); + else if( status == PHAuthorizationStatusRestricted ) + UnitySendMessage( "NGPermissionCallbackiOS", "OnPermissionRequested", "3" ); + else + UnitySendMessage( "NGPermissionCallbackiOS", "OnPermissionRequested", "0" ); + }]; + + return -1; + } + else + { + __block int authorized = 0; + + dispatch_semaphore_t sema = dispatch_semaphore_create( 0 ); + [PHPhotoLibrary requestAuthorizationForAccessLevel:( readPermission ? PHAccessLevelReadWrite : PHAccessLevelAddOnly ) handler:^( PHAuthorizationStatus status ) + { + if( status == PHAuthorizationStatusAuthorized ) + authorized = 1; + else if( status == PHAuthorizationStatusRestricted ) + authorized = 3; - dispatch_semaphore_signal( sema ); - }]; - dispatch_semaphore_wait( sema, DISPATCH_TIME_FOREVER ); - - return authorized; + dispatch_semaphore_signal( sema ); + }]; + dispatch_semaphore_wait( sema, DISPATCH_TIME_FOREVER ); + + return authorized; + } } return 0; @@ -244,7 +293,7 @@ + (void)showLimitedLibraryPicker #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatusForAccessLevel:PHAccessLevelReadWrite]; if( status == PHAuthorizationStatusNotDetermined ) - [self requestPermissionNewest:YES]; + [self requestPermissionNewest:YES asyncMode:YES]; else if( status == PHAuthorizationStatusRestricted ) [[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:UnityGetGLViewController()]; #endif @@ -1469,9 +1518,9 @@ + (char *)getCString:(NSString *)source return [UNativeGallery checkPermission:( readPermission == 1 ) permissionFreeMode:( permissionFreeMode == 1 )]; } -extern "C" int _NativeGallery_RequestPermission( int readPermission, int permissionFreeMode ) +extern "C" int _NativeGallery_RequestPermission( int readPermission, int permissionFreeMode, int asyncMode ) { - return [UNativeGallery requestPermission:( readPermission == 1 ) permissionFreeMode:( permissionFreeMode == 1 )]; + return [UNativeGallery requestPermission:( readPermission == 1 ) permissionFreeMode:( permissionFreeMode == 1 ) asyncMode:( asyncMode == 1 )]; } extern "C" void _NativeGallery_ShowLimitedLibraryPicker() diff --git a/package.json b/package.json index 8fa1087..14f3f4b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "com.yasirkula.nativegallery", "displayName": "Native Gallery", - "version": "1.7.3", + "version": "1.7.4", "documentationUrl": "https://github.com/yasirkula/UnityNativeGallery", "changelogUrl": "https://github.com/yasirkula/UnityNativeGallery/releases", "licensesUrl": "https://github.com/yasirkula/UnityNativeGallery/blob/master/LICENSE.txt",