New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IOS 14 permissions handling #136
Comments
I may not be able to resolve this issue until I get my hands on an iOS 14 device but thanks for reporting it. |
how about you update it and i will test it for you? |
Do you get any error messages in Xcode console when attempting to save an image? |
okay i will get you the full logs as soon as possible (y) |
yup its the same problem :( |
For reference, here's the possible solution to this problem: https://mackuba.eu/2020/07/07/photo-library-changes-ios-14/ |
@MaryamSaeed I've added the following features to the plugin:
UPDATE (09/17): on iOS 14, when PermissionFreeMode is set to true, SaveImageToGallery/SaveVideoToGallery will ignore the album parameter: #136 (comment) Download: redacted, simply download the latest version of the plugin Unfortunately, I couldn't test most of these features because Unity doesn't support iOS 14 simulators and I don't have an iOS 14 device. The features I really wanted to test on iOS 14 are:
If you could test these features for me, I'd really appreciate it. I've written the following test script, you may find it useful: // This must be assigned value from the Inspector
public Texture2D image;
private GUIStyle buttonStyle;
private int optionsUnlocked;
private void OnGUI()
{
if( buttonStyle == null )
buttonStyle = new GUIStyle( GUI.skin.button ) { fontSize = Screen.height / 40, wordWrap = true };
float width = Screen.width;
float height = Screen.height;
if( optionsUnlocked == 0 )
{
if( GUI.Button( new Rect( 0f, 0f, width, height * 0.2f ), "See Buttons", buttonStyle ) )
{
optionsUnlocked = 1;
Invoke( "UnlockOptions", 0.1f );
GUIUtility.ExitGUI();
}
}
else if( optionsUnlocked == 2 )
{
bool interacted = false;
if( GUI.Button( new Rect( 0f, 0f, width / 3, height * 0.2f ), "Permission Free Mode: " + NativeGallery.PermissionFreeMode, buttonStyle ) )
NativeGallery.PermissionFreeMode = !NativeGallery.PermissionFreeMode;
if( GUI.Button( new Rect( width / 3, 0f, width / 3, height * 0.2f ), "Check Read Permission", buttonStyle ) )
print( NativeGallery.CheckPermission( NativeGallery.PermissionType.Read ) );
if( GUI.Button( new Rect( width * 2 / 3, 0f, width / 3, height * 0.2f ), "Check Write Permission", buttonStyle ) )
print( NativeGallery.CheckPermission( NativeGallery.PermissionType.Write ) );
if( GUI.Button( new Rect( 0f, height * 0.2f, width / 3, height * 0.2f ), "Request Read Permission", buttonStyle ) )
{
interacted = true;
print( NativeGallery.RequestPermission( NativeGallery.PermissionType.Read ) );
}
if( GUI.Button( new Rect( width / 3, height * 0.2f, width / 3, height * 0.2f ), "Request Write Permission", buttonStyle ) )
{
interacted = true;
print( NativeGallery.RequestPermission( NativeGallery.PermissionType.Write ) );
}
if( GUI.Button( new Rect( width * 2 / 3, height * 0.2f, width / 3, height * 0.2f ), "Extend Limited Permission", buttonStyle ) )
{
interacted = true;
NativeGallery.TryExtendLimitedAccessPermission();
}
if( GUI.Button( new Rect( 0f, height * 0.4f, width / 3, height * 0.2f ), "Get Image", buttonStyle ) )
{
interacted = true;
print( NativeGallery.GetImageFromGallery( ( path ) =>
{
print( path );
DisplayImage( path );
} ) );
}
if( GUI.Button( new Rect( width / 3, height * 0.4f, width / 3, height * 0.2f ), "Get Video", buttonStyle ) )
{
interacted = true;
print( NativeGallery.GetVideoFromGallery( ( path ) =>
{
print( path );
DisplayVideo( path );
} ) );
}
if( GUI.Button( new Rect( width * 2 / 3, height * 0.4f, width / 3, height * 0.2f ), "Get Image/Video", buttonStyle ) )
{
interacted = true;
print( NativeGallery.GetMixedMediaFromGallery( ( path ) =>
{
print( path );
if( path != null )
{
// Determine if user has picked an image, video or neither of these
switch( NativeGallery.GetMediaTypeOfFile( path ) )
{
case NativeGallery.MediaType.Image: Debug.Log( "Picked image" ); break;
case NativeGallery.MediaType.Video: Debug.Log( "Picked video" ); break;
default: Debug.Log( "Probably picked something else" ); break;
}
}
}, NativeGallery.MediaType.Image | NativeGallery.MediaType.Video ) );
}
if( GUI.Button( new Rect( 0f, height * 0.6f, width / 3, height * 0.2f ), "Get Images", buttonStyle ) )
{
interacted = true;
print( NativeGallery.GetImagesFromGallery( ( paths ) =>
{
if( paths != null )
{
for( int i = 0; i < paths.Length; i++ )
{
print( paths[i] );
if( i == paths.Length - 1 )
DisplayImage( paths[i] );
}
}
} ) );
}
if( GUI.Button( new Rect( width / 3, height * 0.6f, width / 3, height * 0.2f ), "Get Videos", buttonStyle ) )
{
interacted = true;
print( NativeGallery.GetVideosFromGallery( ( paths ) =>
{
if( paths != null )
{
for( int i = 0; i < paths.Length; i++ )
{
print( paths[i] );
if( i == paths.Length - 1 )
DisplayVideo( paths[i] );
}
}
} ) );
}
if( GUI.Button( new Rect( width * 2 / 3, height * 0.6f, width / 3, height * 0.2f ), "Get Images/Videos", buttonStyle ) )
{
interacted = true;
print( NativeGallery.GetMixedMediasFromGallery( ( paths ) =>
{
if( paths != null )
{
for( int i = 0; i < paths.Length; i++ )
{
print( paths[i] );
// Determine if user has picked an image, video or neither of these
switch( NativeGallery.GetMediaTypeOfFile( paths[i] ) )
{
case NativeGallery.MediaType.Image: Debug.Log( "Picked image" ); break;
case NativeGallery.MediaType.Video: Debug.Log( "Picked video" ); break;
default: Debug.Log( "Probably picked something else" ); break;
}
}
}
}, NativeGallery.MediaType.Image | NativeGallery.MediaType.Video ) );
}
if( GUI.Button( new Rect( 0f, height * 0.8f, width, height * 0.2f ), "Save Image", buttonStyle ) )
{
interacted = true;
print( NativeGallery.SaveImageToGallery( image, "Test Album", "Hello world.png", ( bool success, string path ) =>
{
print( "Save result: " + success + " " + path );
} ) );
}
if( interacted )
{
optionsUnlocked = 1;
Invoke( "LockOptions", 0.1f );
GUIUtility.ExitGUI();
}
}
}
private void DisplayImage( string path )
{
if( path != null )
{
// Create Texture from selected image
Texture2D texture = NativeGallery.LoadImageAtPath( path, 512 );
if( texture == null )
{
Debug.Log( "Couldn't load texture from " + path );
return;
}
// Assign texture to a temporary quad and destroy it after 5 seconds
GameObject quad = GameObject.CreatePrimitive( PrimitiveType.Quad );
quad.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 2.5f;
quad.transform.forward = Camera.main.transform.forward;
quad.transform.localScale = new Vector3( 1f, texture.height / (float) texture.width, 1f );
Material material = quad.GetComponent<Renderer>().material;
if( !material.shader.isSupported ) // happens when Standard shader is not included in the build
material.shader = Shader.Find( "Legacy Shaders/Diffuse" );
material.mainTexture = texture;
Destroy( quad, 5f );
Destroy( texture, 5f );
}
}
private void DisplayVideo( string path )
{
if( path != null )
Handheld.PlayFullScreenMovie( "file://" + path ); // It is OK if this function sometimes fails due to "Couldn't attach movie player to UIImagePickerController"-like warnings
}
private void UnlockOptions()
{
optionsUnlocked = 2;
}
private void LockOptions()
{
optionsUnlocked = 0;
} |
Has this been resolved? Is the fix released on the asset store? |
I'll release the fix when it is confirmed to be working. You can check out the post above to download the latest version and test it on your iOS 14 devices. |
Ok, thanks, I'll test tomorrow once I install iOS 14 beta and Xcode beta. |
@yasirkula I am testing at the moment. The read works great, I can pick images and videos. The write permission I am still not sure of. My app needs only the write access, it doesn't need to access to files without user selection. |
@yasirkula also when the write permission is granted the app returns the permission immediately, not after the second permission window closes. |
Hmm, I fear that the second permission is asked by the OS when I try to save the video to a specific album. I'm guessing that the second permission dialog had 3 options: Allow, Select Photos and Deny, am I right? |
@yasirkula yes exactly. Is there a way to only save without a specific album? |
Yes, inside NativeGallery.mm file, delete lines [405, 466] and put a single To resolve this issue in general, I think I'll support 2 different use-cases:
|
@yasirkula thank you for the solution, but the lines you told me about don't seem to correspond to the file I have. |
@yasirkula I am also getting the following error when I only have read permission: |
In your case, you can delete lines [413,474] and insert The "you don't have permission to view it" warning is normal when you grant "Selected photos" permission but pick a photo that wasn't included in "Selected photos". This should happen only when PermissionFreeMode is set to false. This warning message is harmless so you can safely ignore it in either case (I'm assuming that the picked image was loaded successfully in Unity). |
@yasirkula thanks very much, just checked and the fix is working fine. |
@yasirkula Do you have a time estimate on when your fix is ready? :) |
@aengmo1 I need to verify that the use-cases I've mentioned in this comment are all working properly. Unity doesn't support iOS 14 simulators and I don't have an iOS 14 device, so I can't verify them at the moment. |
@yasirkula so sorry for may late reply and thank you for the updates, |
@MaryamSaeed Hmm, did this happen after updating the plugin using the download link I've provided? Were there any error messages in Xcode console? |
@yasirkula yes ,i am setting up Xcode 12 and will check what message i get from the console when i open the app and attempt to save for the first time a prompt appears and and ask to add photos giving 2 options allow and deny , when i allow photos the image gets saved in recents, |
@yasirkula Thank you for the recent updates... we just needed write-only access and it's made the iOS 14 permissions prompt nice and tidy now. |
@dtaddisF42 Yes, the write-only permission dialog is definitely more user friendly than the one with "Select Photos" option. The only downside is that the custom album name will be ignored. I hope Apple allows us to save media to custom albums with write-only permission 🤞 |
@yasirkula Okay i am running your test cases now,
saving an image to Photos when full Photos access isn't granted (I suspect that the image will be saved to the default Camera Roll album instead of the custom album in this case). This must be tested in 2 different ways:
there are 2 features i did not test yet Update |
Thank you for testing these features, your help is much appreciated. I see that half of the features don't work at all... I'll have to wait until Unity adding support for iOS 14 simulators so that I can debug these issues in detail :/ Until then, I won't release this iOS 14 update. |
@yasirkula glad i could help 😄 , |
As far as I understand, trying to write to Photos with "Select Photos" permission freezes the device with a "Saving non-readable textures is slower" log. That log is normal but the freeze isn't. At the moment, I'm unsure about the cause of the freeze. I'll get to the bottom of it when iOS 14 simulators are supported :D |
@yasirkula check this out , |
But why would it freeze when you first tested it? TryExtendLimitedAccessPermission freezing is also a similar issue. |
the above image is for the example i am testing on, |
It looks like these screenshots are taken from the app's permission settings in Settings app. I think that as long as the permission dialog with "Select Photos" option isn't displayed (i.e. when app is in PermissionFreeMode), only the "Add Photos Only" permission will be listed in Settings. After displaying the permission dialog with "Select Photos" option, Settings will expand to include all 3 options. But still, this isn't related to the freeze problem, am I right? |
let me test this scenario and get back to you
|
I am also having issues with permission handling in iOS 14. When application is first launched it asks for permissions on either of the above events. When the app is manually closed and restarted it no longer asks for permissions and seems to work ok. |
Does the app still freeze when you comment out the |
After commenting this line in two places a new window comes out to select pictures that will be available for the app. Confirmimg this window stops the process. The app now seems to be alive but the gallery selection windows does not appear. Need to restart the app to work. |
Do you also encounter the freeze issue that occurs after calling TryExtendLimitedAccessPermission and selecting "Select Photos"? |
Now I noticed your post above with beta version of Native Gallery. Uploaded it to the project and now it seems to work fine. |
Hi, I used master and appstore told me app can not save picture in IOS14.1. |
|
If you don't touch the value of NativeGallery.PermissionFreeMode, then you should be good to go. The only downside is that, your images will be saved to default Photos album rather than the one you've passed as parameter. |
|
You should use the zip archive, yes. |
Thank you again~ |
Thank you very much!It can save to default album~ |
With the latest release, I removed the PermissionFreeMode property (set it to always true). Also removed the LimitedAccess permission (treated it as Granted) since in PermissionFreeMode, the "Select Photos" permission isn't displayed at all. This way, the current API stayed pretty much the same. The only downside is that, photos/videos will be saved to the default Photos album instead of the specified custom album on iOS 14+. To be able to save media to a custom album, we must show the "Allow Access", "Select Photos", "Deny" permission dialog and the user must select the "Allow Access" option. Clicking "Select Photos" freezes the app (I think due to how I handle the permission dialog synchronously) and even if it didn't freeze, it is a weird user experience to see "Select Photos" option while attempting to save an image to Photos. |
If I want to show the "Select photos" Option, but after iOS11+, the permission is always allowed. |
Why would you want to show "Select Photos" permission option? |
I want user to manage his gallery permission.. |
I still don't get it, sorry. You don't need any permissions to get media from Photos on iOS11+ and you need to show only an "Allow/Deny" permission to save media to Photos. "Select Photos" permission is completely redundant. Why would you want to show a permission option that does basically nothing in NativeGallery? |
Because maybe a user doesn't want the game to access some photos in the gallery, though on iOS11+ we can access all permission. I think that's the reason why iOS14 push the new permission solution. So I want to show "Select Photos" option, that they can manage their own gallery permission. |
I see your point but Select Photos doesn't work like that. PHPickerViewController will always show the whole album regardless of Select Photos. That is internal design by iOS team and it is a good thing because: 1) seeing all photos in PHPickerViewController doesn't mean that app has instant access to these photos, app has access to only the picked photos because otherwise it would be a ridiculous privacy issue and 2) as I said, we don't need any permissions. Select Photos permission is used only to fetch sensitive metadata from picked images or access those selected photos programmatically without needing to present the image picker (PHPickerViewController). I'd recommend you to google "select photos shows all gallery PHPickerViewController" and "ios 14 PHPickerViewController" for more info. |
Hello. Im using this version to fix iOS crash. but not it is crashing on android.
|
You should check logcat logs to find the crash logs, check if an Issue has already been created for that error and if not, create a new Issue. |
Description:
i used the example written in the wiki ,When i change permission of photos to “selected photos” then attempting to save an image it does not get saved.
suggestion :
add a value to enum NativeGallery.Permission to handle “selected photos” permission.
The text was updated successfully, but these errors were encountered: