Структуры
This commit is contained in:
1 parent
06b08f1efe
commit
1b578067f3
82 files changed
+2692
-944
No files matched your search
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fbefdb800f5c8e4468bf456469caaf61
|
||||
folderAsset: yes
|
||||
timeCreated: 1596983915
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5c273c78eb8ebb47a9c6005d4041d73
|
||||
folderAsset: yes
|
||||
timeCreated: 1596971200
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,52 @@
|
||||
#if UNITY_EDITOR || UNITY_ANDROID
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NativeFilePickerNamespace
|
||||
{
|
||||
public class FPCallbackHelper : MonoBehaviour
|
||||
{
|
||||
private bool autoDestroyWithCallback;
|
||||
private Action mainThreadAction = null;
|
||||
|
||||
public static FPCallbackHelper Create( bool autoDestroyWithCallback )
|
||||
{
|
||||
FPCallbackHelper result = new GameObject( "FPCallbackHelper" ).AddComponent<FPCallbackHelper>();
|
||||
result.autoDestroyWithCallback = autoDestroyWithCallback;
|
||||
DontDestroyOnLoad( result.gameObject );
|
||||
return result;
|
||||
}
|
||||
|
||||
public void CallOnMainThread( Action function )
|
||||
{
|
||||
lock( this )
|
||||
{
|
||||
mainThreadAction += function;
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if( mainThreadAction != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
Action temp;
|
||||
lock( this )
|
||||
{
|
||||
temp = mainThreadAction;
|
||||
mainThreadAction = null;
|
||||
}
|
||||
|
||||
temp();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if( autoDestroyWithCallback )
|
||||
Destroy( gameObject );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 41423473566db0b4ebd62882996f08bc
|
||||
timeCreated: 1596973837
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 173238
|
||||
packageName: Native File Picker for Android & iOS
|
||||
packageVersion: 1.4.1
|
||||
assetPath: Assets/Plugins/NativeFilePicker/Android/FPCallbackHelper.cs
|
||||
uploadId: 757770
|
||||
@@ -0,0 +1,24 @@
|
||||
#if UNITY_EDITOR || UNITY_ANDROID
|
||||
using UnityEngine;
|
||||
|
||||
namespace NativeFilePickerNamespace
|
||||
{
|
||||
public class FPPermissionCallbackAndroid : AndroidJavaProxy
|
||||
{
|
||||
private readonly NativeFilePicker.PermissionCallback callback;
|
||||
private readonly FPCallbackHelper callbackHelper;
|
||||
|
||||
public FPPermissionCallbackAndroid( NativeFilePicker.PermissionCallback callback ) : base( "com.yasirkula.unity.NativeFilePickerPermissionReceiver" )
|
||||
{
|
||||
this.callback = callback;
|
||||
callbackHelper = FPCallbackHelper.Create( true );
|
||||
}
|
||||
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public void OnPermissionResult( int result )
|
||||
{
|
||||
callbackHelper.CallOnMainThread( () => callback( (NativeFilePicker.Permission) result ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f8c2de0178a90140b030975551436a5
|
||||
timeCreated: 1596973837
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 173238
|
||||
packageName: Native File Picker for Android & iOS
|
||||
packageVersion: 1.4.1
|
||||
assetPath: Assets/Plugins/NativeFilePicker/Android/FPPermissionCallbackAndroid.cs
|
||||
uploadId: 757770
|
||||
@@ -0,0 +1,71 @@
|
||||
#if UNITY_EDITOR || UNITY_ANDROID
|
||||
using UnityEngine;
|
||||
|
||||
namespace NativeFilePickerNamespace
|
||||
{
|
||||
public class FPResultCallbackAndroid : AndroidJavaProxy
|
||||
{
|
||||
private readonly NativeFilePicker.FilePickedCallback pickCallback;
|
||||
private readonly NativeFilePicker.MultipleFilesPickedCallback pickCallbackMultiple;
|
||||
private readonly NativeFilePicker.FilesExportedCallback exportCallback;
|
||||
|
||||
private readonly FPCallbackHelper callbackHelper;
|
||||
|
||||
public FPResultCallbackAndroid( NativeFilePicker.FilePickedCallback pickCallback, NativeFilePicker.MultipleFilesPickedCallback pickCallbackMultiple, NativeFilePicker.FilesExportedCallback exportCallback ) : base( "com.yasirkula.unity.NativeFilePickerResultReceiver" )
|
||||
{
|
||||
this.pickCallback = pickCallback;
|
||||
this.pickCallbackMultiple = pickCallbackMultiple;
|
||||
this.exportCallback = exportCallback;
|
||||
|
||||
callbackHelper = FPCallbackHelper.Create( true );
|
||||
}
|
||||
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public void OnFilePicked( string path )
|
||||
{
|
||||
callbackHelper.CallOnMainThread( () => pickCallback( !string.IsNullOrEmpty( path ) ? path : null ) );
|
||||
}
|
||||
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public void OnMultipleFilesPicked( string paths )
|
||||
{
|
||||
string[] result = null;
|
||||
if( !string.IsNullOrEmpty( paths ) )
|
||||
{
|
||||
string[] pathsSplit = paths.Split( '>' );
|
||||
|
||||
int validPathCount = 0;
|
||||
for( int i = 0; i < pathsSplit.Length; i++ )
|
||||
{
|
||||
if( !string.IsNullOrEmpty( pathsSplit[i] ) )
|
||||
validPathCount++;
|
||||
}
|
||||
|
||||
if( validPathCount == 0 )
|
||||
pathsSplit = new string[0];
|
||||
else if( validPathCount != pathsSplit.Length )
|
||||
{
|
||||
string[] validPaths = new string[validPathCount];
|
||||
for( int i = 0, j = 0; i < pathsSplit.Length; i++ )
|
||||
{
|
||||
if( !string.IsNullOrEmpty( pathsSplit[i] ) )
|
||||
validPaths[j++] = pathsSplit[i];
|
||||
}
|
||||
|
||||
pathsSplit = validPaths;
|
||||
}
|
||||
|
||||
result = pathsSplit;
|
||||
}
|
||||
|
||||
callbackHelper.CallOnMainThread( () => pickCallbackMultiple( ( result != null && result.Length > 0 ) ? result : null ) );
|
||||
}
|
||||
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public void OnFilesExported( bool result )
|
||||
{
|
||||
callbackHelper.CallOnMainThread( () => exportCallback( result ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f43d316f7eb1cdf4abcf327a1fbc025b
|
||||
timeCreated: 1596973837
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 173238
|
||||
packageName: Native File Picker for Android & iOS
|
||||
packageVersion: 1.4.1
|
||||
assetPath: Assets/Plugins/NativeFilePicker/Android/FPResultCallbackAndroid.cs
|
||||
uploadId: 757770
|
||||
Binary file not shown.
@@ -0,0 +1,40 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ed817dcf924721488f9672995f51cb3
|
||||
timeCreated: 1607368610
|
||||
licenseType: Store
|
||||
PluginImporter:
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
platformData:
|
||||
data:
|
||||
first:
|
||||
Android: Android
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
data:
|
||||
first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
data:
|
||||
first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 173238
|
||||
packageName: Native File Picker for Android & iOS
|
||||
packageVersion: 1.4.1
|
||||
assetPath: Assets/Plugins/NativeFilePicker/Android/NativeFilePicker.aar
|
||||
uploadId: 757770
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f387670006405804d9b5c216ebd8ab1f
|
||||
folderAsset: yes
|
||||
timeCreated: 1521452097
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "NativeFilePicker.Editor",
|
||||
"references": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31a0463be93a160428f78ae484a99f5b
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 173238
|
||||
packageName: Native File Picker for Android & iOS
|
||||
packageVersion: 1.4.1
|
||||
assetPath: Assets/Plugins/NativeFilePicker/Editor/NativeFilePicker.Editor.asmdef
|
||||
uploadId: 757770
|
||||
@@ -0,0 +1,65 @@
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NativeFilePickerNamespace
|
||||
{
|
||||
[HelpURL( "https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/understanding_utis/understand_utis_declare/understand_utis_declare.html" )]
|
||||
public class NativeFilePickerCustomTypes : ScriptableObject
|
||||
{
|
||||
[System.Serializable]
|
||||
public class TypeHolder
|
||||
{
|
||||
[Tooltip( "A unique identifier for the type (UTI) (e.g. com.mycompany.mydata)" )]
|
||||
public string identifier;
|
||||
[Tooltip( "Description of the type (e.g. Save data for My App)" )]
|
||||
public string description;
|
||||
[Tooltip( "If this type is owned by your app (i.e. exclusive to your app), set this value to true. If another app generates files of this type and your app is merely importing/modifying them, set this value to false." )]
|
||||
public bool isExported;
|
||||
[Tooltip( "Which official UTI(s) is this type part of (e.g. public.data for generic types or public.image for image types)\nFull list available at: https://developer.apple.com/library/archive/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html" )]
|
||||
public string[] conformsTo;
|
||||
[Tooltip( "Extension(s) associated with this type (don't include the period; i.e. use myextension instead of .myextension)" )]
|
||||
public string[] extensions;
|
||||
}
|
||||
|
||||
private const string INITIAL_SAVE_PATH = "Assets/Plugins/NativeFilePicker/NativeFilePickerCustomTypes.asset";
|
||||
|
||||
#pragma warning disable 0649
|
||||
[SerializeField]
|
||||
private TypeHolder[] customTypes;
|
||||
#pragma warning restore 0649
|
||||
|
||||
[MenuItem( "Window/NativeFilePicker Custom Types" )]
|
||||
private static void InspectCustomTypes()
|
||||
{
|
||||
Selection.activeObject = GetInstance( true );
|
||||
}
|
||||
|
||||
private static NativeFilePickerCustomTypes GetInstance( bool createIfNotExists )
|
||||
{
|
||||
NativeFilePickerCustomTypes instance = null;
|
||||
string[] instances = AssetDatabase.FindAssets( "t:NativeFilePickerCustomTypes" );
|
||||
if( instances != null && instances.Length > 0 )
|
||||
instance = AssetDatabase.LoadAssetAtPath<NativeFilePickerCustomTypes>( AssetDatabase.GUIDToAssetPath( instances[0] ) );
|
||||
|
||||
if( !instance && createIfNotExists )
|
||||
{
|
||||
Directory.CreateDirectory( Path.GetDirectoryName( INITIAL_SAVE_PATH ) );
|
||||
|
||||
AssetDatabase.CreateAsset( CreateInstance<NativeFilePickerCustomTypes>(), INITIAL_SAVE_PATH );
|
||||
AssetDatabase.SaveAssets();
|
||||
instance = AssetDatabase.LoadAssetAtPath<NativeFilePickerCustomTypes>( INITIAL_SAVE_PATH );
|
||||
|
||||
Debug.Log( "Created NativeFilePickerCustomTypes file at " + INITIAL_SAVE_PATH + ". You can move this file around freely.", instance );
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static TypeHolder[] GetCustomTypes()
|
||||
{
|
||||
NativeFilePickerCustomTypes instance = GetInstance( false );
|
||||
return instance ? instance.customTypes : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f281670325986984c95fde82c23195e0
|
||||
timeCreated: 1592237398
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 173238
|
||||
packageName: Native File Picker for Android & iOS
|
||||
packageVersion: 1.4.1
|
||||
assetPath: Assets/Plugins/NativeFilePicker/Editor/NativeFilePickerCustomTypes.cs
|
||||
uploadId: 757770
|
||||
@@ -0,0 +1,199 @@
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
#if UNITY_IOS
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Callbacks;
|
||||
using UnityEditor.iOS.Xcode;
|
||||
#endif
|
||||
|
||||
namespace NativeFilePickerNamespace
|
||||
{
|
||||
[System.Serializable]
|
||||
public class Settings
|
||||
{
|
||||
private const string SAVE_PATH = "ProjectSettings/NativeFilePicker.json";
|
||||
|
||||
public bool AutoSetupFrameworks = true;
|
||||
public bool AutoSetupiCloud = false;
|
||||
|
||||
private static Settings m_instance = null;
|
||||
public static Settings Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if( m_instance == null )
|
||||
{
|
||||
try
|
||||
{
|
||||
if( File.Exists( SAVE_PATH ) )
|
||||
m_instance = JsonUtility.FromJson<Settings>( File.ReadAllText( SAVE_PATH ) );
|
||||
else
|
||||
m_instance = new Settings();
|
||||
}
|
||||
catch( System.Exception e )
|
||||
{
|
||||
Debug.LogException( e );
|
||||
m_instance = new Settings();
|
||||
}
|
||||
}
|
||||
|
||||
return m_instance;
|
||||
}
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
File.WriteAllText( SAVE_PATH, JsonUtility.ToJson( this, true ) );
|
||||
}
|
||||
|
||||
[SettingsProvider]
|
||||
public static SettingsProvider CreatePreferencesGUI()
|
||||
{
|
||||
return new SettingsProvider( "Project/yasirkula/Native File Picker", SettingsScope.Project )
|
||||
{
|
||||
guiHandler = ( searchContext ) => PreferencesGUI(),
|
||||
keywords = new System.Collections.Generic.HashSet<string>() { "Native", "File", "Picker", "Android", "iOS" }
|
||||
};
|
||||
}
|
||||
|
||||
public static void PreferencesGUI()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
Instance.AutoSetupFrameworks = EditorGUILayout.Toggle( new GUIContent( "Auto Setup Frameworks", "Automatically adds MobileCoreServices and CloudKit frameworks to the generated Xcode project" ), Instance.AutoSetupFrameworks );
|
||||
Instance.AutoSetupiCloud = EditorGUILayout.Toggle( new GUIContent( "Auto Setup iCloud", "Automatically enables iCloud capability of the generated Xcode project" ), Instance.AutoSetupiCloud );
|
||||
|
||||
if( EditorGUI.EndChangeCheck() )
|
||||
Instance.Save();
|
||||
}
|
||||
}
|
||||
|
||||
public class NativeFilePickerPostProcessBuild
|
||||
{
|
||||
#if UNITY_IOS
|
||||
#pragma warning disable 0162
|
||||
[PostProcessBuild]
|
||||
public static void OnPostprocessBuild( BuildTarget target, string buildPath )
|
||||
{
|
||||
// Add declared custom types to Info.plist
|
||||
if( target == BuildTarget.iOS )
|
||||
{
|
||||
NativeFilePickerCustomTypes.TypeHolder[] customTypes = NativeFilePickerCustomTypes.GetCustomTypes();
|
||||
if( customTypes != null )
|
||||
{
|
||||
string plistPath = Path.Combine( buildPath, "Info.plist" );
|
||||
|
||||
PlistDocument plist = new PlistDocument();
|
||||
plist.ReadFromString( File.ReadAllText( plistPath ) );
|
||||
|
||||
PlistElementDict rootDict = plist.root;
|
||||
|
||||
for( int i = 0; i < customTypes.Length; i++ )
|
||||
{
|
||||
NativeFilePickerCustomTypes.TypeHolder customType = customTypes[i];
|
||||
PlistElementArray customTypesArray = GetCustomTypesArray( rootDict, customType.isExported );
|
||||
|
||||
// Don't allow duplicate entries
|
||||
RemoveCustomTypeIfExists( customTypesArray, customType.identifier );
|
||||
|
||||
PlistElementDict customTypeDict = customTypesArray.AddDict();
|
||||
customTypeDict.SetString( "UTTypeIdentifier", customType.identifier );
|
||||
customTypeDict.SetString( "UTTypeDescription", customType.description );
|
||||
|
||||
PlistElementArray conformsTo = customTypeDict.CreateArray( "UTTypeConformsTo" );
|
||||
for( int j = 0; j < customType.conformsTo.Length; j++ )
|
||||
conformsTo.AddString( customType.conformsTo[j] );
|
||||
|
||||
PlistElementDict tagSpecification = customTypeDict.CreateDict( "UTTypeTagSpecification" );
|
||||
PlistElementArray tagExtensions = tagSpecification.CreateArray( "public.filename-extension" );
|
||||
for( int j = 0; j < customType.extensions.Length; j++ )
|
||||
tagExtensions.AddString( customType.extensions[j] );
|
||||
}
|
||||
|
||||
File.WriteAllText( plistPath, plist.WriteToString() );
|
||||
}
|
||||
}
|
||||
|
||||
// Rest of the function shouldn't execute unless build post-processing is enabled
|
||||
if( !Settings.Instance.AutoSetupFrameworks && !Settings.Instance.AutoSetupiCloud )
|
||||
return;
|
||||
|
||||
if( target == BuildTarget.iOS )
|
||||
{
|
||||
string pbxProjectPath = PBXProject.GetPBXProjectPath( buildPath );
|
||||
|
||||
PBXProject pbxProject = new PBXProject();
|
||||
pbxProject.ReadFromFile( pbxProjectPath );
|
||||
|
||||
string targetGUID = pbxProject.GetUnityFrameworkTargetGuid();
|
||||
if( Settings.Instance.AutoSetupFrameworks )
|
||||
{
|
||||
pbxProject.AddFrameworkToProject( targetGUID, "MobileCoreServices.framework", false );
|
||||
pbxProject.AddFrameworkToProject( targetGUID, "CloudKit.framework", false );
|
||||
}
|
||||
|
||||
File.WriteAllText( pbxProjectPath, pbxProject.WriteToString() );
|
||||
|
||||
if( Settings.Instance.AutoSetupiCloud )
|
||||
{
|
||||
ProjectCapabilityManager manager = new ProjectCapabilityManager( pbxProjectPath, "iCloud.entitlements", "Unity-iPhone" );
|
||||
manager.AddiCloud( false, true, false, true, null );
|
||||
manager.WriteToFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adding PRODUCT_BUNDLE_IDENTIFIER if not exists (if another plugin also fills this value, we must not touch it)
|
||||
[PostProcessBuild( 99 )]
|
||||
public static void OnPostprocessBuild2( BuildTarget target, string buildPath )
|
||||
{
|
||||
if( !Settings.Instance.AutoSetupFrameworks && !Settings.Instance.AutoSetupiCloud )
|
||||
return;
|
||||
|
||||
if( target == BuildTarget.iOS )
|
||||
{
|
||||
string pbxProjectPath = PBXProject.GetPBXProjectPath( buildPath );
|
||||
|
||||
PBXProject pbxProject = new PBXProject();
|
||||
pbxProject.ReadFromFile( pbxProjectPath );
|
||||
|
||||
string targetGUID = pbxProject.GetUnityFrameworkTargetGuid();
|
||||
if( string.IsNullOrEmpty( pbxProject.GetBuildPropertyForAnyConfig( targetGUID, "PRODUCT_BUNDLE_IDENTIFIER" ) ) )
|
||||
pbxProject.AddBuildProperty( targetGUID, "PRODUCT_BUNDLE_IDENTIFIER", PlayerSettings.applicationIdentifier );
|
||||
|
||||
File.WriteAllText( pbxProjectPath, pbxProject.WriteToString() );
|
||||
}
|
||||
}
|
||||
|
||||
private static PlistElementArray GetCustomTypesArray( PlistElementDict rootDict, bool isExported )
|
||||
{
|
||||
string key = isExported ? "UTExportedTypeDeclarations" : "UTImportedTypeDeclarations";
|
||||
PlistElementArray result = rootDict[key] as PlistElementArray;
|
||||
if( result == null )
|
||||
result = rootDict.CreateArray( key );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void RemoveCustomTypeIfExists( PlistElementArray customTypesArray, string UTI )
|
||||
{
|
||||
List<PlistElement> values = customTypesArray.values;
|
||||
if( values == null )
|
||||
return;
|
||||
|
||||
for( int i = values.Count - 1; i >= 0; i-- )
|
||||
{
|
||||
PlistElementDict exportedType = values[i] as PlistElementDict;
|
||||
if( exportedType != null )
|
||||
{
|
||||
PlistElementString exportedTypeID = exportedType["UTTypeIdentifier"] as PlistElementString;
|
||||
if( exportedTypeID != null && exportedTypeID.value == UTI )
|
||||
values.RemoveAt( i );
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore 0162
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d466ecf51c239f9419715f6b59348d6c
|
||||
timeCreated: 1521452119
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 173238
|
||||
packageName: Native File Picker for Android & iOS
|
||||
packageVersion: 1.4.1
|
||||
assetPath: Assets/Plugins/NativeFilePicker/Editor/NativeFilePickerPostProcessBuild.cs
|
||||
uploadId: 757770
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"name": "NativeFilePicker.Runtime"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 250e096504da3aa4f851a4df12262950
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 173238
|
||||
packageName: Native File Picker for Android & iOS
|
||||
packageVersion: 1.4.1
|
||||
assetPath: Assets/Plugins/NativeFilePicker/NativeFilePicker.Runtime.asmdef
|
||||
uploadId: 757770
|
||||
@@ -0,0 +1,411 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using System.Threading.Tasks;
|
||||
#if UNITY_ANDROID || UNITY_IOS
|
||||
using NativeFilePickerNamespace;
|
||||
#endif
|
||||
|
||||
public static class NativeFilePicker
|
||||
{
|
||||
public delegate void PermissionCallback( Permission permission );
|
||||
public delegate void FilePickedCallback( string path );
|
||||
public delegate void MultipleFilesPickedCallback( string[] paths );
|
||||
public delegate void FilesExportedCallback( bool success );
|
||||
|
||||
public enum Permission { Denied = 0, Granted = 1, ShouldAsk = 2 };
|
||||
|
||||
#region Platform Specific Elements
|
||||
#if !UNITY_EDITOR && UNITY_ANDROID
|
||||
private static AndroidJavaClass m_ajc = null;
|
||||
private static AndroidJavaClass AJC
|
||||
{
|
||||
get
|
||||
{
|
||||
if( m_ajc == null )
|
||||
m_ajc = new AndroidJavaClass( "com.yasirkula.unity.NativeFilePicker" );
|
||||
|
||||
return m_ajc;
|
||||
}
|
||||
}
|
||||
|
||||
private static AndroidJavaObject m_context = null;
|
||||
private static AndroidJavaObject Context
|
||||
{
|
||||
get
|
||||
{
|
||||
if( m_context == null )
|
||||
{
|
||||
using( AndroidJavaObject unityClass = new AndroidJavaClass( "com.unity3d.player.UnityPlayer" ) )
|
||||
{
|
||||
m_context = unityClass.GetStatic<AndroidJavaObject>( "currentActivity" );
|
||||
}
|
||||
}
|
||||
|
||||
return m_context;
|
||||
}
|
||||
}
|
||||
#elif !UNITY_EDITOR && UNITY_IOS
|
||||
[System.Runtime.InteropServices.DllImport( "__Internal" )]
|
||||
private static extern int _NativeFilePicker_CanPickMultipleFiles();
|
||||
|
||||
[System.Runtime.InteropServices.DllImport( "__Internal" )]
|
||||
private static extern string _NativeFilePicker_ConvertExtensionToUTI( string extension );
|
||||
|
||||
[System.Runtime.InteropServices.DllImport( "__Internal" )]
|
||||
private static extern void _NativeFilePicker_PickFile( string[] UTIs, int UTIsCount );
|
||||
|
||||
[System.Runtime.InteropServices.DllImport( "__Internal" )]
|
||||
private static extern void _NativeFilePicker_PickMultipleFiles( string[] UTIs, int UTIsCount );
|
||||
|
||||
[System.Runtime.InteropServices.DllImport( "__Internal" )]
|
||||
private static extern void _NativeFilePicker_ExportFiles( string[] files, int filesCount );
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#if !UNITY_EDITOR && UNITY_ANDROID
|
||||
private static string m_selectedFilePath = null;
|
||||
private static string SelectedFilePath
|
||||
{
|
||||
get
|
||||
{
|
||||
if( m_selectedFilePath == null )
|
||||
{
|
||||
m_selectedFilePath = Path.Combine( Application.temporaryCachePath, "pickedFile" );
|
||||
Directory.CreateDirectory( Application.temporaryCachePath );
|
||||
}
|
||||
|
||||
return m_selectedFilePath;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#region Runtime Permissions
|
||||
public static bool CheckPermission( bool readPermissionOnly = false )
|
||||
{
|
||||
#if !UNITY_EDITOR && UNITY_ANDROID
|
||||
return AJC.CallStatic<int>( "CheckPermission", Context, readPermissionOnly ) == 1;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void RequestPermissionAsync( PermissionCallback callback, bool readPermissionOnly = false )
|
||||
{
|
||||
#if !UNITY_EDITOR && UNITY_ANDROID
|
||||
FPPermissionCallbackAndroid nativeCallback = new( callback );
|
||||
AJC.CallStatic( "RequestPermission", Context, nativeCallback, readPermissionOnly );
|
||||
#else
|
||||
callback( Permission.Granted );
|
||||
#endif
|
||||
}
|
||||
|
||||
public static Task<Permission> RequestPermissionAsync( bool readPermissionOnly = false )
|
||||
{
|
||||
TaskCompletionSource<Permission> tcs = new TaskCompletionSource<Permission>();
|
||||
RequestPermissionAsync( ( permission ) => tcs.SetResult( permission ), readPermissionOnly );
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
public static void OpenSettings()
|
||||
{
|
||||
#if !UNITY_EDITOR && UNITY_ANDROID
|
||||
AJC.CallStatic( "OpenSettings", Context );
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Helper Functions
|
||||
public static bool CanPickMultipleFiles()
|
||||
{
|
||||
#if !UNITY_EDITOR && UNITY_ANDROID
|
||||
return AJC.CallStatic<bool>( "CanPickMultipleFiles" );
|
||||
#elif !UNITY_EDITOR && UNITY_IOS
|
||||
return _NativeFilePicker_CanPickMultipleFiles() == 1;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool CanExportFiles()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
return true;
|
||||
#elif UNITY_ANDROID
|
||||
return AJC.CallStatic<bool>( "CanExportFiles" );
|
||||
#elif UNITY_IOS
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool CanExportMultipleFiles()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
return true;
|
||||
#elif UNITY_ANDROID
|
||||
return AJC.CallStatic<bool>( "CanExportMultipleFiles" );
|
||||
#elif UNITY_IOS
|
||||
return _NativeFilePicker_CanPickMultipleFiles() == 1;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool IsFilePickerBusy()
|
||||
{
|
||||
#if !UNITY_EDITOR && UNITY_IOS
|
||||
return FPResultCallbackiOS.IsBusy;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static string ConvertExtensionToFileType( string extension )
|
||||
{
|
||||
if( string.IsNullOrEmpty( extension ) )
|
||||
return null;
|
||||
|
||||
if( extension.IndexOf( '*' ) >= 0 )
|
||||
{
|
||||
// So many users try to do this that it's now necessary to throw an exception for this particular scenario
|
||||
throw new ArgumentException( "See: https://github.com/yasirkula/UnityNativeFilePicker#faq" );
|
||||
}
|
||||
|
||||
#if !UNITY_EDITOR && UNITY_ANDROID
|
||||
return AJC.CallStatic<string>( "GetMimeTypeFromExtension", extension.ToLowerInvariant() );
|
||||
#elif !UNITY_EDITOR && UNITY_IOS
|
||||
return _NativeFilePicker_ConvertExtensionToUTI( extension.ToLowerInvariant() );
|
||||
#else
|
||||
return extension;
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Import Functions
|
||||
public static void PickFile( FilePickedCallback callback, params string[] allowedFileTypes )
|
||||
{
|
||||
// If no file type is specified, allow all file types
|
||||
if( allowedFileTypes == null || allowedFileTypes.Length == 0 )
|
||||
{
|
||||
#if UNITY_ANDROID
|
||||
allowedFileTypes = new string[] { "*/*" };
|
||||
#else
|
||||
allowedFileTypes = new string[] { "public.item", "public.content" };
|
||||
#endif
|
||||
}
|
||||
|
||||
RequestPermissionAsync( ( permission ) =>
|
||||
{
|
||||
if( permission != Permission.Granted || IsFilePickerBusy() )
|
||||
{
|
||||
callback?.Invoke( null );
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Accept Android and iOS UTIs when possible, for user's convenience
|
||||
string[] editorFilters = new string[allowedFileTypes.Length * 2];
|
||||
for( int i = 0; i < allowedFileTypes.Length; i++ )
|
||||
{
|
||||
if( allowedFileTypes[i].IndexOf( '*' ) >= 0 )
|
||||
{
|
||||
if( allowedFileTypes[i] == "image/*" )
|
||||
{
|
||||
editorFilters[i * 2] = "Image files";
|
||||
editorFilters[i * 2 + 1] = "png,jpg,jpeg";
|
||||
}
|
||||
else if( allowedFileTypes[i] == "video/*" )
|
||||
{
|
||||
editorFilters[i * 2] = "Video files";
|
||||
editorFilters[i * 2 + 1] = "mp4,mov,webm,avi";
|
||||
}
|
||||
else if( allowedFileTypes[i] == "audio/*" )
|
||||
{
|
||||
editorFilters[i * 2] = "Audio files";
|
||||
editorFilters[i * 2 + 1] = "mp3,wav,aac,flac";
|
||||
}
|
||||
else
|
||||
{
|
||||
editorFilters[i * 2] = "All files";
|
||||
editorFilters[i * 2 + 1] = "*";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
editorFilters[i * 2] = allowedFileTypes[i];
|
||||
|
||||
if( allowedFileTypes[i].IndexOf( '/' ) >= 0 ) // Android UTIs like 'image/png'
|
||||
editorFilters[i * 2 + 1] = allowedFileTypes[i].Substring( allowedFileTypes[i].IndexOf( '/' ) + 1 );
|
||||
else if( allowedFileTypes[i].StartsWith( "public." ) ) // iOS UTIs like 'public.png'
|
||||
editorFilters[i * 2 + 1] = allowedFileTypes[i].Substring( 7 );
|
||||
else if( allowedFileTypes[i].IndexOf( '.' ) == 0 ) // Extensions starting with period like '.png'
|
||||
editorFilters[i * 2 + 1] = allowedFileTypes[i].Substring( 1 );
|
||||
else
|
||||
editorFilters[i * 2 + 1] = allowedFileTypes[i];
|
||||
}
|
||||
}
|
||||
|
||||
string pickedFile = UnityEditor.EditorUtility.OpenFilePanelWithFilters( "Select file", "", editorFilters );
|
||||
|
||||
if( callback != null )
|
||||
callback( pickedFile != "" ? pickedFile : null );
|
||||
#elif UNITY_ANDROID
|
||||
AJC.CallStatic( "PickFiles", Context, new FPResultCallbackAndroid( callback, null, null ), false, SelectedFilePath, allowedFileTypes, "" );
|
||||
#elif UNITY_IOS
|
||||
FPResultCallbackiOS.Initialize( callback, null, null );
|
||||
_NativeFilePicker_PickFile( allowedFileTypes, allowedFileTypes.Length );
|
||||
#else
|
||||
if( callback != null )
|
||||
callback( null );
|
||||
#endif
|
||||
}, true );
|
||||
}
|
||||
|
||||
public static void PickMultipleFiles( MultipleFilesPickedCallback callback, params string[] allowedFileTypes )
|
||||
{
|
||||
// If no file type is specified, allow all file types
|
||||
if( allowedFileTypes == null || allowedFileTypes.Length == 0 )
|
||||
{
|
||||
#if UNITY_ANDROID
|
||||
allowedFileTypes = new string[] { "*/*" };
|
||||
#else
|
||||
allowedFileTypes = new string[] { "public.item", "public.content" };
|
||||
#endif
|
||||
}
|
||||
|
||||
RequestPermissionAsync( ( permission ) =>
|
||||
{
|
||||
if( permission != Permission.Granted || IsFilePickerBusy() )
|
||||
{
|
||||
callback?.Invoke( null );
|
||||
return;
|
||||
}
|
||||
|
||||
if( CanPickMultipleFiles() )
|
||||
{
|
||||
#if !UNITY_EDITOR && UNITY_ANDROID
|
||||
AJC.CallStatic( "PickFiles", Context, new FPResultCallbackAndroid( null, callback, null ), true, SelectedFilePath, allowedFileTypes, "" );
|
||||
#elif !UNITY_EDITOR && UNITY_IOS
|
||||
FPResultCallbackiOS.Initialize( null, callback, null );
|
||||
_NativeFilePicker_PickMultipleFiles( allowedFileTypes, allowedFileTypes.Length );
|
||||
#endif
|
||||
}
|
||||
else if( callback != null )
|
||||
callback( null );
|
||||
}, true );
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Export Functions
|
||||
public static void ExportFile( string filePath, FilesExportedCallback callback = null )
|
||||
{
|
||||
if( string.IsNullOrEmpty( filePath ) )
|
||||
throw new ArgumentException( "Parameter 'filePath' is null or empty!" );
|
||||
|
||||
RequestPermissionAsync( ( permission ) =>
|
||||
{
|
||||
if( permission != Permission.Granted || IsFilePickerBusy() )
|
||||
{
|
||||
callback?.Invoke( false );
|
||||
return;
|
||||
}
|
||||
|
||||
if( CanExportFiles() )
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
string extension = Path.GetExtension( filePath );
|
||||
if( extension == null )
|
||||
extension = "";
|
||||
else if( extension.IndexOf( '.' ) == 0 )
|
||||
extension = extension.Substring( 1 );
|
||||
|
||||
string destination = UnityEditor.EditorUtility.SaveFilePanel( "Select destination", Path.GetDirectoryName( filePath ), Path.GetFileName( filePath ), extension );
|
||||
if( string.IsNullOrEmpty( destination ) )
|
||||
{
|
||||
if( callback != null )
|
||||
callback( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Copy( filePath, destination, true );
|
||||
|
||||
if( callback != null )
|
||||
callback( true );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
Debug.LogException( e );
|
||||
|
||||
if( callback != null )
|
||||
callback( false );
|
||||
}
|
||||
}
|
||||
#elif UNITY_ANDROID
|
||||
AJC.CallStatic( "ExportFiles", Context, new FPResultCallbackAndroid( null, null, callback ), new string[1] { filePath }, 1 );
|
||||
#elif UNITY_IOS
|
||||
FPResultCallbackiOS.Initialize( null, null, callback );
|
||||
_NativeFilePicker_ExportFiles( new string[1] { filePath }, 1 );
|
||||
#endif
|
||||
}
|
||||
else if( callback != null )
|
||||
callback( false );
|
||||
}, false );
|
||||
}
|
||||
|
||||
public static void ExportMultipleFiles( string[] filePaths, FilesExportedCallback callback = null )
|
||||
{
|
||||
if( filePaths == null || filePaths.Length == 0 )
|
||||
throw new ArgumentException( "Parameter 'filePaths' is null or empty!" );
|
||||
|
||||
RequestPermissionAsync( ( permission ) =>
|
||||
{
|
||||
if( permission != Permission.Granted || IsFilePickerBusy() )
|
||||
{
|
||||
callback?.Invoke( false );
|
||||
return;
|
||||
}
|
||||
|
||||
if( CanExportMultipleFiles() )
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
string destination = UnityEditor.EditorUtility.OpenFolderPanel( "Select destination", Path.GetDirectoryName( filePaths[0] ), "" );
|
||||
if( string.IsNullOrEmpty( destination ) )
|
||||
{
|
||||
if( callback != null )
|
||||
callback( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
for( int i = 0; i < filePaths.Length; i++ )
|
||||
File.Copy( filePaths[i], Path.Combine( destination, Path.GetFileName( filePaths[i] ) ), true );
|
||||
|
||||
if( callback != null )
|
||||
callback( true );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
Debug.LogException( e );
|
||||
|
||||
if( callback != null )
|
||||
callback( false );
|
||||
}
|
||||
}
|
||||
#elif UNITY_ANDROID
|
||||
AJC.CallStatic( "ExportFiles", Context, new FPResultCallbackAndroid( null, null, callback ), filePaths, filePaths.Length );
|
||||
#elif UNITY_IOS
|
||||
FPResultCallbackiOS.Initialize( null, null, callback );
|
||||
_NativeFilePicker_ExportFiles( filePaths, filePaths.Length );
|
||||
#endif
|
||||
}
|
||||
else if( callback != null )
|
||||
callback( false );
|
||||
}, false );
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ecdc359fc7b7e448a5aa6433eafcb8b
|
||||
timeCreated: 1498722610
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 173238
|
||||
packageName: Native File Picker for Android & iOS
|
||||
packageVersion: 1.4.1
|
||||
assetPath: Assets/Plugins/NativeFilePicker/NativeFilePicker.cs
|
||||
uploadId: 757770
|
||||
@@ -0,0 +1,6 @@
|
||||
= Native File Picker for Android & iOS (v1.4.1) =
|
||||
|
||||
Documentation: https://github.com/yasirkula/UnityNativeFilePicker
|
||||
FAQ: https://github.com/yasirkula/UnityNativeFilePicker#faq
|
||||
Example code: https://github.com/yasirkula/UnityNativeFilePicker#example-code
|
||||
E-mail: yasirkula@gmail.com
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a0357092d6d35434c8b136abfe2b6260
|
||||
timeCreated: 1563308465
|
||||
licenseType: Store
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 173238
|
||||
packageName: Native File Picker for Android & iOS
|
||||
packageVersion: 1.4.1
|
||||
assetPath: Assets/Plugins/NativeFilePicker/README.txt
|
||||
uploadId: 757770
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d99a20b76631e440a062e4fad822fc8
|
||||
folderAsset: yes
|
||||
timeCreated: 1592132993
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,155 @@
|
||||
#if UNITY_EDITOR || UNITY_IOS
|
||||
using UnityEngine;
|
||||
|
||||
namespace NativeFilePickerNamespace
|
||||
{
|
||||
public class FPResultCallbackiOS : MonoBehaviour
|
||||
{
|
||||
private static FPResultCallbackiOS instance;
|
||||
|
||||
private NativeFilePicker.FilePickedCallback pickCallback;
|
||||
private NativeFilePicker.MultipleFilesPickedCallback pickCallbackMultiple;
|
||||
private NativeFilePicker.FilesExportedCallback exportCallback;
|
||||
|
||||
private float nextBusyCheckTime;
|
||||
|
||||
public static bool IsBusy { get; private set; }
|
||||
|
||||
[System.Runtime.InteropServices.DllImport( "__Internal" )]
|
||||
private static extern int _NativeFilePicker_IsFilePickerBusy();
|
||||
|
||||
public static void Initialize( NativeFilePicker.FilePickedCallback pickCallback, NativeFilePicker.MultipleFilesPickedCallback pickCallbackMultiple, NativeFilePicker.FilesExportedCallback exportCallback )
|
||||
{
|
||||
if( IsBusy )
|
||||
return;
|
||||
|
||||
if( instance == null )
|
||||
{
|
||||
instance = new GameObject( "FPResultCallbackiOS" ).AddComponent<FPResultCallbackiOS>();
|
||||
DontDestroyOnLoad( instance.gameObject );
|
||||
}
|
||||
|
||||
instance.pickCallback = pickCallback;
|
||||
instance.pickCallbackMultiple = pickCallbackMultiple;
|
||||
instance.exportCallback = exportCallback;
|
||||
|
||||
instance.nextBusyCheckTime = Time.realtimeSinceStartup + 1f;
|
||||
IsBusy = true;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if( IsBusy )
|
||||
{
|
||||
if( Time.realtimeSinceStartup >= nextBusyCheckTime )
|
||||
{
|
||||
nextBusyCheckTime = Time.realtimeSinceStartup + 1f;
|
||||
|
||||
if( _NativeFilePicker_IsFilePickerBusy() == 0 )
|
||||
OnOperationCancelled( null );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public void OnFilePicked( string path )
|
||||
{
|
||||
IsBusy = false;
|
||||
|
||||
if( string.IsNullOrEmpty( path ) )
|
||||
path = null;
|
||||
|
||||
NativeFilePicker.FilePickedCallback _pickCallback = pickCallback;
|
||||
pickCallback = null;
|
||||
|
||||
if( _pickCallback != null )
|
||||
_pickCallback( path );
|
||||
}
|
||||
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public void OnMultipleFilesPicked( string paths )
|
||||
{
|
||||
IsBusy = false;
|
||||
|
||||
string[] _paths = SplitPaths( paths );
|
||||
if( _paths != null && _paths.Length == 0 )
|
||||
_paths = null;
|
||||
|
||||
NativeFilePicker.MultipleFilesPickedCallback _pickCallbackMultiple = pickCallbackMultiple;
|
||||
pickCallbackMultiple = null;
|
||||
|
||||
if( _pickCallbackMultiple != null )
|
||||
_pickCallbackMultiple( _paths );
|
||||
}
|
||||
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public void OnFilesExported( string message )
|
||||
{
|
||||
IsBusy = false;
|
||||
|
||||
NativeFilePicker.FilesExportedCallback _exportCallback = exportCallback;
|
||||
exportCallback = null;
|
||||
|
||||
if( _exportCallback != null )
|
||||
_exportCallback( message == "1" );
|
||||
}
|
||||
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public void OnOperationCancelled( string message )
|
||||
{
|
||||
IsBusy = false;
|
||||
|
||||
NativeFilePicker.FilePickedCallback _pickCallback = pickCallback;
|
||||
NativeFilePicker.MultipleFilesPickedCallback _pickCallbackMultiple = pickCallbackMultiple;
|
||||
NativeFilePicker.FilesExportedCallback _exportCallback = exportCallback;
|
||||
|
||||
pickCallback = null;
|
||||
pickCallbackMultiple = null;
|
||||
exportCallback = null;
|
||||
|
||||
if( _pickCallback != null )
|
||||
_pickCallback( null );
|
||||
|
||||
if( _pickCallbackMultiple != null )
|
||||
_pickCallbackMultiple( null );
|
||||
|
||||
if( _exportCallback != null )
|
||||
_exportCallback( false );
|
||||
}
|
||||
|
||||
private string[] SplitPaths( string paths )
|
||||
{
|
||||
string[] result = null;
|
||||
if( !string.IsNullOrEmpty( paths ) )
|
||||
{
|
||||
string[] pathsSplit = paths.Split( '>' );
|
||||
|
||||
int validPathCount = 0;
|
||||
for( int i = 0; i < pathsSplit.Length; i++ )
|
||||
{
|
||||
if( !string.IsNullOrEmpty( pathsSplit[i] ) )
|
||||
validPathCount++;
|
||||
}
|
||||
|
||||
if( validPathCount == 0 )
|
||||
pathsSplit = new string[0];
|
||||
else if( validPathCount != pathsSplit.Length )
|
||||
{
|
||||
string[] validPaths = new string[validPathCount];
|
||||
for( int i = 0, j = 0; i < pathsSplit.Length; i++ )
|
||||
{
|
||||
if( !string.IsNullOrEmpty( pathsSplit[i] ) )
|
||||
validPaths[j++] = pathsSplit[i];
|
||||
}
|
||||
|
||||
pathsSplit = validPaths;
|
||||
}
|
||||
|
||||
result = pathsSplit;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b11d2999e16ca864f8974988d73c2017
|
||||
timeCreated: 1519060539
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 173238
|
||||
packageName: Native File Picker for Android & iOS
|
||||
packageVersion: 1.4.1
|
||||
assetPath: Assets/Plugins/NativeFilePicker/iOS/FPResultCallbackiOS.cs
|
||||
uploadId: 757770
|
||||
@@ -0,0 +1,213 @@
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
|
||||
extern UIViewController* UnityGetGLViewController();
|
||||
|
||||
@interface UNativeFilePicker:NSObject
|
||||
+ (void)pickFiles:(BOOL)allowMultipleSelection withUTIs:(NSArray<NSString *> *)allowedUTIs;
|
||||
+ (void)exportFiles:(NSArray<NSURL *> *)paths;
|
||||
+ (int)canPickMultipleFiles;
|
||||
+ (int)isFilePickerBusy;
|
||||
+ (char *)convertExtensionToUTI:(NSString *)extension;
|
||||
@end
|
||||
|
||||
@implementation UNativeFilePicker
|
||||
|
||||
static UIDocumentPickerViewController *filePicker;
|
||||
static BOOL pickingMultipleFiles;
|
||||
static int filePickerState = 0; // 0 -> none, 1 -> showing, 2 -> finished
|
||||
|
||||
+ (void)pickFiles:(BOOL)allowMultipleSelection withUTIs:(NSArray<NSString *> *)allowedUTIs
|
||||
{
|
||||
filePicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:allowedUTIs inMode:UIDocumentPickerModeImport];
|
||||
filePicker.delegate = (id) self;
|
||||
|
||||
if( @available(iOS 11.0, *) )
|
||||
filePicker.allowsMultipleSelection = allowMultipleSelection;
|
||||
|
||||
// Show file extensions if possible
|
||||
if( @available(iOS 13.0, *) )
|
||||
filePicker.shouldShowFileExtensions = YES;
|
||||
|
||||
pickingMultipleFiles = allowMultipleSelection;
|
||||
filePickerState = 1;
|
||||
|
||||
[UnityGetGLViewController() presentViewController:filePicker animated:NO completion:^{ filePickerState = 0; }];
|
||||
}
|
||||
|
||||
+ (void)exportFiles:(NSArray<NSURL *> *)paths
|
||||
{
|
||||
if( paths != nil && [paths count] > 0 )
|
||||
{
|
||||
if ([paths count] > 1 && [self canPickMultipleFiles] == 1)
|
||||
filePicker = [[UIDocumentPickerViewController alloc] initWithURLs:paths inMode:UIDocumentPickerModeExportToService];
|
||||
else
|
||||
filePicker = [[UIDocumentPickerViewController alloc] initWithURL:paths[0] inMode:UIDocumentPickerModeExportToService];
|
||||
|
||||
filePicker.delegate = (id) self;
|
||||
|
||||
// Show file extensions if possible
|
||||
if( @available(iOS 13.0, *) )
|
||||
filePicker.shouldShowFileExtensions = YES;
|
||||
|
||||
filePickerState = 1;
|
||||
[UnityGetGLViewController() presentViewController:filePicker animated:NO completion:^{ filePickerState = 0; }];
|
||||
}
|
||||
}
|
||||
|
||||
+ (int)canPickMultipleFiles
|
||||
{
|
||||
if( @available(iOS 11.0, *) )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+ (int)isFilePickerBusy
|
||||
{
|
||||
if( filePickerState == 2 )
|
||||
return 1;
|
||||
|
||||
if( filePicker != nil )
|
||||
{
|
||||
if( filePickerState == 1 || [filePicker presentingViewController] == UnityGetGLViewController() )
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
filePicker = nil;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Credit: https://lists.apple.com/archives/cocoa-dev/2012/Jan/msg00052.html
|
||||
+ (char *)convertExtensionToUTI:(NSString *)extension
|
||||
{
|
||||
CFStringRef fileUTI = UTTypeCreatePreferredIdentifierForTag( kUTTagClassFilenameExtension, (__bridge CFStringRef) extension, NULL );
|
||||
char *result = [self getCString:(__bridge NSString *) fileUTI];
|
||||
CFRelease( fileUTI );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
+ (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url
|
||||
{
|
||||
[self documentPickerCompleted:controller documents:@[url]];
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
+ (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls
|
||||
{
|
||||
[self documentPickerCompleted:controller documents:urls];
|
||||
}
|
||||
|
||||
+ (void)documentPickerCompleted:(UIDocumentPickerViewController *)controller documents:(NSArray<NSURL *> *)urls
|
||||
{
|
||||
filePicker = nil;
|
||||
filePickerState = 2;
|
||||
|
||||
if( controller.documentPickerMode == UIDocumentPickerModeImport )
|
||||
{
|
||||
if( !pickingMultipleFiles || [urls count] <= 1 )
|
||||
{
|
||||
const char* filePath;
|
||||
if( [urls count] == 0 )
|
||||
filePath = "";
|
||||
else
|
||||
filePath = [self getCString:[urls[0] path]];
|
||||
|
||||
if( pickingMultipleFiles )
|
||||
UnitySendMessage( "FPResultCallbackiOS", "OnMultipleFilesPicked", filePath );
|
||||
else
|
||||
UnitySendMessage( "FPResultCallbackiOS", "OnFilePicked", filePath );
|
||||
}
|
||||
else
|
||||
{
|
||||
NSMutableArray<NSString *> *filePaths = [NSMutableArray arrayWithCapacity:[urls count]];
|
||||
for( int i = 0; i < [urls count]; i++ )
|
||||
[filePaths addObject:[urls[i] path]];
|
||||
|
||||
UnitySendMessage( "FPResultCallbackiOS", "OnMultipleFilesPicked", [self getCString:[filePaths componentsJoinedByString:@">"]] );
|
||||
}
|
||||
}
|
||||
else if( controller.documentPickerMode == UIDocumentPickerModeExportToService )
|
||||
{
|
||||
if( [urls count] > 0 )
|
||||
UnitySendMessage( "FPResultCallbackiOS", "OnFilesExported", "1" );
|
||||
else
|
||||
UnitySendMessage( "FPResultCallbackiOS", "OnFilesExported", "0" );
|
||||
}
|
||||
|
||||
[controller dismissViewControllerAnimated:NO completion:nil];
|
||||
}
|
||||
|
||||
+ (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller
|
||||
{
|
||||
filePicker = nil;
|
||||
UnitySendMessage( "FPResultCallbackiOS", "OnOperationCancelled", "" );
|
||||
|
||||
[controller dismissViewControllerAnimated:NO completion:nil];
|
||||
}
|
||||
|
||||
// Credit: https://stackoverflow.com/a/37052118/2373034
|
||||
+ (char *)getCString:(NSString *)source
|
||||
{
|
||||
if( source == nil )
|
||||
source = @"";
|
||||
|
||||
const char *sourceUTF8 = [source UTF8String];
|
||||
char *result = (char*) malloc( strlen( sourceUTF8 ) + 1 );
|
||||
strcpy(result, sourceUTF8);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
extern "C" void _NativeFilePicker_PickFile( const char* UTIs[], int UTIsCount )
|
||||
{
|
||||
NSMutableArray<NSString *> *allowedUTIs = [NSMutableArray arrayWithCapacity:UTIsCount];
|
||||
for( int i = 0; i < UTIsCount; i++ )
|
||||
[allowedUTIs addObject:[NSString stringWithUTF8String:UTIs[i]]];
|
||||
|
||||
[UNativeFilePicker pickFiles:NO withUTIs:allowedUTIs];
|
||||
}
|
||||
|
||||
extern "C" void _NativeFilePicker_PickMultipleFiles( const char* UTIs[], int UTIsCount )
|
||||
{
|
||||
NSMutableArray<NSString *> *allowedUTIs = [NSMutableArray arrayWithCapacity:UTIsCount];
|
||||
for( int i = 0; i < UTIsCount; i++ )
|
||||
[allowedUTIs addObject:[NSString stringWithUTF8String:UTIs[i]]];
|
||||
|
||||
[UNativeFilePicker pickFiles:YES withUTIs:allowedUTIs];
|
||||
}
|
||||
|
||||
extern "C" void _NativeFilePicker_ExportFiles( const char* files[], int filesCount )
|
||||
{
|
||||
NSMutableArray<NSURL *> *paths = [NSMutableArray arrayWithCapacity:filesCount];
|
||||
for( int i = 0; i < filesCount; i++ )
|
||||
{
|
||||
NSString *filePath = [NSString stringWithUTF8String:files[i]];
|
||||
[paths addObject:[NSURL fileURLWithPath:filePath]];
|
||||
}
|
||||
|
||||
[UNativeFilePicker exportFiles:paths];
|
||||
}
|
||||
|
||||
extern "C" int _NativeFilePicker_CanPickMultipleFiles()
|
||||
{
|
||||
return [UNativeFilePicker canPickMultipleFiles];
|
||||
}
|
||||
|
||||
extern "C" int _NativeFilePicker_IsFilePickerBusy()
|
||||
{
|
||||
return [UNativeFilePicker isFilePickerBusy];
|
||||
}
|
||||
|
||||
extern "C" char* _NativeFilePicker_ConvertExtensionToUTI( const char* extension )
|
||||
{
|
||||
return [UNativeFilePicker convertExtensionToUTI:[NSString stringWithUTF8String:extension]];
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c65eb8688946be4ea1af62f377f8891
|
||||
timeCreated: 1498722774
|
||||
licenseType: Store
|
||||
PluginImporter:
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
platformData:
|
||||
data:
|
||||
first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
data:
|
||||
first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
data:
|
||||
first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 173238
|
||||
packageName: Native File Picker for Android & iOS
|
||||
packageVersion: 1.4.1
|
||||
assetPath: Assets/Plugins/NativeFilePicker/iOS/NativeFilePicker.mm
|
||||
uploadId: 757770
|
||||
Reference in new issue
Block a user