Skip to content

Commit

Permalink
On Android 33+, it's now possible to preserve access to the picked im…
Browse files Browse the repository at this point in the history
…ages after the app is restarted but it isn't recommended (see the relevant FAQ entry)(#328)
  • Loading branch information
yasirkula committed Aug 10, 2024
1 parent 66157bd commit 8bb2dbd
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import android.app.Activity;
import android.app.Fragment;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
Expand All @@ -29,6 +30,7 @@ public class NativeGalleryMediaPickerFragment extends Fragment
public static boolean tryPreserveFilenames = false; // When enabled, app's cache will fill more quickly since most of the images will have a unique filename (less chance of overwriting old files)
public static boolean showProgressbar = true; // When enabled, a progressbar will be displayed while selected file(s) are copied (if necessary) to the destination directory
public static boolean useDefaultGalleryApp = false; // false: Intent.createChooser is used to pick the Gallery app
public static boolean GrantPersistableUriPermission = false; // When enabled, on newest Android versions, picked file can still be accessed after the app is restarted. Note that there's a 512-file hard limit: https://issuetracker.google.com/issues/149315521#comment7

private final NativeGalleryMediaReceiver mediaReceiver;
private boolean selectMultiple;
Expand All @@ -49,7 +51,10 @@ public void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
if( mediaReceiver == null )
{
Log.e( "Unity", "NativeGalleryMediaPickerFragment.mediaReceiver became null in onCreate!" );
onActivityResult( MEDIA_REQUEST_CODE, Activity.RESULT_CANCELED, null );
}
else
{
int mediaType = getArguments().getInt( MEDIA_TYPE_ID );
Expand Down Expand Up @@ -114,6 +119,9 @@ else if( mediaType == NativeGallery.MEDIA_TYPE_VIDEO )
intent.setType( mime );
}

if( ShouldGrantPersistableUriPermission( getActivity() ) )
intent.addFlags( Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION );

if( title != null && title.length() > 0 )
intent.putExtra( Intent.EXTRA_TITLE, title );

Expand All @@ -133,6 +141,11 @@ else if( mediaType == NativeGallery.MEDIA_TYPE_VIDEO )
}
}

public static boolean ShouldGrantPersistableUriPermission( Context context )
{
return GrantPersistableUriPermission && Build.VERSION.SDK_INT >= 33 && context.getApplicationInfo().targetSdkVersion >= 33;
}

@Override
public void onActivityResult( int requestCode, int resultCode, Intent data )
{
Expand All @@ -142,7 +155,7 @@ public void onActivityResult( int requestCode, int resultCode, Intent data )
NativeGalleryMediaPickerResultFragment resultFragment = null;

if( mediaReceiver == null )
Log.d( "Unity", "NativeGalleryMediaPickerFragment.mediaReceiver became null!" );
Log.d( "Unity", "NativeGalleryMediaPickerFragment.mediaReceiver became null in onActivityResult!" );
else if( resultCode != Activity.RESULT_OK || data == null )
{
if( !selectMultiple )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.OpenableColumns;
import android.util.Log;
import android.webkit.MimeTypeMap;
Expand Down Expand Up @@ -50,9 +51,11 @@ public void execute()
{
if( !selectMultiple || data.getClipData() == null )
{
unityResult = getPathFromURI( data.getData() );
if( unityResult == null || ( unityResult.length() > 0 && !( new File( unityResult ).exists() ) ) )
unityResult = "";
String _unityResult = getPathFromURI( data.getData() );
if( _unityResult != null && _unityResult.length() > 0 && new File( _unityResult ).exists() )
unityResult = _unityResult;

Log.d( "Unity", "NativeGalleryMediaPickerResultOperation: " + _unityResult );
}
else
{
Expand All @@ -73,6 +76,8 @@ public void execute()
else
unityResult += ">" + _unityResult;
}

Log.d( "Unity", "NativeGalleryMediaPickerResultOperation: " + _unityResult );
}
}
}
Expand Down Expand Up @@ -106,7 +111,7 @@ public void sendResultToUnity()
sentResult = true;

if( mediaReceiver == null )
Log.d( "Unity", "NativeGalleryMediaPickerResultOperation.mediaReceiver became null!" );
Log.d( "Unity", "NativeGalleryMediaPickerResultOperation.mediaReceiver became null in sendResultToUnity!" );
else
{
if( selectMultiple )
Expand All @@ -133,10 +138,14 @@ private String getPathFromURI( Uri uri )
inputStream = new FileInputStream( new File( path ) );
inputStream.read();

if( NativeGalleryMediaPickerFragment.ShouldGrantPersistableUriPermission( context ) )
context.getContentResolver().takePersistableUriPermission( uri, Intent.FLAG_GRANT_READ_URI_PERMISSION );

return path;
}
catch( Exception e )
{
Log.e( "Unity", "Media uri isn't accessible via File API: " + uri, e );
}
finally
{
Expand Down Expand Up @@ -214,7 +223,10 @@ else if( filename.endsWith( extension ) )
{
InputStream input = resolver.openInputStream( uri );
if( input == null )
{
Log.w( "Unity", "Couldn't open input stream: " + uri );
return null;
}

if( fileSize < 0 )
{
Expand Down Expand Up @@ -289,6 +301,7 @@ else if( fileSize > 0 )
savedFiles.add( fullName );
}

Log.d( "Unity", "Copied media from " + uri + " to: " + tempFile.getAbsolutePath() );
return tempFile.getAbsolutePath();
}
finally
Expand Down
9 changes: 9 additions & 0 deletions .github/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ Only Android & iOS platforms are supported. Editor functionality is for preview

If you are sure that your plugin is up-to-date, then enable **Custom Proguard File** option from *Player Settings* and add the following line to that file: `-keep class com.yasirkula.unity.* { *; }`

- **I save the picked image's path for later use but I can no longer access it after restarting the app**

This happens on Android 33+ devices when *Target API Level* is set to 33 or later. The recommended solution is to copy the image to [persistentDataPath](https://docs.unity3d.com/ScriptReference/Application-persistentDataPath.html) because otherwise, the source image can be deleted by the user from Gallery, deleted by the operating system to free up space or overwritten by NativeGallery in the next *PickImage* call (if NativeGallery can't determine the image's source file path, then it copies the picked image to a fixed location in temporaryCachePath and thus, the image can easily be overwritten). If you still would like to persist access to the image, you can call the following code in your *Awake* function but be aware that this fix has a [hard limit of 512 files](https://issuetracker.google.com/issues/149315521#comment7):

#if !UNITY_EDITOR && UNITY_ANDROID
using( AndroidJavaClass ajc = new AndroidJavaClass( "com.yasirkula.unity.NativeGalleryMediaPickerFragment" ) )
ajc.SetStatic<bool>( "GrantPersistableUriPermission", true );
#endif

- **Android build fails, it says "error: attribute android:requestLegacyExternalStorage not found" in Console**

`android:requestLegacyExternalStorage` attribute in _AndroidManifest.xml_ fixes a rare UnauthorizedAccessException on Android 10 but requires you to update your Android SDK to at least **SDK 29**. If this isn't possible for you, you should open *NativeGallery.aar* with WinRAR or 7-Zip and then remove the `<application ... />` tag from _AndroidManifest.xml_.
Expand Down
Binary file modified Plugins/NativeGallery/Android/NativeGallery.aar
Binary file not shown.
2 changes: 1 addition & 1 deletion Plugins/NativeGallery/README.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
= Native Gallery for Android & iOS (v1.8.0) =
= Native Gallery for Android & iOS (v1.8.1) =

Documentation: https://github.com/yasirkula/UnityNativeGallery
FAQ: https://github.com/yasirkula/UnityNativeGallery#faq
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "com.yasirkula.nativegallery",
"displayName": "Native Gallery",
"version": "1.8.0",
"version": "1.8.1",
"documentationUrl": "https://github.com/yasirkula/UnityNativeGallery",
"changelogUrl": "https://github.com/yasirkula/UnityNativeGallery/releases",
"licensesUrl": "https://github.com/yasirkula/UnityNativeGallery/blob/master/LICENSE.txt",
Expand Down

0 comments on commit 8bb2dbd

Please sign in to comment.