Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only. On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live. Read our full announcement for more information and let us know if you have any questions.

Native Gallery for Android & iOS [Open Source]

Discussion in 'Assets and Asset Store' started by yasirkula, Feb 28, 2018.

  1. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    @crackbrain94 Hi! The permission dialog can be displayed only once on iOS. This limitation is put by the operating system. User must visit Settings to grant the permission later.
     
  2. crackbrain94

    crackbrain94

    Joined:
    May 2, 2017
    Posts:
    14
    Hello @yasirkula

    Thanks for your reply.

    At least is it possible to display the permission dialog on Android every time?
     
  3. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    @crackbrain94 Unless user grants or forever denies the permission, the dialog should show up every time.
     
  4. crackbrain94

    crackbrain94

    Joined:
    May 2, 2017
    Posts:
    14
    Unfortunately this is not happening @yasirkula.

    Is there a code I can use to display the permission dialog box for photos and videos?
     
  5. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    @crackbrain94 NativeGallery.RequestPermission does that, only if the permission can be asked. If operating system doesn't allow that, the dialog won't be displayed. At that point, the operating system is to blame.
     
  6. kentou1506

    kentou1506

    Joined:
    Oct 1, 2018
    Posts:
    4
    Thank you for your great asset.

    I can save and load a photo.

    But if I save a photo and delete app, after then I reinstall and try deleting the photo, it can not delete.

    Do you know how to resolve this?
     
  7. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    App must be losing the file's ownership on uninstall. If it can be resolved, I'm unaware how unfortunately.
     
  8. danipomix

    danipomix

    Joined:
    Oct 18, 2019
    Posts:
    15
    hello Yasirkula. Thanks for all the advices you've given me so far. Sorry to keep writing to you but sometimes my app (android) keeps crashing on importing the photo - on slightly older devices (for example: a redmi M2003j15ss). I saved the path value on the sharedprefs in the NativeGalleryMediaPickerResultOperation execute, as you advised me, but
    recently I've realized that the crash is prior to this function: In fact, the message shown on the logcat when the crash occurs is "NativeGalleryMediaPickerFragment.mediaReceiver became null!!" (NativeGalleryMediaPickerFragment - line 145), so the execute of NativeGalleryMediaPickerResultOperation is not reached. So I would like to know, generally, the condition mediaReceiver == null what is usually caused by (too much memory used so the app crashes in background?)? Could you recommend me a way to minimize the occurrence of this problem?
     
    Last edited: Sep 1, 2023
  9. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    @danipomix That's worrying. I don't really know why NativeGalleryMediaPickerFragment.mediaReceiver would become null either. That if condition is there just-in-case. I'm using the legacy Fragment class instead of the AndroidX Fragment class (due to complicated manual steps of installing AndroidX). Perhaps this is a bug that is resolved in AndroidX Fragment. I'm not planning to try to migrate to AndroidX anytime soon though.
     
    danipomix likes this.
  10. Hangpt_bap

    Hangpt_bap

    Joined:
    Jul 29, 2022
    Posts:
    1
    Hi @yasirkula @crackbrain94 and everyone, I also using NativeGallery.LoadImageAtPath to load an image .heic, then I create a sprite and assign it to the Image but it still displays (?). Is there any solution?
    Code (CSharp):
    1. var tex = NativeGallery.LoadImageAtPath(path, 512, false, false);
    2. var spr = Sprite.Create(tex, new Rect(0.0f, 0.0f, tex.width, tex.height), new Vector2(0.5f, 0.5f), 100.0f);
    3. imgAvatar.sprite = spr;
     
    Last edited: Sep 20, 2023
  11. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    @Hangpt_bap Can you spot any native errors in Xcode console/logcat?
     
  12. EdChen0712

    EdChen0712

    Joined:
    May 9, 2023
    Posts:
    6
    Hello Yasirkula,

    Thank you for providing Native Gallery, it has been quite helpful to me. However, I've encountered an issue in my usage and was wondering if there's a solution.

    Under normal circumstances, Native Gallery works fine. But when I meet both of the following conditions:

    1. Installing AvatarSDK Offline version 1.9.1 in the project.
    2. Generating an iOS version of the application using Unity Cloud Build.
    I face a problem where I seemingly have the permissions, but I can't open images successfully. The error message is attached.

    The code I'm using is from the example program provided on GitHub. If needed, I can provide the testing environment.

    Thank you for your assistance
     

    Attached Files:

  13. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    @EdChen0712 Hi, does AvatarSDK have any native iOS files with extension .mm? Or any other non-C# script in an iOS folder?
     
  14. EdChen0712

    EdChen0712

    Joined:
    May 9, 2023
    Posts:
    6
    Thank you for your response. As shown in the images, I couldn't find any relevant files. In Image 1, there are no .mm files or scripts under AvatarSDK's own Plugins in iOS. In Image 2, under the project's Plugins, there are only folders for NativeGallery and InGameDebugConsole.
     

    Attached Files:

    • 1.jpg
      1.jpg
      File size:
      28.2 KB
      Views:
      51
    • 2.jpg
      2.jpg
      File size:
      8.3 KB
      Views:
      50
  15. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    I don't know if it's possible that they've embedded an older version of NativeGallery in iOSInternal framework. Could you ask the author of AvatarSDK if they're using NativeGallery in their plugin and if so, if they're willing to update it to the latest version?
     
  16. EdChen0712

    EdChen0712

    Joined:
    May 9, 2023
    Posts:
    6
    Thank you for your response. After all, the version of AvatarSDK I'm using is indeed from over three years ago, so your suggestion is very valuable. I will reach out to the Avatar SDK team again for further inquiries. Thank you!
     
    yasirkula likes this.
  17. Grimmjow_Jaegerjackquez

    Grimmjow_Jaegerjackquez

    Joined:
    Dec 14, 2021
    Posts:
    16
    Hi @yasirkula , thanks for creating such a easy to use plugin. I am stuck in trying to access the Mime type of image that I pick from gallery. I am picking up png image still it gives empty string but path returns correct string.


    public void OnClickUploadImageButton()
    {
    NativeGallery.Permission per = NativeGallery.RequestPermission(NativeGallery.PermissionType.Read,NativeGallery.MediaType.Image);

    // probably should do some permissions checking here

    NativeGallery.Permission permission = NativeGallery.GetImageFromGallery((path) =>
    {
    if (path != null)
    {
    // Create Texture from selected image
    Texture2D texture = NativeGallery.LoadImageAtPath(path, 2073600, false);

    if (texture == null) return;

    ImageToBase64(path);

    //PlayerPrefs.SetString("ImagePath", imageUrl);

    NativeGallery.ImageProperties property = NativeGallery.GetImageProperties(path);

    Debug.Log("Image Path : " + path);

    Debug.Log("Mime Type" + property.mimeType);

    CropImageTaken(texture);
    }
    }, "Select an image", "image/*");
    }
     
    Last edited: Oct 31, 2023
  18. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
  19. Grimmjow_Jaegerjackquez

    Grimmjow_Jaegerjackquez

    Joined:
    Dec 14, 2021
    Posts:
    16
    @yasirkula I just copy pasted the code of returning mime type in my class and it is working, don't know why it is not working with NativeGallery one. Thanks for the reply.
     
  20. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    @Grimmjow_Jaegerjackquez Could you put Debug.Logs inside the NativeGallery code I've posted to help me debug where it fails?
     
  21. Akzamutdinov

    Akzamutdinov

    Joined:
    Jan 4, 2021
    Posts:
    7
    Dear @yasirkula, first thanks a lot for providing such tools to make people life easier. I was using it for years and now I'm working on update of my app. I've added permission to manifest, I've swithced to external storage in Unity build settings, but still it does do nothing when I push button with assigned script. The task of it is simple to set player avatar from native gallery. Traget API 33. If I miss something?
     
  22. Grimmjow_Jaegerjackquez

    Grimmjow_Jaegerjackquez

    Joined:
    Dec 14, 2021
    Posts:
    16
    Hi @yasirkula , sorry for the late reply , I wrote debug for all checks and found that only debug 1 and 5 were called. Tested in editor , Unity 2022.3.11f1


    public static ImageProperties GetImageProperties( string imagePath )
    {
    if( !File.Exists( imagePath ) )
    throw new FileNotFoundException( "File not found at " + imagePath );

    #if !UNITY_EDITOR && UNITY_ANDROID
    string value = AJC.CallStatic<string>( "GetImageProperties", Context, imagePath );
    #elif !UNITY_EDITOR && UNITY_IOS
    string value = _NativeGallery_GetImageProperties( imagePath );
    #else
    string value = null;
    #endif
    Debug.Log("Debug1");
    int width = 0, height = 0;
    string mimeType = null;
    ImageOrientation orientation = ImageOrientation.Unknown;
    if( !string.IsNullOrEmpty( value ) )
    {
    Debug.Log("Debug2");
    string[] properties = value.Split( '>' );
    if( properties != null && properties.Length >= 4 )
    {
    Debug.Log("Debug3");
    if ( !int.TryParse( properties[0].Trim(), out width ) )
    width = 0;
    if( !int.TryParse( properties[1].Trim(), out height ) )
    height = 0;

    mimeType = properties[2].Trim();
    if( mimeType.Length == 0 )
    {
    Debug.Log("Debug4");
    string extension = Path.GetExtension( imagePath ).ToLowerInvariant();
    if( extension == ".png" )
    mimeType = "image/png";
    else if( extension == ".jpg" || extension == ".jpeg" )
    mimeType = "image/jpeg";
    else if( extension == ".gif" )
    mimeType = "image/gif";
    else if( extension == ".bmp" )
    mimeType = "image/bmp";
    else
    mimeType = null;
    }

    int orientationInt;
    if( int.TryParse( properties[3].Trim(), out orientationInt ) )
    orientation = (ImageOrientation) orientationInt;
    }
    }
    Debug.Log("Debug5");
    return new ImageProperties( width, height, mimeType, orientation );
    }
     
  23. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
  24. Grimmjow_Jaegerjackquez

    Grimmjow_Jaegerjackquez

    Joined:
    Dec 14, 2021
    Posts:
    16
    Hmm , that explains the issue. Thanks.
     
    yasirkula likes this.
  25. lonewolf4_

    lonewolf4_

    Joined:
    May 20, 2019
    Posts:
    2
    yasir hocam merhaba,
    kodumda aracın üzerindeki stickerı kaydetme ve yükleme işlemini yapmak istiyorum ama birşeyler ters gidiyor
    işte kodların bir kaçı gerekli düzenlemeyi nasıl yapabilirim yardımcı olurmusunuz teşekürler.

    Code (CSharp):
    1. #if UNITY_ANDROID || UNITY_IOS || UNITY_WP_8 //ATTENTION: YOU NEED NATIVE GALLERY TO USE IT ON MOBILE! ////
    2.        tex = NativeGallery.LoadImageAtPath(NativeGallery.GetSavePath(Application.productName + "_Livery", fileName));
    3.  
    4.         CarMaterial[CarIndex].SetTexture("_MainTex", tex);
    5.  
    6.         SelectedLivery = 99 + slot;
    7.  
    8.         carColorManager.SelectedLivery = SelectedLivery;
    9.  
    10.         //save the slot used
    11.         PlayerPrefs.SetInt(carColorManager.CarSelected + "Livery", 99 + slot);
    12.  
    13.         StartCoroutine(UpdateMaterials());
    14.         //show text on message text : texture is loaded
    15.         if (MessageText) StartCoroutine(SavedTextAnimation("LOADED!", 1.5f));
    16. #endif
    17.  
    18.  
    19.  
    20.  
    21.  
    22. #if UNITY_ANDROID || UNITY_IOS || UNITY_WP_8 //ATTENTION: YOU NEED NATIVE GALLERY TO USE IT ON MOBILE! ////
    23.         NativeGallery.CheckPermission ();
    24.         NativeGallery.SaveImageToGallery(bytes, Application.productName + "_Livery", fileName);
    25.         yield return new WaitForSeconds (2f);
    26. #endif
     
  26. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    @lonewolf4_ NativeGallery.GetSavePath fonksiyonu bulunmuyor. NativeGallery.GetImageFromGallery kullanmanız lazım. Kullanıcının en son kaydettiği resme erişmek istiyorsanız, malesef resmin bir kopyasını persistentDataPath'e kopyalamak dışında bunun bir yolu bulunmuyor.
     
  27. cnsjjj

    cnsjjj

    Joined:
    Aug 13, 2022
    Posts:
    35
    Hi! @yasirkula
    Thanks for the awesome two packages!

    The version of UnityNativeGallery I use is 1.7.7, which is packaged on XCode15.0.1 and run on ios17.0.3. Both packaging and running are normal.

    But there was a small problem with the animation. When I opened the uitoolkit page and jumped to the native gallery page, the animation was normal. When I clicked Cancel again, the page was stuck and immediately jumped to the uitoolkit page. The animation was missing during the process. If I don't click cancel but close by swiping down the page, the animation works fine.

    The animation of UnityNativeFilePicker (1.3.2) freezes when opening the native page. When the close button is clicked, the page animation runs normally.

    Sorry, I can't find the cause of the problem. Is this a bug?
     
    Last edited: Nov 29, 2023
  28. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    @cnsjjj Hi, this is intentional. You can set all dismissViewControllerAnimated calls inside NativeGallery.mm to YES to revert it. I've encountered edge cases during the close animation (maybe when showing the dialog while it's being closed? I can't remember) which is why the animations are turned off by default.
     
    cnsjjj likes this.
  29. cnsjjj

    cnsjjj

    Joined:
    Aug 13, 2022
    Posts:
    35
    Thanks a lot! This method works for NativeGallery but not for NativeFilePicker.

    Thanks very much for your answer again!
     
  30. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    I'm sorry to hear that. I'd expect the same to work for NativeFilePicker, too. Note that while displaying a dialog, presentViewController function is called, which also has its own animated property.
     
  31. cnsjjj

    cnsjjj

    Joined:
    Aug 13, 2022
    Posts:
    35
    Sorry, I still haven't been able to solve the problem.
    I changed dismissViewControllerAnimated and presentViewController to YES. The animation ran normally, but there was a problem of page jitter. The pop-up page would first animate to the top of the phone page, and then suddenly jump back to normal location.
    Thanks again!
     
  32. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    At first glance, I couldn't spot anything that would cause this. Could you spot possibly problematic lines in the native source code?
     
    cnsjjj likes this.
  33. cnsjjj

    cnsjjj

    Joined:
    Aug 13, 2022
    Posts:
    35
    I found it was my mistake. I didn't give the correct file type format which caused the above problem.
    All problems have been solved. I'm very sorry for causing you any trouble.
    Thanks again for your help!
     
    yasirkula likes this.
  34. smritichopra3

    smritichopra3

    Joined:
    Feb 5, 2020
    Posts:
    12
    Hey @yasirkula I seem to be running into a weird problem. My Android app is able to access images from the gallery no problem at runtime, but when I save and load the image paths from the persistent data path location, I get permission errors at app startup. In particular, NativeGallery.LoadImageAtPath() function fails.

    Warn System.err java.lang.SecurityException: Calling uid ( 10315 ) does not have permission to access picker uri: content://media/picker/0/com.android.providers.media.photopicker/media/1000000023

    Error Unity FileNotFoundException: File not found at /sdcard/.transforms/synthetic/picker/0/com.android.providers.media.photopicker/media/1000000023.jpg


    I have WRITE_EXTERNAL_STORAGE in my Manifest file, and Player settings set to external SD Card.
    I'm not sure what the problem could be, considering I am successfully able to write and read the paths, but suddenly unable to access them. Would you be able to point me in the right direction pls?
     
  35. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    @smritichopra3 May I ask your Android version, device model and Unity version?
     
  36. smritichopra3

    smritichopra3

    Joined:
    Feb 5, 2020
    Posts:
    12
    Last edited: Dec 12, 2023
    yasirkula likes this.
  37. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    May I ask how you suspected the persistable URI permissions? To my knowledge, persistable URI permission can be granted by the app that gave the URI to us. In this case, that's the Gallery app.

    I'll investigate this issue further when I get the chance. It's just that I've a bust schedule on weekdays.
     
  38. smritichopra3

    smritichopra3

    Joined:
    Feb 5, 2020
    Posts:
    12
    Oh no I was hoping you'd know a quick fix :( My app is a bit time critical, it's for christmas.
    I was googling for answers where I came across several posts that comment on how to access a URI again (after a restart for example), you'd need to grant persistable permissions. Here's an example: https://stackoverflow.com/questions...rsistable-uri-permission-with-pickvisualmedia

    In your use cases so far, has nobody tried to access their images from saved paths before? Wondering if this has always been an issue, or is popping up in later versions.

    I know I could probably save and load the images themselves from the persistent data path, but that's memory I don't want to expend.
     
  39. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    I've seen just one more issue similar to yours that was reported recently. It's certainly new. When people ask me how to retrieve the last photos that they've saved to Gallery, I recommend them to save another copy to persistentDataPath because NativeGallery doesn't have that functionality. Unless you're saving tons of large images, that's still a valid choice in my opinion, considering the urgency of the matter. I hope I'll be able to pinpoint the issue quickly when I get the chance.
     
    smritichopra3 likes this.
  40. smritichopra3

    smritichopra3

    Joined:
    Feb 5, 2020
    Posts:
    12
    It's a photo carousel app so I do not have control over the number of images saved, hence I cannot really go with saving and loading the images themselves :(

    Would you be open to sharing the source code for your Android java classes? That way I can simultaneously look for a fix as well. I emailed you, it would be a great help if that's an option!
     
  41. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
  42. smritichopra3

    smritichopra3

    Joined:
    Feb 5, 2020
    Posts:
    12
    Hey @yasirkula I fixed the problem by adding the following snippet to your code:
    Code (CSharp):
    1.     private String getPathFromURI( Uri uri )
    2.     {
    3.         if( uri == null )
    4.             return null;
    5.  
    6.         Log.d( "Unity", "Selected media uri: " + uri.toString() );
    7.         Log.d( "Unity", "Attempting persistable permissions for media uri: " + uri.toString() );
    8.  
    9.         try
    10.         {
    11.             ContentResolver resolver = context.getContentResolver();
    12.             resolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
    13.             resolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    14.         }
    15.         catch( Exception e )
    16.         {
    17.             Log.e( "Unity", "Exception:", e );
    18.         }
    This allows the user to save and load paths instead of images, and retrieve them in-between app sessions. Thanks again for pointing me to your source code, this should be a good addition to your already awesome plugin!
     
  43. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    Thank you for sharing this solution :) May I ask how the plugin behaved before you've added those takePersistableUriPermission calls?
     
  44. smritichopra3

    smritichopra3

    Joined:
    Feb 5, 2020
    Posts:
    12
    Sure. I was saving user selected image paths in between app sessions. However, on a fresh restart, I couldn't reload the images from those presaved paths due to lack of persistableURI permissions. The plugin worked perfectly at runtime, however to reuse the paths (URIs) across app sessions, we need these permissions. You can look at my previous posts for the exact errors it threw!
     
  45. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    Hmm, the uri can be a storage access framework path like
    content://com.android.externalstorage.documents/tree/primary%3A/document/primary%3APictures
    . In fact, I expect most uris passed to getPathFromURI to be like this. Since System.IO or Texture2D.LoadImage work only with raw file paths, how are you using the uri and how are you fetching it from NativeGallery (NativeGallery doesn't return the uri)?
     
  46. smritichopra3

    smritichopra3

    Joined:
    Feb 5, 2020
    Posts:
    12
    Hmm okay. Well, I'm not doing anything fancy here, I'm simply saving the raw paths that are returned from Native Gallery to the persistent data folder in Androids, and upon trying to read them again after an app shutdown, I get the following error:

    Warn System.err java.lang.SecurityException: Calling uid ( 10315 ) does not have permission to access picker uri: content://media/picker/0/com.android.providers.media.photopicker/media/1000000023

    Honestly I have never developed on Androids before, so I might not be saving the paths in the correct location? Though I thought Application.persistentDataPath was the way to go. Looks like upon getting this error (which is common it seems), the fix is to get the right permissions and that's what I did. If there's a better solution, please let me know I'll be happy to take it :)
     
  47. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    I mean, are you saving these paths in a json file inside persistentDataPath and then reading that json file to get the path string and use that path string with a NativeGallery/Unity function? If so, I really would like to know which NativeGallery/Unity function you've used that worked without any issues with the path "content://media/picker/0/com.android.providers.media.photopicker/media/1000000023". Or, are you simply copying the source image to persistentDataPath and then reading the image itself from there? In that case where does the path "content://media/picker/0/com.android.providers.media.photopicker/media/1000000023" come into play?
     
  48. smritichopra3

    smritichopra3

    Joined:
    Feb 5, 2020
    Posts:
    12
    Correct on the first part. I'm writing the paths as strings to json, reading them after a shutdown, and trying to load the image from them using NativeGallery.LoadImageAtPath(path). The same function was throwing the FileNotFound exception, and is not anymore after I added the snippet as discussed previously. Hope that helps!
     
    yasirkula likes this.
  49. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,910
    Thank you for all the information! Lastly, did you comment out this File.Exists call or it just works with "content://media/picker/0/com.android.providers.media.photopicker/media/1000000023"? PS. You were using SaveImageToGallery and caching its returned path, not using GetImageFromGallery, right?
     
  50. smritichopra3

    smritichopra3

    Joined:
    Feb 5, 2020
    Posts:
    12
    Sure no problem. To answer your questions:
    1) Nope, I didn't comment anything out, simply added the snippet for permissions that I mentioned and it just works.
    2) I am only ever using 2 NativeGallery functions - NativeGallery.GetImagesFromGallery to get the paths of the user selected images from the gallery, and NativeGallery.LoadImageAtPath there onwards for whenever I want to load an image from the retrieved path (either afresh from the Gallery or after an app shutdown from json)