Skip to content

Commit c8528c4

Browse files
committed
- BREAKING CHANGE: CheckPermission returns bool instead of Permission (see yasirkula/UnityAndroidRuntimePermissions#14)
- BREAKING CHANGE: Replaced RequestPermission with RequestPermissionAsync (see yasirkula/UnityNativeGallery#343) - Updated Unity version to 2021.3.41f1 (simplified codebase accordingly) - iOS frameworks are now added properly instead of changing OTHER_LDFLAGS - Fixed Xcode compiler warnings
1 parent de516b9 commit c8528c4

11 files changed

Lines changed: 91 additions & 224 deletions

File tree

.github/AAR Source (Android)/java/com/yasirkula/unity/NativeFilePicker.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,20 +89,14 @@ public static int CheckPermission( Context context, final boolean readPermission
8989
}
9090

9191
// Credit: https://github.com/Over17/UnityAndroidPermissions/blob/0dca33e40628f1f279decb67d901fd444b409cd7/src/UnityAndroidPermissions/src/main/java/com/unity3d/plugin/UnityAndroidPermissions.java
92-
public static void RequestPermission( Context context, final NativeFilePickerPermissionReceiver permissionReceiver, final boolean readPermissionOnly, final int lastCheckResult )
92+
public static void RequestPermission( Context context, final NativeFilePickerPermissionReceiver permissionReceiver, final boolean readPermissionOnly )
9393
{
9494
if( CheckPermission( context, readPermissionOnly ) == 1 )
9595
{
9696
permissionReceiver.OnPermissionResult( 1 );
9797
return;
9898
}
9999

100-
if( lastCheckResult == 0 ) // If user clicked "Don't ask again" before, don't bother asking them again
101-
{
102-
permissionReceiver.OnPermissionResult( 0 );
103-
return;
104-
}
105-
106100
Bundle bundle = new Bundle();
107101
bundle.putBoolean( NativeFilePickerPermissionFragment.READ_PERMISSION_ONLY, readPermissionOnly );
108102

.github/README.md

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ Make sure that you've set the **Write Permission** to **External (SDCard)** in *
6868

6969
- **NativeFilePicker functions return Permission.Denied even though I've set "Write Permission" to "External (SDCard)"**
7070

71-
Declare the `WRITE_EXTERNAL_STORAGE` permission manually in your [**Plugins/Android/AndroidManifest.xml** file](https://answers.unity.com/questions/982710/where-is-the-manifest-file-in-unity.html) with the `tools:node="replace"` attribute as follows: `<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="replace"/>` (you'll need to add the `xmlns:tools="http://schemas.android.com/tools"` attribute to the `<manifest ...>` element).
71+
Declare the `WRITE_EXTERNAL_STORAGE` permission manually in your **Plugins/Android/AndroidManifest.xml** with the `tools:node="replace"` attribute as follows: `<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="replace"/>`.
7272

7373
## HOW TO
7474

@@ -100,25 +100,23 @@ Declare the `WRITE_EXTERNAL_STORAGE` permission manually in your [**Plugins/Andr
100100
`NativeFilePicker.ExportMultipleFiles( string[] filePaths, FilesExportedCallback callback = null )`: prompts the user to export one or more files.
101101
- Exporting multiple files is only available on *Android 21+* and *iOS 11+*. Call *CanExportMultipleFiles()* to see if this feature is available
102102

103-
All of these functions return a *NativeFilePicker.Permission* value. More details about it is available below.
103+
All of these functions automatically call *NativeFilePicker.RequestPermissionAsync*. More details available below.
104104

105105
### C. Runtime Permissions
106106

107107
Beginning with *6.0 Marshmallow*, Android apps must request runtime permissions before accessing certain services. There are two functions to handle permissions with this plugin:
108108

109-
`NativeFilePicker.Permission NativeFilePicker.CheckPermission( bool readPermissionOnly = false )`: checks whether the app has access to the document providers or not.
109+
`bool NativeFilePicker.CheckPermission( bool readPermissionOnly = false )`: checks whether the app has access to the document providers or not.
110+
111+
`void NativeFilePicker.RequestPermissionAsync( PermissionCallback callback, bool readPermissionOnly = false )`: requests permission to access the document providers from the user and returns the result asynchronously. 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 PickFile/PickMultipleFiles and ExportFile/ExportMultipleFiles functions call RequestPermissionAsync internally and execute only if the permission is granted.
112+
- **PermissionCallback** takes `NativeFilePicker.Permission permission` parameter
110113

111114
**NativeFilePicker.Permission** is an enum that can take 3 values:
112115
- **Granted**: we have the permission to access the document providers
113-
- **ShouldAsk**: we don't have permission yet, but we can ask the user for permission via *RequestPermission* function (see below). As long as the user doesn't select "Don't ask again" while denying the permission, ShouldAsk is returned
116+
- **ShouldAsk**: permission is denied but we can ask the user for permission once again. As long as the user doesn't select "Don't ask again" while denying the permission, ShouldAsk is returned
114117
- **Denied**: we don't have permission and we can't ask the user for permission. In this case, user has to give the permission from Settings. This happens when user selects "Don't ask again" while denying the permission or when user is not allowed to give that permission (parental controls etc.)
115118

116-
`NativeFilePicker.Permission NativeFilePicker.RequestPermission( bool readPermissionOnly = false )`: requests permission to access the document providers 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 PickFile/PickMultipleFiles and ExportFile/ExportMultipleFiles functions call RequestPermission internally and execute only if the permission is granted (the result of RequestPermission is also returned).
117-
118-
`void NativeFilePicker.RequestPermissionAsync( PermissionCallback callback, bool readPermissionOnly = false )`: 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.
119-
- **PermissionCallback** takes `NativeFilePicker.Permission permission` parameter
120-
121-
`Task<NativeFilePicker.Permission> NativeFilePicker.RequestPermissionAsync( bool readPermissionOnly = false )`: Another asynchronous variant of *RequestPermission* (requires Unity 2018.4 or later).
119+
`Task<NativeFilePicker.Permission> NativeFilePicker.RequestPermissionAsync( bool readPermissionOnly = false )`: Task-based overload of *RequestPermissionAsync*.
122120

123121
`NativeFilePicker.OpenSettings()`: opens the settings for this app, from where the user can manually grant the *Storage* permission in case current permission state is *Permission.Denied*.
124122

@@ -164,15 +162,13 @@ void Update()
164162
if( Input.mousePosition.x < Screen.width / 3 )
165163
{
166164
// Pick a PDF file
167-
NativeFilePicker.Permission permission = NativeFilePicker.PickFile( ( path ) =>
165+
NativeFilePicker.PickFile( ( path ) =>
168166
{
169167
if( path == null )
170168
Debug.Log( "Operation cancelled" );
171169
else
172170
Debug.Log( "Picked file: " + path );
173171
}, new string[] { pdfFileType } );
174-
175-
Debug.Log( "Permission result: " + permission );
176172
}
177173
else if( Input.mousePosition.x < Screen.width * 2 / 3 )
178174
{
@@ -185,7 +181,7 @@ void Update()
185181
#endif
186182

187183
// Pick image(s) and/or video(s)
188-
NativeFilePicker.Permission permission = NativeFilePicker.PickMultipleFiles( ( paths ) =>
184+
NativeFilePicker.PickMultipleFiles( ( paths ) =>
189185
{
190186
if( paths == null )
191187
Debug.Log( "Operation cancelled" );
@@ -195,8 +191,6 @@ void Update()
195191
Debug.Log( "Picked file: " + paths[i] );
196192
}
197193
}, fileTypes );
198-
199-
Debug.Log( "Permission result: " + permission );
200194
}
201195
else
202196
{
@@ -205,18 +199,8 @@ void Update()
205199
File.WriteAllText( filePath, "Hello world!" );
206200

207201
// Export the file
208-
NativeFilePicker.Permission permission = NativeFilePicker.ExportFile( filePath, ( success ) => Debug.Log( "File exported: " + success ) );
209-
210-
Debug.Log( "Permission result: " + permission );
202+
NativeFilePicker.ExportFile( filePath, ( success ) => Debug.Log( "File exported: " + success ) );
211203
}
212204
}
213205
}
214-
215-
// Example code doesn't use this function but it is here for reference. It's recommended to ask for permissions manually using the
216-
// RequestPermissionAsync methods prior to calling NativeFilePicker functions
217-
private async void RequestPermissionAsynchronously( bool readPermissionOnly = false )
218-
{
219-
NativeFilePicker.Permission permission = await NativeFilePicker.RequestPermissionAsync( readPermissionOnly );
220-
Debug.Log( "Permission result: " + permission );
221-
}
222206
```
Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
11
#if UNITY_EDITOR || UNITY_ANDROID
2+
using System;
23
using UnityEngine;
34

45
namespace NativeFilePickerNamespace
56
{
67
public class FPCallbackHelper : MonoBehaviour
78
{
8-
private System.Action mainThreadAction = null;
9+
private bool autoDestroyWithCallback;
10+
private Action mainThreadAction = null;
911

10-
private void Awake()
12+
public static FPCallbackHelper Create( bool autoDestroyWithCallback )
1113
{
12-
DontDestroyOnLoad( gameObject );
14+
FPCallbackHelper result = new GameObject( "FPCallbackHelper" ).AddComponent<FPCallbackHelper>();
15+
result.autoDestroyWithCallback = autoDestroyWithCallback;
16+
DontDestroyOnLoad( result.gameObject );
17+
return result;
18+
}
19+
20+
public void CallOnMainThread( Action function )
21+
{
22+
lock( this )
23+
{
24+
mainThreadAction += function;
25+
}
1326
}
1427

1528
private void Update()
@@ -18,21 +31,22 @@ private void Update()
1831
{
1932
try
2033
{
21-
System.Action temp = mainThreadAction;
22-
mainThreadAction = null;
34+
Action temp;
35+
lock( this )
36+
{
37+
temp = mainThreadAction;
38+
mainThreadAction = null;
39+
}
40+
2341
temp();
2442
}
2543
finally
2644
{
27-
Destroy( gameObject );
45+
if( autoDestroyWithCallback )
46+
Destroy( gameObject );
2847
}
2948
}
3049
}
31-
32-
public void CallOnMainThread( System.Action function )
33-
{
34-
mainThreadAction = function;
35-
}
3650
}
3751
}
3852
#endif

Plugins/NativeFilePicker/Android/FPPermissionCallbackAndroid.cs

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,17 @@
11
#if UNITY_EDITOR || UNITY_ANDROID
2-
using System.Threading;
32
using UnityEngine;
43

54
namespace NativeFilePickerNamespace
65
{
76
public class FPPermissionCallbackAndroid : AndroidJavaProxy
8-
{
9-
private object threadLock;
10-
public int Result { get; private set; }
11-
12-
public FPPermissionCallbackAndroid( object threadLock ) : base( "com.yasirkula.unity.NativeFilePickerPermissionReceiver" )
13-
{
14-
Result = -1;
15-
this.threadLock = threadLock;
16-
}
17-
18-
[UnityEngine.Scripting.Preserve]
19-
public void OnPermissionResult( int result )
20-
{
21-
Result = result;
22-
23-
lock( threadLock )
24-
{
25-
Monitor.Pulse( threadLock );
26-
}
27-
}
28-
}
29-
30-
public class FPPermissionCallbackAsyncAndroid : AndroidJavaProxy
317
{
328
private readonly NativeFilePicker.PermissionCallback callback;
339
private readonly FPCallbackHelper callbackHelper;
3410

35-
public FPPermissionCallbackAsyncAndroid( NativeFilePicker.PermissionCallback callback ) : base( "com.yasirkula.unity.NativeFilePickerPermissionReceiver" )
11+
public FPPermissionCallbackAndroid( NativeFilePicker.PermissionCallback callback ) : base( "com.yasirkula.unity.NativeFilePickerPermissionReceiver" )
3612
{
3713
this.callback = callback;
38-
callbackHelper = new GameObject( "FPCallbackHelper" ).AddComponent<FPCallbackHelper>();
14+
callbackHelper = FPCallbackHelper.Create( true );
3915
}
4016

4117
[UnityEngine.Scripting.Preserve]

Plugins/NativeFilePicker/Android/FPResultCallbackAndroid.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public FPResultCallbackAndroid( NativeFilePicker.FilePickedCallback pickCallback
1717
this.pickCallbackMultiple = pickCallbackMultiple;
1818
this.exportCallback = exportCallback;
1919

20-
callbackHelper = new GameObject( "FPCallbackHelper" ).AddComponent<FPCallbackHelper>();
20+
callbackHelper = FPCallbackHelper.Create( true );
2121
}
2222

2323
[UnityEngine.Scripting.Preserve]
-34 Bytes
Binary file not shown.

Plugins/NativeFilePicker/Editor/NativeFilePickerPostProcessBuild.cs

Lines changed: 2 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ public void Save()
4747
File.WriteAllText( SAVE_PATH, JsonUtility.ToJson( this, true ) );
4848
}
4949

50-
#if UNITY_2018_3_OR_NEWER
5150
[SettingsProvider]
5251
public static SettingsProvider CreatePreferencesGUI()
5352
{
@@ -57,11 +56,7 @@ public static SettingsProvider CreatePreferencesGUI()
5756
keywords = new System.Collections.Generic.HashSet<string>() { "Native", "File", "Picker", "Android", "iOS" }
5857
};
5958
}
60-
#endif
6159

62-
#if !UNITY_2018_3_OR_NEWER
63-
[PreferenceItem( "Native File Picker" )]
64-
#endif
6560
public static void PreferencesGUI()
6661
{
6762
EditorGUI.BeginChangeCheck();
@@ -77,27 +72,6 @@ public static void PreferencesGUI()
7772
public class NativeFilePickerPostProcessBuild
7873
{
7974
#if UNITY_IOS
80-
#if !UNITY_2017_1_OR_NEWER
81-
private const string ICLOUD_ENTITLEMENTS = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
82-
"<!DOCTYPE plist PUBLIC \" -//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" +
83-
"<plist version=\"1.0\">" +
84-
"<dict>" +
85-
"<key>com.apple.developer.icloud-container-identifiers</key>" +
86-
"<array>" +
87-
"<string>iCloud.$(CFBundleIdentifier)</string>" +
88-
"</array>" +
89-
"<key>com.apple.developer.icloud-services</key>" +
90-
"<array>" +
91-
"<string>CloudDocuments</string>" +
92-
"</array>" +
93-
"<key>com.apple.developer.ubiquity-container-identifiers</key>" +
94-
"<array>" +
95-
"<string>iCloud.$(CFBundleIdentifier)</string>" +
96-
"</array>" +
97-
"</dict>" +
98-
"</plist>";
99-
#endif
100-
10175
#pragma warning disable 0162
10276
[PostProcessBuild]
10377
public static void OnPostprocessBuild( BuildTarget target, string buildPath )
@@ -152,48 +126,21 @@ public static void OnPostprocessBuild( BuildTarget target, string buildPath )
152126
PBXProject pbxProject = new PBXProject();
153127
pbxProject.ReadFromFile( pbxProjectPath );
154128

155-
#if UNITY_2019_3_OR_NEWER
156129
string targetGUID = pbxProject.GetUnityFrameworkTargetGuid();
157-
#else
158-
string targetGUID = pbxProject.TargetGuidByName( PBXProject.GetUnityTargetName() );
159-
#endif
160-
161130
if( Settings.Instance.AutoSetupFrameworks )
162131
{
163-
pbxProject.AddBuildProperty( targetGUID, "OTHER_LDFLAGS", "-framework MobileCoreServices" );
164-
pbxProject.AddBuildProperty( targetGUID, "OTHER_LDFLAGS", "-framework CloudKit" );
132+
pbxProject.AddFrameworkToProject( targetGUID, "MobileCoreServices.framework", false );
133+
pbxProject.AddFrameworkToProject( targetGUID, "CloudKit.framework", false );
165134
}
166135

167-
#if !UNITY_2017_1_OR_NEWER
168-
if( Settings.Instance.AutoSetupiCloud )
169-
{
170-
// Add iCloud capability without Cloud Build support on 5.6 or earlier
171-
string entitlementsPath = Path.Combine( buildPath, "iCloud.entitlements" );
172-
File.WriteAllText( entitlementsPath, ICLOUD_ENTITLEMENTS );
173-
pbxProject.AddFile( entitlementsPath, Path.GetFileName( entitlementsPath ) );
174-
pbxProject.AddBuildProperty( targetGUID, "CODE_SIGN_ENTITLEMENTS", entitlementsPath );
175-
}
176-
#endif
177-
178136
File.WriteAllText( pbxProjectPath, pbxProject.WriteToString() );
179137

180-
#if UNITY_2017_1_OR_NEWER
181138
if( Settings.Instance.AutoSetupiCloud )
182139
{
183-
// Add iCloud capability with Cloud Build support on 2017.1+
184-
#if UNITY_2019_3_OR_NEWER
185140
ProjectCapabilityManager manager = new ProjectCapabilityManager( pbxProjectPath, "iCloud.entitlements", "Unity-iPhone" );
186-
#else
187-
ProjectCapabilityManager manager = new ProjectCapabilityManager( pbxProjectPath, "iCloud.entitlements", PBXProject.GetUnityTargetName() );
188-
#endif
189-
#if UNITY_2018_3_OR_NEWER
190141
manager.AddiCloud( false, true, false, true, null );
191-
#else
192-
manager.AddiCloud( false, true, true, null );
193-
#endif
194142
manager.WriteToFile();
195143
}
196-
#endif
197144
}
198145
}
199146

@@ -211,18 +158,9 @@ public static void OnPostprocessBuild2( BuildTarget target, string buildPath )
211158
PBXProject pbxProject = new PBXProject();
212159
pbxProject.ReadFromFile( pbxProjectPath );
213160

214-
#if UNITY_2019_3_OR_NEWER
215161
string targetGUID = pbxProject.GetUnityFrameworkTargetGuid();
216-
#else
217-
string targetGUID = pbxProject.TargetGuidByName( PBXProject.GetUnityTargetName() );
218-
#endif
219-
220-
#if UNITY_2018_2_OR_NEWER
221162
if( string.IsNullOrEmpty( pbxProject.GetBuildPropertyForAnyConfig( targetGUID, "PRODUCT_BUNDLE_IDENTIFIER" ) ) )
222163
pbxProject.AddBuildProperty( targetGUID, "PRODUCT_BUNDLE_IDENTIFIER", PlayerSettings.applicationIdentifier );
223-
#else
224-
pbxProject.SetBuildProperty( targetGUID, "PRODUCT_BUNDLE_IDENTIFIER", PlayerSettings.applicationIdentifier );
225-
#endif
226164

227165
File.WriteAllText( pbxProjectPath, pbxProject.WriteToString() );
228166
}

0 commit comments

Comments
 (0)