[file_selector] Basic iOS implementation (#5448)
diff --git a/packages/file_selector/file_selector_ios/.gitignore b/packages/file_selector/file_selector_ios/.gitignore
new file mode 100644
index 0000000..9be145f
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/.gitignore
@@ -0,0 +1,29 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
+/pubspec.lock
+**/doc/api/
+.dart_tool/
+.packages
+build/
diff --git a/packages/file_selector/file_selector_ios/.metadata b/packages/file_selector/file_selector_ios/.metadata
new file mode 100644
index 0000000..295d2f7
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/.metadata
@@ -0,0 +1,30 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled.
+
+version:
+ revision: ac1aa511ca94f46c7e80b94dafd521de35e808e5
+ channel: master
+
+project_type: plugin
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: ac1aa511ca94f46c7e80b94dafd521de35e808e5
+ base_revision: ac1aa511ca94f46c7e80b94dafd521de35e808e5
+ - platform: ios
+ create_revision: ac1aa511ca94f46c7e80b94dafd521de35e808e5
+ base_revision: ac1aa511ca94f46c7e80b94dafd521de35e808e5
+
+ # User provided section
+
+ # List of Local paths (relative to this file) that should be
+ # ignored by the migrate tool.
+ #
+ # Files that are not part of the templates will be ignored by default.
+ unmanaged_files:
+ - 'lib/main.dart'
+ - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/packages/file_selector/file_selector_ios/AUTHORS b/packages/file_selector/file_selector_ios/AUTHORS
new file mode 100644
index 0000000..557dff9
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/AUTHORS
@@ -0,0 +1,6 @@
+# Below is a list of people and organizations that have contributed
+# to the Flutter project. Names should be added to the list like so:
+#
+# Name/Organization <email address>
+
+Google Inc.
diff --git a/packages/file_selector/file_selector_ios/CHANGELOG.md b/packages/file_selector/file_selector_ios/CHANGELOG.md
new file mode 100644
index 0000000..8c5d885
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/CHANGELOG.md
@@ -0,0 +1,3 @@
+## 0.5.0
+
+* Initial iOS implementation of `file_selector`.
diff --git a/packages/file_selector/file_selector_ios/LICENSE b/packages/file_selector/file_selector_ios/LICENSE
new file mode 100644
index 0000000..c6823b8
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/LICENSE
@@ -0,0 +1,25 @@
+Copyright 2013 The Flutter Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/packages/file_selector/file_selector_ios/README.md b/packages/file_selector/file_selector_ios/README.md
new file mode 100644
index 0000000..23b234d
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/README.md
@@ -0,0 +1,19 @@
+# file\_selector\_ios
+
+The iOS implementation of [`file_selector`][1].
+
+## Usage
+
+### Importing the package
+
+This implementation has not yet been endorsed, meaning that you need to
+[depend on `file_selector_ios`][2] in addition to
+[depending on `file_selector`][3].
+
+Once your pubspec includes the ios implementation, you can use the
+`file_selector` APIs normally. You should not use the `file_selector_ios`
+APIs directly.
+
+[1]: https://pub.dev/packages/file_selector
+[2]: https://pub.dev/packages/file_selector_ios/install
+[3]: https://pub.dev/packages/file_selector/install
\ No newline at end of file
diff --git a/packages/file_selector/file_selector_ios/example/.gitignore b/packages/file_selector/file_selector_ios/example/.gitignore
new file mode 100644
index 0000000..0fa6b67
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/.gitignore
@@ -0,0 +1,46 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.packages
+.pub-cache/
+.pub/
+/build/
+
+# Web related
+lib/generated_plugin_registrant.dart
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
diff --git a/packages/file_selector/file_selector_ios/example/.metadata b/packages/file_selector/file_selector_ios/example/.metadata
new file mode 100644
index 0000000..3c3e4b5
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/.metadata
@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: 5464c5bac742001448fe4fc0597be939379f88ea
+ channel: stable
+
+project_type: app
diff --git a/packages/file_selector/file_selector_ios/example/README.md b/packages/file_selector/file_selector_ios/example/README.md
new file mode 100644
index 0000000..9ed63fd
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/README.md
@@ -0,0 +1,4 @@
+# `file_selector_ios` example
+
+Demonstrates iOS implementation of the
+[`file_selector` plugin](https://pub.dev/packages/file_selector).
\ No newline at end of file
diff --git a/packages/file_selector/file_selector_ios/example/ios/.gitignore b/packages/file_selector/file_selector_ios/example/ios/.gitignore
new file mode 100644
index 0000000..7a7f987
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/.gitignore
@@ -0,0 +1,34 @@
+**/dgph
+*.mode1v3
+*.mode2v3
+*.moved-aside
+*.pbxuser
+*.perspectivev3
+**/*sync/
+.sconsign.dblite
+.tags*
+**/.vagrant/
+**/DerivedData/
+Icon?
+**/Pods/
+**/.symlinks/
+profile
+xcuserdata
+**/.generated/
+Flutter/App.framework
+Flutter/Flutter.framework
+Flutter/Flutter.podspec
+Flutter/Generated.xcconfig
+Flutter/ephemeral/
+Flutter/app.flx
+Flutter/app.zip
+Flutter/flutter_assets/
+Flutter/flutter_export_environment.sh
+ServiceDefinitions.json
+Runner/GeneratedPluginRegistrant.*
+
+# Exceptions to above rules.
+!default.mode1v3
+!default.mode2v3
+!default.pbxuser
+!default.perspectivev3
diff --git a/packages/file_selector/file_selector_ios/example/ios/Flutter/AppFrameworkInfo.plist b/packages/file_selector/file_selector_ios/example/ios/Flutter/AppFrameworkInfo.plist
new file mode 100644
index 0000000..9625e10
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Flutter/AppFrameworkInfo.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>App</string>
+ <key>CFBundleIdentifier</key>
+ <string>io.flutter.flutter.app</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>App</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>MinimumOSVersion</key>
+ <string>11.0</string>
+</dict>
+</plist>
diff --git a/packages/file_selector/file_selector_ios/example/ios/Flutter/Debug.xcconfig b/packages/file_selector/file_selector_ios/example/ios/Flutter/Debug.xcconfig
new file mode 100644
index 0000000..ec97fc6
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Flutter/Debug.xcconfig
@@ -0,0 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
+#include "Generated.xcconfig"
diff --git a/packages/file_selector/file_selector_ios/example/ios/Flutter/Release.xcconfig b/packages/file_selector/file_selector_ios/example/ios/Flutter/Release.xcconfig
new file mode 100644
index 0000000..c4855bf
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Flutter/Release.xcconfig
@@ -0,0 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
+#include "Generated.xcconfig"
diff --git a/packages/file_selector/file_selector_ios/example/ios/Podfile b/packages/file_selector/file_selector_ios/example/ios/Podfile
new file mode 100644
index 0000000..3c0b314
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Podfile
@@ -0,0 +1,46 @@
+# Uncomment this line to define a global platform for your project
+# platform :ios, '11.0'
+
+# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
+ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+
+project 'Runner', {
+ 'Debug' => :debug,
+ 'Profile' => :release,
+ 'Release' => :release,
+}
+
+def flutter_root
+ generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
+ unless File.exist?(generated_xcode_build_settings_path)
+ raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
+ end
+
+ File.foreach(generated_xcode_build_settings_path) do |line|
+ matches = line.match(/FLUTTER_ROOT\=(.*)/)
+ return matches[1].strip if matches
+ end
+ raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
+end
+
+require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
+
+flutter_ios_podfile_setup
+
+target 'Runner' do
+ use_frameworks!
+ use_modular_headers!
+
+ flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
+ target 'RunnerTests' do
+ inherit! :search_paths
+ # Pods for testing
+ pod 'OCMock', '~> 3.8.1'
+ end
+end
+
+post_install do |installer|
+ installer.pods_project.targets.each do |target|
+ flutter_additional_ios_build_settings(target)
+ end
+end
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner.xcodeproj/project.pbxproj b/packages/file_selector/file_selector_ios/example/ios/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..e21f78a
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,771 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 54;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+ 21160A929DC757957DE39F1E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 000792269CB6B9FE88AC567C /* Pods_Runner.framework */; };
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
+ 6165A2F80DFA224EAF50A1D5 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AC3841659BF3693FAC5A2F8F /* Pods_RunnerTests.framework */; };
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+ C71AE4C8281C6B6B0086307A /* FileSelectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C71AE4C5281C6B530086307A /* FileSelectorTests.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ C71AE4BA281C6A090086307A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 97C146E61CF9000F007C117D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 97C146ED1CF9000F007C117D;
+ remoteInfo = Runner;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 000792269CB6B9FE88AC567C /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
+ 4A27CC0DB4EF6669B637A1E8 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
+ 5667547C6832727A744371E2 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
+ 5C0E87EDCB9350EC4916E293 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
+ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
+ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
+ 786CCB880423FD6D1019F59B /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
+ 79C120FEED85F112A72B5D35 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
+ 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+ 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ AC3841659BF3693FAC5A2F8F /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ C71AE4B6281C6A090086307A /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ C71AE4C5281C6B530086307A /* FileSelectorTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FileSelectorTests.m; sourceTree = "<group>"; };
+ F818CE2D7CDF8AFF94707327 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 97C146EB1CF9000F007C117D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 21160A929DC757957DE39F1E /* Pods_Runner.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C71AE4B3281C6A090086307A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 6165A2F80DFA224EAF50A1D5 /* Pods_RunnerTests.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 2E44EE3EE3BCCAB6933171F8 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ 79C120FEED85F112A72B5D35 /* Pods-Runner.debug.xcconfig */,
+ F818CE2D7CDF8AFF94707327 /* Pods-Runner.release.xcconfig */,
+ 5C0E87EDCB9350EC4916E293 /* Pods-Runner.profile.xcconfig */,
+ 4A27CC0DB4EF6669B637A1E8 /* Pods-RunnerTests.debug.xcconfig */,
+ 5667547C6832727A744371E2 /* Pods-RunnerTests.release.xcconfig */,
+ 786CCB880423FD6D1019F59B /* Pods-RunnerTests.profile.xcconfig */,
+ );
+ path = Pods;
+ sourceTree = "<group>";
+ };
+ 9740EEB11CF90186004384FC /* Flutter */ = {
+ isa = PBXGroup;
+ children = (
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */,
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */,
+ );
+ name = Flutter;
+ sourceTree = "<group>";
+ };
+ 97C146E51CF9000F007C117D = {
+ isa = PBXGroup;
+ children = (
+ C71AE4C4281C6B370086307A /* RunnerTests */,
+ 9740EEB11CF90186004384FC /* Flutter */,
+ 97C146F01CF9000F007C117D /* Runner */,
+ 97C146EF1CF9000F007C117D /* Products */,
+ 2E44EE3EE3BCCAB6933171F8 /* Pods */,
+ C832A34FD3BC866442874ED0 /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ 97C146EF1CF9000F007C117D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146EE1CF9000F007C117D /* Runner.app */,
+ C71AE4B6281C6A090086307A /* RunnerTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 97C146F01CF9000F007C117D /* Runner */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146FA1CF9000F007C117D /* Main.storyboard */,
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */,
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
+ 97C147021CF9000F007C117D /* Info.plist */,
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
+ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
+ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
+ );
+ path = Runner;
+ sourceTree = "<group>";
+ };
+ C71AE4C4281C6B370086307A /* RunnerTests */ = {
+ isa = PBXGroup;
+ children = (
+ C71AE4C5281C6B530086307A /* FileSelectorTests.m */,
+ );
+ path = RunnerTests;
+ sourceTree = "<group>";
+ };
+ C832A34FD3BC866442874ED0 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 000792269CB6B9FE88AC567C /* Pods_Runner.framework */,
+ AC3841659BF3693FAC5A2F8F /* Pods_RunnerTests.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 97C146ED1CF9000F007C117D /* Runner */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
+ buildPhases = (
+ AC24910767ED5F17F5245292 /* [CP] Check Pods Manifest.lock */,
+ 9740EEB61CF901F6004384FC /* Run Script */,
+ 97C146EA1CF9000F007C117D /* Sources */,
+ 97C146EB1CF9000F007C117D /* Frameworks */,
+ 97C146EC1CF9000F007C117D /* Resources */,
+ 9705A1C41CF9048500538489 /* Embed Frameworks */,
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ BE6D85B8F242B768015B938B /* [CP] Embed Pods Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Runner;
+ productName = Runner;
+ productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
+ productType = "com.apple.product-type.application";
+ };
+ C71AE4B5281C6A090086307A /* RunnerTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C71AE4BF281C6A090086307A /* Build configuration list for PBXNativeTarget "RunnerTests" */;
+ buildPhases = (
+ A68B14611B411E4F96A5C80D /* [CP] Check Pods Manifest.lock */,
+ C71AE4B2281C6A090086307A /* Sources */,
+ C71AE4B3281C6A090086307A /* Frameworks */,
+ C71AE4B4281C6A090086307A /* Resources */,
+ 5BE5886DAAA885227DE0796D /* [CP] Embed Pods Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ C71AE4BB281C6A090086307A /* PBXTargetDependency */,
+ );
+ name = RunnerTests;
+ productName = FileSelectorTests;
+ productReference = C71AE4B6281C6A090086307A /* RunnerTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 97C146E61CF9000F007C117D /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 1300;
+ ORGANIZATIONNAME = "";
+ TargetAttributes = {
+ 97C146ED1CF9000F007C117D = {
+ CreatedOnToolsVersion = 7.3.1;
+ LastSwiftMigration = 1100;
+ };
+ C71AE4B5281C6A090086307A = {
+ CreatedOnToolsVersion = 13.1;
+ TestTargetID = 97C146ED1CF9000F007C117D;
+ };
+ };
+ };
+ buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
+ compatibilityVersion = "Xcode 9.3";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 97C146E51CF9000F007C117D;
+ productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 97C146ED1CF9000F007C117D /* Runner */,
+ C71AE4B5281C6A090086307A /* RunnerTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 97C146EC1CF9000F007C117D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C71AE4B4281C6A090086307A /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
+ isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Thin Binary";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
+ };
+ 5BE5886DAAA885227DE0796D /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 9740EEB61CF901F6004384FC /* Run Script */ = {
+ isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Run Script";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
+ };
+ A68B14611B411E4F96A5C80D /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ AC24910767ED5F17F5245292 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BE6D85B8F242B768015B938B /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 97C146EA1CF9000F007C117D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C71AE4B2281C6A090086307A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C71AE4C8281C6B6B0086307A /* FileSelectorTests.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ C71AE4BB281C6A090086307A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 97C146ED1CF9000F007C117D /* Runner */;
+ targetProxy = C71AE4BA281C6A090086307A /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C146FB1CF9000F007C117D /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "<group>";
+ };
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C147001CF9000F007C117D /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 249021D3217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Profile;
+ };
+ 249021D4217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.fileSelectorIosExample;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Profile;
+ };
+ 97C147031CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 97C147041CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 97C147061CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.fileSelectorIosExample;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Debug;
+ };
+ 97C147071CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.fileSelectorIosExample;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Release;
+ };
+ C71AE4BC281C6A090086307A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 4A27CC0DB4EF6669B637A1E8 /* Pods-RunnerTests.debug.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.FileSelectorTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner";
+ };
+ name = Debug;
+ };
+ C71AE4BD281C6A090086307A /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 5667547C6832727A744371E2 /* Pods-RunnerTests.release.xcconfig */;
+ buildSettings = {
+ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GENERATE_INFOPLIST_FILE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.FileSelectorTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner";
+ };
+ name = Release;
+ };
+ C71AE4BE281C6A090086307A /* Profile */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 786CCB880423FD6D1019F59B /* Pods-RunnerTests.profile.xcconfig */;
+ buildSettings = {
+ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GENERATE_INFOPLIST_FILE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.FileSelectorTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner";
+ };
+ name = Profile;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147031CF9000F007C117D /* Debug */,
+ 97C147041CF9000F007C117D /* Release */,
+ 249021D3217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147061CF9000F007C117D /* Debug */,
+ 97C147071CF9000F007C117D /* Release */,
+ 249021D4217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C71AE4BF281C6A090086307A /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C71AE4BC281C6A090086307A /* Debug */,
+ C71AE4BD281C6A090086307A /* Release */,
+ C71AE4BE281C6A090086307A /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 97C146E61CF9000F007C117D /* Project object */;
+}
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/file_selector/file_selector_ios/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:">
+ </FileRef>
+</Workspace>
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/file_selector/file_selector_ios/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IDEDidComputeMac32BitWarning</key>
+ <true/>
+</dict>
+</plist>
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/file_selector/file_selector_ios/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>PreviewsEnabled</key>
+ <false/>
+</dict>
+</plist>
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/file_selector/file_selector_ios/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
new file mode 100644
index 0000000..c842c6b
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "1300"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+ BuildableName = "Runner.app"
+ BlueprintName = "Runner"
+ ReferencedContainer = "container:Runner.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+ BuildableName = "Runner.app"
+ BlueprintName = "Runner"
+ ReferencedContainer = "container:Runner.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "C71AE4B5281C6A090086307A"
+ BuildableName = "RunnerTests.xctest"
+ BlueprintName = "RunnerTests"
+ ReferencedContainer = "container:Runner.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+ BuildableName = "Runner.app"
+ BlueprintName = "Runner"
+ ReferencedContainer = "container:Runner.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Profile"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+ BuildableName = "Runner.app"
+ BlueprintName = "Runner"
+ ReferencedContainer = "container:Runner.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/file_selector/file_selector_ios/example/ios/Runner.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..21a3cc1
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "group:Runner.xcodeproj">
+ </FileRef>
+ <FileRef
+ location = "group:Pods/Pods.xcodeproj">
+ </FileRef>
+</Workspace>
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/file_selector/file_selector_ios/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IDEDidComputeMac32BitWarning</key>
+ <true/>
+</dict>
+</plist>
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/file_selector/file_selector_ios/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>PreviewsEnabled</key>
+ <false/>
+</dict>
+</plist>
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/AppDelegate.swift b/packages/file_selector/file_selector_ios/example/ios/Runner/AppDelegate.swift
new file mode 100644
index 0000000..caf9983
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/AppDelegate.swift
@@ -0,0 +1,17 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import UIKit
+import Flutter
+
+@UIApplicationMain
+@objc class AppDelegate: FlutterAppDelegate {
+ override func application(
+ _ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
+ ) -> Bool {
+ GeneratedPluginRegistrant.register(with: self)
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+ }
+}
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..d36b1fa
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,122 @@
+{
+ "images" : [
+ {
+ "size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-20x20@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-20x20@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-40x40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-40x40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-60x60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-60x60@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-20x20@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-20x20@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-29x29@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-29x29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-40x40@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-40x40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-76x76@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-76x76@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "83.5x83.5",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-83.5x83.5@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "1024x1024",
+ "idiom" : "ios-marketing",
+ "filename" : "Icon-App-1024x1024@1x.png",
+ "scale" : "1x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
new file mode 100644
index 0000000..dc9ada4
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
new file mode 100644
index 0000000..28c6bf0
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
new file mode 100644
index 0000000..2ccbfd9
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
new file mode 100644
index 0000000..f091b6b
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
new file mode 100644
index 0000000..4cde121
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
new file mode 100644
index 0000000..d0ef06e
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
new file mode 100644
index 0000000..dcdc230
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
new file mode 100644
index 0000000..2ccbfd9
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
new file mode 100644
index 0000000..c8f9ed8
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
new file mode 100644
index 0000000..a6d6b86
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
new file mode 100644
index 0000000..a6d6b86
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
new file mode 100644
index 0000000..75b2d16
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
new file mode 100644
index 0000000..c4df70d
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
new file mode 100644
index 0000000..6a84f41
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
new file mode 100644
index 0000000..d0e1f58
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
new file mode 100644
index 0000000..0bedcf2
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
new file mode 100644
index 0000000..9da19ea
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
new file mode 100644
index 0000000..9da19ea
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
new file mode 100644
index 0000000..9da19ea
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
Binary files differ
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
new file mode 100644
index 0000000..89c2725
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
@@ -0,0 +1,5 @@
+# Launch Screen Assets
+
+You can customize the launch screen with your own desired assets by replacing the image files in this directory.
+
+You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
\ No newline at end of file
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/file_selector/file_selector_ios/example/ios/Runner/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..f2e259c
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
+ </dependencies>
+ <scenes>
+ <!--View Controller-->
+ <scene sceneID="EHf-IW-A2E">
+ <objects>
+ <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
+ <viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
+ </imageView>
+ </subviews>
+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <constraints>
+ <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
+ <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
+ </constraints>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="53" y="375"/>
+ </scene>
+ </scenes>
+ <resources>
+ <image name="LaunchImage" width="168" height="185"/>
+ </resources>
+</document>
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Base.lproj/Main.storyboard b/packages/file_selector/file_selector_ios/example/ios/Runner/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..f3c2851
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Base.lproj/Main.storyboard
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
+ </dependencies>
+ <scenes>
+ <!--Flutter View Controller-->
+ <scene sceneID="tne-QT-ifu">
+ <objects>
+ <viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+ <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+ </objects>
+ </scene>
+ </scenes>
+</document>
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Info.plist b/packages/file_selector/file_selector_ios/example/ios/Runner/Info.plist
new file mode 100644
index 0000000..2bf6e92
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Info.plist
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleDisplayName</key>
+ <string>File Selector Ios</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>file_selector_ios_example</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>$(FLUTTER_BUILD_NAME)</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>$(FLUTTER_BUILD_NUMBER)</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UILaunchStoryboardName</key>
+ <string>LaunchScreen</string>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+ <key>UISupportedInterfaceOrientations~ipad</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+ <key>UIViewControllerBasedStatusBarAppearance</key>
+ <false/>
+ <key>CADisableMinimumFrameDurationOnPhone</key>
+ <true/>
+ <key>UIApplicationSupportsIndirectInputEvents</key>
+ <true/>
+</dict>
+</plist>
diff --git a/packages/file_selector/file_selector_ios/example/ios/Runner/Runner-Bridging-Header.h b/packages/file_selector/file_selector_ios/example/ios/Runner/Runner-Bridging-Header.h
new file mode 100644
index 0000000..eb7e8ba
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/Runner/Runner-Bridging-Header.h
@@ -0,0 +1,5 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "GeneratedPluginRegistrant.h"
diff --git a/packages/file_selector/file_selector_ios/example/ios/RunnerTests/FileSelectorTests.m b/packages/file_selector/file_selector_ios/example/ios/RunnerTests/FileSelectorTests.m
new file mode 100644
index 0000000..a32622a
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/ios/RunnerTests/FileSelectorTests.m
@@ -0,0 +1,98 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+@import file_selector_ios;
+@import file_selector_ios.Test;
+@import XCTest;
+
+#import <OCMock/OCMock.h>
+
+@interface FileSelectorTests : XCTestCase
+
+@end
+
+@implementation FileSelectorTests
+
+- (void)testPickerPresents {
+ FFSFileSelectorPlugin *plugin = [[FFSFileSelectorPlugin alloc] init];
+ UIDocumentPickerViewController *picker =
+ [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[]
+ inMode:UIDocumentPickerModeImport];
+ id mockPresentingVC = OCMClassMock([UIViewController class]);
+ plugin.documentPickerViewControllerOverride = picker;
+ plugin.presentingViewControllerOverride = mockPresentingVC;
+
+ [plugin openFileSelectorWithConfig:[FFSFileSelectorConfig makeWithUtis:@[]
+ allowMultiSelection:@NO]
+ completion:^(NSArray<NSString *> *paths, FlutterError *error){
+ }];
+
+ XCTAssertEqualObjects(picker.delegate, plugin);
+ OCMVerify(times(1), [mockPresentingVC presentViewController:picker
+ animated:[OCMArg any]
+ completion:[OCMArg any]]);
+}
+
+- (void)testReturnsPickedFiles {
+ FFSFileSelectorPlugin *plugin = [[FFSFileSelectorPlugin alloc] init];
+ XCTestExpectation *completionWasCalled = [self expectationWithDescription:@"completion"];
+ UIDocumentPickerViewController *picker =
+ [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[]
+ inMode:UIDocumentPickerModeImport];
+ plugin.documentPickerViewControllerOverride = picker;
+ [plugin openFileSelectorWithConfig:[FFSFileSelectorConfig makeWithUtis:@[]
+ allowMultiSelection:@YES]
+ completion:^(NSArray<NSString *> *paths, FlutterError *error) {
+ NSArray *expectedPaths = @[ @"/file1.txt", @"/file2.txt" ];
+ XCTAssertEqualObjects(paths, expectedPaths);
+ [completionWasCalled fulfill];
+ }];
+ [plugin documentPicker:picker
+ didPickDocumentsAtURLs:@[
+ [NSURL URLWithString:@"file:///file1.txt"], [NSURL URLWithString:@"file:///file2.txt"]
+ ]];
+ [self waitForExpectationsWithTimeout:1.0 handler:nil];
+}
+
+- (void)testReturnsPickedFileLegacy {
+ // Tests that it handles the pre iOS 11 UIDocumentPickerDelegate method.
+ FFSFileSelectorPlugin *plugin = [[FFSFileSelectorPlugin alloc] init];
+ XCTestExpectation *completionWasCalled = [self expectationWithDescription:@"completion"];
+ UIDocumentPickerViewController *picker =
+ [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[]
+ inMode:UIDocumentPickerModeImport];
+ plugin.documentPickerViewControllerOverride = picker;
+ [plugin openFileSelectorWithConfig:[FFSFileSelectorConfig makeWithUtis:@[]
+ allowMultiSelection:@NO]
+ completion:^(NSArray<NSString *> *paths, FlutterError *error) {
+ NSArray *expectedPaths = @[ @"/file1.txt" ];
+ XCTAssertEqualObjects(paths, expectedPaths);
+ [completionWasCalled fulfill];
+ }];
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+ [plugin documentPicker:picker didPickDocumentAtURL:[NSURL URLWithString:@"file:///file1.txt"]];
+#pragma GCC diagnostic pop
+ [self waitForExpectationsWithTimeout:1.0 handler:nil];
+}
+
+- (void)testCancellingPickerReturnsNil {
+ FFSFileSelectorPlugin *plugin = [[FFSFileSelectorPlugin alloc] init];
+ UIDocumentPickerViewController *picker =
+ [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[]
+ inMode:UIDocumentPickerModeImport];
+ plugin.documentPickerViewControllerOverride = picker;
+
+ XCTestExpectation *completionWasCalled = [self expectationWithDescription:@"completion"];
+ [plugin openFileSelectorWithConfig:[FFSFileSelectorConfig makeWithUtis:@[]
+ allowMultiSelection:@NO]
+ completion:^(NSArray<NSString *> *paths, FlutterError *error) {
+ XCTAssertEqual(paths.count, 0);
+ [completionWasCalled fulfill];
+ }];
+ [plugin documentPickerWasCancelled:picker];
+ [self waitForExpectationsWithTimeout:1.0 handler:nil];
+}
+
+@end
diff --git a/packages/file_selector/file_selector_ios/example/lib/home_page.dart b/packages/file_selector/file_selector_ios/example/lib/home_page.dart
new file mode 100644
index 0000000..a4b2ae1
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/lib/home_page.dart
@@ -0,0 +1,63 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+
+/// Home Page of the application.
+class HomePage extends StatelessWidget {
+ /// Default Constructor
+ const HomePage({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ final ButtonStyle style = ElevatedButton.styleFrom(
+ // TODO(darrenaustin): Migrate to new API once it lands in stable: https://github.com/flutter/flutter/issues/105724
+ // ignore: deprecated_member_use
+ primary: Colors.blue,
+ // ignore: deprecated_member_use
+ onPrimary: Colors.white,
+ );
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('File Selector Demo Home Page'),
+ ),
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: <Widget>[
+ ElevatedButton(
+ style: style,
+ child: const Text('Open a text file'),
+ onPressed: () => Navigator.pushNamed(context, '/open/text'),
+ ),
+ const SizedBox(height: 10),
+ ElevatedButton(
+ style: style,
+ child: const Text('Open an image'),
+ onPressed: () => Navigator.pushNamed(context, '/open/image'),
+ ),
+ const SizedBox(height: 10),
+ ElevatedButton(
+ style: style,
+ child: const Text('Open multiple images'),
+ onPressed: () => Navigator.pushNamed(context, '/open/images'),
+ ),
+ const SizedBox(height: 10),
+ ElevatedButton(
+ style: style,
+ child: const Text('Save a file'),
+ onPressed: () => Navigator.pushNamed(context, '/save/text'),
+ ),
+ const SizedBox(height: 10),
+ ElevatedButton(
+ style: style,
+ child: const Text('Open a get directory dialog'),
+ onPressed: () => Navigator.pushNamed(context, '/directory'),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/packages/file_selector/file_selector_ios/example/lib/main.dart b/packages/file_selector/file_selector_ios/example/lib/main.dart
new file mode 100644
index 0000000..929c48f
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/lib/main.dart
@@ -0,0 +1,38 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+
+import 'home_page.dart';
+import 'open_image_page.dart';
+import 'open_multiple_images_page.dart';
+import 'open_text_page.dart';
+
+void main() {
+ runApp(const MyApp());
+}
+
+/// MyApp is the Main Application.
+class MyApp extends StatelessWidget {
+ /// Default Constructor
+ const MyApp({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ title: 'File Selector Demo',
+ theme: ThemeData(
+ primarySwatch: Colors.blue,
+ visualDensity: VisualDensity.adaptivePlatformDensity,
+ ),
+ home: const HomePage(),
+ routes: <String, WidgetBuilder>{
+ '/open/image': (BuildContext context) => const OpenImagePage(),
+ '/open/images': (BuildContext context) =>
+ const OpenMultipleImagesPage(),
+ '/open/text': (BuildContext context) => const OpenTextPage(),
+ },
+ );
+ }
+}
diff --git a/packages/file_selector/file_selector_ios/example/lib/open_image_page.dart b/packages/file_selector/file_selector_ios/example/lib/open_image_page.dart
new file mode 100644
index 0000000..fd0f4e7
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/lib/open_image_page.dart
@@ -0,0 +1,95 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+
+/// Screen that allows the user to select an image file using
+/// `openFiles`, then displays the selected images in a gallery dialog.
+class OpenImagePage extends StatelessWidget {
+ /// Default Constructor
+ const OpenImagePage({Key? key}) : super(key: key);
+
+ Future<void> _openImageFile(BuildContext context) async {
+ final XTypeGroup typeGroup = XTypeGroup(
+ label: 'images',
+ extensions: <String>['jpg', 'png'],
+ macUTIs: <String>['public.image'],
+ );
+ final XFile? file = await FileSelectorPlatform.instance
+ .openFile(acceptedTypeGroups: <XTypeGroup>[typeGroup]);
+ if (file == null) {
+ // Operation was canceled by the user.
+ return;
+ }
+ final String fileName = file.name;
+ final String filePath = file.path;
+
+ await showDialog<void>(
+ context: context,
+ builder: (BuildContext context) => ImageDisplay(fileName, filePath),
+ );
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('Open an image'),
+ ),
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: <Widget>[
+ ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ // TODO(darrenaustin): Migrate to new API once it lands in stable: https://github.com/flutter/flutter/issues/105724
+ // ignore: deprecated_member_use
+ primary: Colors.blue,
+ // ignore: deprecated_member_use
+ onPrimary: Colors.white,
+ ),
+ child: const Text('Press to open an image file(png, jpg)'),
+ onPressed: () => _openImageFile(context),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
+
+/// Widget that displays an image in a dialog.
+class ImageDisplay extends StatelessWidget {
+ /// Default Constructor.
+ const ImageDisplay(this.fileName, this.filePath, {Key? key})
+ : super(key: key);
+
+ /// The name of the selected file.
+ final String fileName;
+
+ /// The path to the selected file.
+ final String filePath;
+
+ @override
+ Widget build(BuildContext context) {
+ return AlertDialog(
+ title: Text(fileName),
+ // On web the filePath is a blob url
+ // while on other platforms it is a system path.
+ content: kIsWeb ? Image.network(filePath) : Image.file(File(filePath)),
+ actions: <Widget>[
+ TextButton(
+ child: const Text('Close'),
+ onPressed: () {
+ Navigator.pop(context);
+ },
+ ),
+ ],
+ );
+ }
+}
diff --git a/packages/file_selector/file_selector_ios/example/lib/open_multiple_images_page.dart b/packages/file_selector/file_selector_ios/example/lib/open_multiple_images_page.dart
new file mode 100644
index 0000000..29b27c1
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/lib/open_multiple_images_page.dart
@@ -0,0 +1,107 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+
+/// Screen that allows the user to select multiple image files using
+/// `openFiles`, then displays the selected images in a gallery dialog.
+class OpenMultipleImagesPage extends StatelessWidget {
+ /// Default Constructor
+ const OpenMultipleImagesPage({Key? key}) : super(key: key);
+
+ Future<void> _openImageFile(BuildContext context) async {
+ final XTypeGroup jpgsTypeGroup = XTypeGroup(
+ label: 'JPEGs',
+ extensions: <String>['jpg', 'jpeg'],
+ macUTIs: <String>['public.jpeg'],
+ );
+ final XTypeGroup pngTypeGroup = XTypeGroup(
+ label: 'PNGs',
+ extensions: <String>['png'],
+ macUTIs: <String>['public.png'],
+ );
+ final List<XFile> files = await FileSelectorPlatform.instance
+ .openFiles(acceptedTypeGroups: <XTypeGroup>[
+ jpgsTypeGroup,
+ pngTypeGroup,
+ ]);
+ if (files.isEmpty) {
+ // Operation was canceled by the user.
+ return;
+ }
+ await showDialog<void>(
+ context: context,
+ builder: (BuildContext context) => MultipleImagesDisplay(files),
+ );
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('Open multiple images'),
+ ),
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: <Widget>[
+ ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ // TODO(darrenaustin): Migrate to new API once it lands in stable: https://github.com/flutter/flutter/issues/105724
+ // ignore: deprecated_member_use
+ primary: Colors.blue,
+ // ignore: deprecated_member_use
+ onPrimary: Colors.white,
+ ),
+ child: const Text('Press to open multiple images (png, jpg)'),
+ onPressed: () => _openImageFile(context),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
+
+/// Widget that displays a text file in a dialog.
+class MultipleImagesDisplay extends StatelessWidget {
+ /// Default Constructor.
+ const MultipleImagesDisplay(this.files, {Key? key}) : super(key: key);
+
+ /// The files containing the images.
+ final List<XFile> files;
+
+ @override
+ Widget build(BuildContext context) {
+ return AlertDialog(
+ title: const Text('Gallery'),
+ // On web the filePath is a blob url
+ // while on other platforms it is a system path.
+ content: Center(
+ child: Row(
+ children: <Widget>[
+ ...files.map(
+ (XFile file) => Flexible(
+ child: kIsWeb
+ ? Image.network(file.path)
+ : Image.file(File(file.path))),
+ )
+ ],
+ ),
+ ),
+ actions: <Widget>[
+ TextButton(
+ child: const Text('Close'),
+ onPressed: () {
+ Navigator.pop(context);
+ },
+ ),
+ ],
+ );
+ }
+}
diff --git a/packages/file_selector/file_selector_ios/example/lib/open_text_page.dart b/packages/file_selector/file_selector_ios/example/lib/open_text_page.dart
new file mode 100644
index 0000000..b747aa8
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/lib/open_text_page.dart
@@ -0,0 +1,92 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
+import 'package:flutter/material.dart';
+
+/// Screen that allows the user to select a text file using `openFile`, then
+/// displays its contents in a dialog.
+class OpenTextPage extends StatelessWidget {
+ /// Default Constructor
+ const OpenTextPage({Key? key}) : super(key: key);
+
+ Future<void> _openTextFile(BuildContext context) async {
+ final XTypeGroup typeGroup = XTypeGroup(
+ label: 'text',
+ extensions: <String>['txt', 'json'],
+ macUTIs: <String>['public.text'],
+ );
+ final XFile? file = await FileSelectorPlatform.instance
+ .openFile(acceptedTypeGroups: <XTypeGroup>[typeGroup]);
+ if (file == null) {
+ // Operation was canceled by the user.
+ return;
+ }
+ final String fileName = file.name;
+ final String fileContent = await file.readAsString();
+
+ await showDialog<void>(
+ context: context,
+ builder: (BuildContext context) => TextDisplay(fileName, fileContent),
+ );
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('Open a text file'),
+ ),
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: <Widget>[
+ ElevatedButton(
+ style: ElevatedButton.styleFrom(
+ // TODO(darrenaustin): Migrate to new API once it lands in stable: https://github.com/flutter/flutter/issues/105724
+ // ignore: deprecated_member_use
+ primary: Colors.blue,
+ // ignore: deprecated_member_use
+ onPrimary: Colors.white,
+ ),
+ child: const Text('Press to open a text file (json, txt)'),
+ onPressed: () => _openTextFile(context),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
+
+/// Widget that displays a text file in a dialog.
+class TextDisplay extends StatelessWidget {
+ /// Default Constructor.
+ const TextDisplay(this.fileName, this.fileContent, {Key? key})
+ : super(key: key);
+
+ /// The name of the selected file.
+ final String fileName;
+
+ /// The contents of the text file.
+ final String fileContent;
+
+ @override
+ Widget build(BuildContext context) {
+ return AlertDialog(
+ title: Text(fileName),
+ content: Scrollbar(
+ child: SingleChildScrollView(
+ child: Text(fileContent),
+ ),
+ ),
+ actions: <Widget>[
+ TextButton(
+ child: const Text('Close'),
+ onPressed: () => Navigator.pop(context),
+ ),
+ ],
+ );
+ }
+}
diff --git a/packages/file_selector/file_selector_ios/example/pubspec.yaml b/packages/file_selector/file_selector_ios/example/pubspec.yaml
new file mode 100644
index 0000000..eae4a2b
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/pubspec.yaml
@@ -0,0 +1,31 @@
+name: example
+description: Example for file_selector_ios implementation.
+publish_to: 'none'
+version: 1.0.0
+
+environment:
+ sdk: ">=2.14.4 <3.0.0"
+
+dependencies:
+ # The following adds the Cupertino Icons font to your application.
+ # Use with the CupertinoIcons class for iOS style icons.
+ cupertino_icons: ^1.0.2
+ file_selector_ios:
+ # When depending on this package from a real application you should use:
+ # file_selector_ios: ^x.y.z
+ # See https://dart.dev/tools/pub/dependencies#version-constraints
+ # The example app is bundled with the plugin so we use a path dependency on
+ # the parent directory to use the current plugin's version.
+ path: ..
+ file_selector_platform_interface: ^2.0.0
+ flutter:
+ sdk: flutter
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+ integration_test:
+ sdk: flutter
+
+flutter:
+ uses-material-design: true
\ No newline at end of file
diff --git a/packages/file_selector/file_selector_ios/example/test_driver/integration_test.dart b/packages/file_selector/file_selector_ios/example/test_driver/integration_test.dart
new file mode 100644
index 0000000..4f10f2a
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/example/test_driver/integration_test.dart
@@ -0,0 +1,7 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:integration_test/integration_test_driver.dart';
+
+Future<void> main() => integrationDriver();
diff --git a/packages/file_selector/file_selector_ios/ios/.gitignore b/packages/file_selector/file_selector_ios/ios/.gitignore
new file mode 100644
index 0000000..0c88507
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/ios/.gitignore
@@ -0,0 +1,38 @@
+.idea/
+.vagrant/
+.sconsign.dblite
+.svn/
+
+.DS_Store
+*.swp
+profile
+
+DerivedData/
+build/
+GeneratedPluginRegistrant.h
+GeneratedPluginRegistrant.m
+
+.generated/
+
+*.pbxuser
+*.mode1v3
+*.mode2v3
+*.perspectivev3
+
+!default.pbxuser
+!default.mode1v3
+!default.mode2v3
+!default.perspectivev3
+
+xcuserdata
+
+*.moved-aside
+
+*.pyc
+*sync/
+Icon?
+.tags*
+
+/Flutter/Generated.xcconfig
+/Flutter/ephemeral/
+/Flutter/flutter_export_environment.sh
\ No newline at end of file
diff --git a/packages/file_selector/file_selector_ios/ios/Assets/.gitkeep b/packages/file_selector/file_selector_ios/ios/Assets/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/ios/Assets/.gitkeep
diff --git a/packages/file_selector/file_selector_ios/ios/Classes/FFSFileSelectorPlugin.h b/packages/file_selector/file_selector_ios/ios/Classes/FFSFileSelectorPlugin.h
new file mode 100644
index 0000000..ca7ca56
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/ios/Classes/FFSFileSelectorPlugin.h
@@ -0,0 +1,8 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Flutter/Flutter.h>
+
+@interface FFSFileSelectorPlugin : NSObject <FlutterPlugin>
+@end
diff --git a/packages/file_selector/file_selector_ios/ios/Classes/FFSFileSelectorPlugin.m b/packages/file_selector/file_selector_ios/ios/Classes/FFSFileSelectorPlugin.m
new file mode 100644
index 0000000..e77585a
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/ios/Classes/FFSFileSelectorPlugin.m
@@ -0,0 +1,88 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "FFSFileSelectorPlugin.h"
+#import "FFSFileSelectorPlugin_Test.h"
+#import "messages.g.h"
+
+#import <objc/runtime.h>
+
+@implementation FFSFileSelectorPlugin
+
+#pragma mark - FFSFileSelectorApi
+
+- (void)openFileSelectorWithConfig:(FFSFileSelectorConfig *)config
+ completion:(void (^)(NSArray<NSString *> *_Nullable,
+ FlutterError *_Nullable))completion {
+ UIDocumentPickerViewController *documentPicker =
+ self.documentPickerViewControllerOverride
+ ?: [[UIDocumentPickerViewController alloc]
+ initWithDocumentTypes:config.utis
+ inMode:UIDocumentPickerModeImport];
+ documentPicker.delegate = self;
+ if (@available(iOS 11.0, *)) {
+ documentPicker.allowsMultipleSelection = config.allowMultiSelection.boolValue;
+ }
+
+ UIViewController *presentingVC =
+ self.presentingViewControllerOverride
+ ?: UIApplication.sharedApplication.delegate.window.rootViewController;
+ if (presentingVC) {
+ objc_setAssociatedObject(documentPicker, @selector(openFileSelectorWithConfig:completion:),
+ completion, OBJC_ASSOCIATION_COPY_NONATOMIC);
+ [presentingVC presentViewController:documentPicker animated:YES completion:nil];
+ } else {
+ completion(nil, [FlutterError errorWithCode:@"error"
+ message:@"Missing root view controller."
+ details:nil]);
+ }
+}
+
+#pragma mark - FlutterPlugin
+
++ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
+ FFSFileSelectorPlugin *plugin = [[FFSFileSelectorPlugin alloc] init];
+ FFSFileSelectorApiSetup(registrar.messenger, plugin);
+}
+
+#pragma mark - UIDocumentPickerDelegate
+
+// This method is only called in iOS < 11.0. The new codepath is
+// documentPicker:didPickDocumentsAtURLs:, implemented below.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-implementations"
+- (void)documentPicker:(UIDocumentPickerViewController *)controller
+ didPickDocumentAtURL:(NSURL *)url {
+ [self sendBackResults:@[ url.path ] error:nil forPicker:controller];
+}
+#pragma clang diagnostic pop
+
+- (void)documentPicker:(UIDocumentPickerViewController *)controller
+ didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls {
+ NSMutableArray *paths = [NSMutableArray arrayWithCapacity:urls.count];
+ for (NSURL *url in urls) {
+ [paths addObject:url.path];
+ };
+ [self sendBackResults:paths error:nil forPicker:controller];
+}
+
+- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller {
+ [self sendBackResults:@[] error:nil forPicker:controller];
+}
+
+#pragma mark - Helper Methods
+
+- (void)sendBackResults:(NSArray<NSString *> *)results
+ error:(FlutterError *)error
+ forPicker:(UIDocumentPickerViewController *)picker {
+ void (^completionBlock)(NSArray<NSString *> *, FlutterError *) =
+ objc_getAssociatedObject(picker, @selector(openFileSelectorWithConfig:completion:));
+ if (completionBlock) {
+ completionBlock(results, error);
+ objc_setAssociatedObject(picker, @selector(openFileSelectorWithConfig:completion:), nil,
+ OBJC_ASSOCIATION_ASSIGN);
+ }
+}
+
+@end
diff --git a/packages/file_selector/file_selector_ios/ios/Classes/FFSFileSelectorPlugin_Test.h b/packages/file_selector/file_selector_ios/ios/Classes/FFSFileSelectorPlugin_Test.h
new file mode 100644
index 0000000..f71a8ae
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/ios/Classes/FFSFileSelectorPlugin_Test.h
@@ -0,0 +1,22 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "FFSFileSelectorPlugin.h"
+
+#import "messages.g.h"
+
+// This header is available in the Test module. Import via "@import file_selector_ios.Test;".
+@interface FFSFileSelectorPlugin () <FFSFileSelectorApi, UIDocumentPickerDelegate>
+
+/**
+ * Overrides the view controller used for presenting the document picker.
+ */
+@property(nonatomic) UIViewController *_Nullable presentingViewControllerOverride;
+
+/**
+ * Overrides the UIDocumentPickerViewController used for file picking.
+ */
+@property(nonatomic) UIDocumentPickerViewController *_Nullable documentPickerViewControllerOverride;
+
+@end
diff --git a/packages/file_selector/file_selector_ios/ios/Classes/FileSelectorPlugin.modulemap b/packages/file_selector/file_selector_ios/ios/Classes/FileSelectorPlugin.modulemap
new file mode 100644
index 0000000..4ff4026
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/ios/Classes/FileSelectorPlugin.modulemap
@@ -0,0 +1,10 @@
+framework module file_selector_ios {
+ umbrella header "file_selector_ios-umbrella.h"
+
+ export *
+ module * { export * }
+
+ explicit module Test {
+ header "FFSFileSelectorPlugin_Test.h"
+ }
+}
diff --git a/packages/file_selector/file_selector_ios/ios/Classes/file_selector_ios-umbrella.h b/packages/file_selector/file_selector_ios/ios/Classes/file_selector_ios-umbrella.h
new file mode 100644
index 0000000..d79d364
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/ios/Classes/file_selector_ios-umbrella.h
@@ -0,0 +1,6 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Foundation/Foundation.h>
+#import <file_selector_ios/FFSFileSelectorPlugin.h>
diff --git a/packages/file_selector/file_selector_ios/ios/Classes/messages.g.h b/packages/file_selector/file_selector_ios/ios/Classes/messages.g.h
new file mode 100644
index 0000000..a04b411
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/ios/Classes/messages.g.h
@@ -0,0 +1,37 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Autogenerated from Pigeon (v3.2.5), do not edit directly.
+// See also: https://pub.dev/packages/pigeon
+#import <Foundation/Foundation.h>
+@protocol FlutterBinaryMessenger;
+@protocol FlutterMessageCodec;
+@class FlutterError;
+@class FlutterStandardTypedData;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class FFSFileSelectorConfig;
+
+@interface FFSFileSelectorConfig : NSObject
+/// `init` unavailable to enforce nonnull fields, see the `make` class method.
+- (instancetype)init NS_UNAVAILABLE;
++ (instancetype)makeWithUtis:(NSArray<NSString *> *)utis
+ allowMultiSelection:(NSNumber *)allowMultiSelection;
+@property(nonatomic, strong) NSArray<NSString *> *utis;
+@property(nonatomic, strong) NSNumber *allowMultiSelection;
+@end
+
+/// The codec used by FFSFileSelectorApi.
+NSObject<FlutterMessageCodec> *FFSFileSelectorApiGetCodec(void);
+
+@protocol FFSFileSelectorApi
+- (void)openFileSelectorWithConfig:(FFSFileSelectorConfig *)config
+ completion:(void (^)(NSArray<NSString *> *_Nullable,
+ FlutterError *_Nullable))completion;
+@end
+
+extern void FFSFileSelectorApiSetup(id<FlutterBinaryMessenger> binaryMessenger,
+ NSObject<FFSFileSelectorApi> *_Nullable api);
+
+NS_ASSUME_NONNULL_END
diff --git a/packages/file_selector/file_selector_ios/ios/Classes/messages.g.m b/packages/file_selector/file_selector_ios/ios/Classes/messages.g.m
new file mode 100644
index 0000000..d4046d2
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/ios/Classes/messages.g.m
@@ -0,0 +1,143 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Autogenerated from Pigeon (v3.2.5), do not edit directly.
+// See also: https://pub.dev/packages/pigeon
+#import "messages.g.h"
+#import <Flutter/Flutter.h>
+
+#if !__has_feature(objc_arc)
+#error File requires ARC to be enabled.
+#endif
+
+static NSDictionary<NSString *, id> *wrapResult(id result, FlutterError *error) {
+ NSDictionary *errorDict = (NSDictionary *)[NSNull null];
+ if (error) {
+ errorDict = @{
+ @"code" : (error.code ?: [NSNull null]),
+ @"message" : (error.message ?: [NSNull null]),
+ @"details" : (error.details ?: [NSNull null]),
+ };
+ }
+ return @{
+ @"result" : (result ?: [NSNull null]),
+ @"error" : errorDict,
+ };
+}
+static id GetNullableObject(NSDictionary *dict, id key) {
+ id result = dict[key];
+ return (result == [NSNull null]) ? nil : result;
+}
+static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) {
+ id result = array[key];
+ return (result == [NSNull null]) ? nil : result;
+}
+
+@interface FFSFileSelectorConfig ()
++ (FFSFileSelectorConfig *)fromMap:(NSDictionary *)dict;
++ (nullable FFSFileSelectorConfig *)nullableFromMap:(NSDictionary *)dict;
+- (NSDictionary *)toMap;
+@end
+
+@implementation FFSFileSelectorConfig
++ (instancetype)makeWithUtis:(NSArray<NSString *> *)utis
+ allowMultiSelection:(NSNumber *)allowMultiSelection {
+ FFSFileSelectorConfig *pigeonResult = [[FFSFileSelectorConfig alloc] init];
+ pigeonResult.utis = utis;
+ pigeonResult.allowMultiSelection = allowMultiSelection;
+ return pigeonResult;
+}
++ (FFSFileSelectorConfig *)fromMap:(NSDictionary *)dict {
+ FFSFileSelectorConfig *pigeonResult = [[FFSFileSelectorConfig alloc] init];
+ pigeonResult.utis = GetNullableObject(dict, @"utis");
+ NSAssert(pigeonResult.utis != nil, @"");
+ pigeonResult.allowMultiSelection = GetNullableObject(dict, @"allowMultiSelection");
+ NSAssert(pigeonResult.allowMultiSelection != nil, @"");
+ return pigeonResult;
+}
++ (nullable FFSFileSelectorConfig *)nullableFromMap:(NSDictionary *)dict {
+ return (dict) ? [FFSFileSelectorConfig fromMap:dict] : nil;
+}
+- (NSDictionary *)toMap {
+ return @{
+ @"utis" : (self.utis ?: [NSNull null]),
+ @"allowMultiSelection" : (self.allowMultiSelection ?: [NSNull null]),
+ };
+}
+@end
+
+@interface FFSFileSelectorApiCodecReader : FlutterStandardReader
+@end
+@implementation FFSFileSelectorApiCodecReader
+- (nullable id)readValueOfType:(UInt8)type {
+ switch (type) {
+ case 128:
+ return [FFSFileSelectorConfig fromMap:[self readValue]];
+
+ default:
+ return [super readValueOfType:type];
+ }
+}
+@end
+
+@interface FFSFileSelectorApiCodecWriter : FlutterStandardWriter
+@end
+@implementation FFSFileSelectorApiCodecWriter
+- (void)writeValue:(id)value {
+ if ([value isKindOfClass:[FFSFileSelectorConfig class]]) {
+ [self writeByte:128];
+ [self writeValue:[value toMap]];
+ } else {
+ [super writeValue:value];
+ }
+}
+@end
+
+@interface FFSFileSelectorApiCodecReaderWriter : FlutterStandardReaderWriter
+@end
+@implementation FFSFileSelectorApiCodecReaderWriter
+- (FlutterStandardWriter *)writerWithData:(NSMutableData *)data {
+ return [[FFSFileSelectorApiCodecWriter alloc] initWithData:data];
+}
+- (FlutterStandardReader *)readerWithData:(NSData *)data {
+ return [[FFSFileSelectorApiCodecReader alloc] initWithData:data];
+}
+@end
+
+NSObject<FlutterMessageCodec> *FFSFileSelectorApiGetCodec() {
+ static dispatch_once_t sPred = 0;
+ static FlutterStandardMessageCodec *sSharedObject = nil;
+ dispatch_once(&sPred, ^{
+ FFSFileSelectorApiCodecReaderWriter *readerWriter =
+ [[FFSFileSelectorApiCodecReaderWriter alloc] init];
+ sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter];
+ });
+ return sSharedObject;
+}
+
+void FFSFileSelectorApiSetup(id<FlutterBinaryMessenger> binaryMessenger,
+ NSObject<FFSFileSelectorApi> *api) {
+ {
+ FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
+ initWithName:@"dev.flutter.pigeon.FileSelectorApi.openFile"
+ binaryMessenger:binaryMessenger
+ codec:FFSFileSelectorApiGetCodec()];
+ if (api) {
+ NSCAssert([api respondsToSelector:@selector(openFileSelectorWithConfig:completion:)],
+ @"FFSFileSelectorApi api (%@) doesn't respond to "
+ @"@selector(openFileSelectorWithConfig:completion:)",
+ api);
+ [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
+ NSArray *args = message;
+ FFSFileSelectorConfig *arg_config = GetNullableObjectAtIndex(args, 0);
+ [api openFileSelectorWithConfig:arg_config
+ completion:^(NSArray<NSString *> *_Nullable output,
+ FlutterError *_Nullable error) {
+ callback(wrapResult(output, error));
+ }];
+ }];
+ } else {
+ [channel setMessageHandler:nil];
+ }
+ }
+}
diff --git a/packages/file_selector/file_selector_ios/ios/file_selector_ios.podspec b/packages/file_selector/file_selector_ios/ios/file_selector_ios.podspec
new file mode 100644
index 0000000..bb96b3c
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/ios/file_selector_ios.podspec
@@ -0,0 +1,24 @@
+#
+# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
+# Run `pod lib lint file_selector_ios.podspec` to validate before publishing.
+#
+Pod::Spec.new do |s|
+ s.name = 'file_selector_ios'
+ s.version = '0.0.1'
+ s.summary = 'iOS implementation of file_selector.'
+ s.description = <<-DESC
+Displays the native iOS document picker.
+ DESC
+ s.homepage = 'https://github.com/flutter/plugins/tree/main/packages/file_selector'
+ s.license = { :type => 'BSD', :file => '../LICENSE' }
+ s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
+ s.source = { :http => 'https://github.com/flutter/plugins/tree/main/packages/file_selector/file_selector_ios' }
+ s.source_files = 'Classes/**/*.{h,m}'
+ s.module_map = 'Classes/FileSelectorPlugin.modulemap'
+ s.dependency 'Flutter'
+ s.platform = :ios, '9.0'
+
+ # Flutter.framework does not contain a i386 slice.
+ s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
+ s.swift_version = '5.0'
+end
diff --git a/packages/file_selector/file_selector_ios/lib/file_selector_ios.dart b/packages/file_selector/file_selector_ios/lib/file_selector_ios.dart
new file mode 100644
index 0000000..e75f67e
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/lib/file_selector_ios.dart
@@ -0,0 +1,64 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
+
+import 'src/messages.g.dart';
+
+/// An implementation of [FileSelectorPlatform] for iOS.
+class FileSelectorIOS extends FileSelectorPlatform {
+ final FileSelectorApi _hostApi = FileSelectorApi();
+
+ /// Registers the iOS implementation.
+ static void registerWith() {
+ FileSelectorPlatform.instance = FileSelectorIOS();
+ }
+
+ @override
+ Future<XFile?> openFile({
+ List<XTypeGroup>? acceptedTypeGroups,
+ String? initialDirectory,
+ String? confirmButtonText,
+ }) async {
+ final List<String> path = (await _hostApi.openFile(FileSelectorConfig(
+ utis: _allowedUtiListFromTypeGroups(acceptedTypeGroups),
+ allowMultiSelection: false)))
+ .cast<String>();
+ return path.isEmpty ? null : XFile(path.first);
+ }
+
+ @override
+ Future<List<XFile>> openFiles({
+ List<XTypeGroup>? acceptedTypeGroups,
+ String? initialDirectory,
+ String? confirmButtonText,
+ }) async {
+ final List<String> pathList = (await _hostApi.openFile(FileSelectorConfig(
+ utis: _allowedUtiListFromTypeGroups(acceptedTypeGroups),
+ allowMultiSelection: true)))
+ .cast<String>();
+ return pathList.map((String path) => XFile(path)).toList();
+ }
+
+ // Converts the type group list into a list of all allowed UTIs, since
+ // iOS doesn't support filter groups.
+ List<String> _allowedUtiListFromTypeGroups(List<XTypeGroup>? typeGroups) {
+ if (typeGroups == null || typeGroups.isEmpty) {
+ return <String>[];
+ }
+ final List<String> allowedUTIs = <String>[];
+ for (final XTypeGroup typeGroup in typeGroups) {
+ // If any group allows everything, no filtering should be done.
+ if (typeGroup.allowsAny) {
+ return <String>[];
+ }
+ if (typeGroup.macUTIs?.isEmpty ?? true) {
+ throw ArgumentError('The provided type group $typeGroup should either '
+ 'allow all files, or have a non-empty "macUTIs"');
+ }
+ allowedUTIs.addAll(typeGroup.macUTIs!);
+ }
+ return allowedUTIs;
+ }
+}
diff --git a/packages/file_selector/file_selector_ios/lib/src/messages.g.dart b/packages/file_selector/file_selector_ios/lib/src/messages.g.dart
new file mode 100644
index 0000000..4218474
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/lib/src/messages.g.dart
@@ -0,0 +1,101 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Autogenerated from Pigeon (v3.2.5), do not edit directly.
+// See also: https://pub.dev/packages/pigeon
+// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
+import 'dart:async';
+import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List;
+
+import 'package:flutter/foundation.dart' show WriteBuffer, ReadBuffer;
+import 'package:flutter/services.dart';
+
+class FileSelectorConfig {
+ FileSelectorConfig({
+ required this.utis,
+ required this.allowMultiSelection,
+ });
+
+ List<String?> utis;
+ bool allowMultiSelection;
+
+ Object encode() {
+ final Map<Object?, Object?> pigeonMap = <Object?, Object?>{};
+ pigeonMap['utis'] = utis;
+ pigeonMap['allowMultiSelection'] = allowMultiSelection;
+ return pigeonMap;
+ }
+
+ static FileSelectorConfig decode(Object message) {
+ final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?>;
+ return FileSelectorConfig(
+ utis: (pigeonMap['utis'] as List<Object?>?)!.cast<String?>(),
+ allowMultiSelection: pigeonMap['allowMultiSelection']! as bool,
+ );
+ }
+}
+
+class _FileSelectorApiCodec extends StandardMessageCodec {
+ const _FileSelectorApiCodec();
+ @override
+ void writeValue(WriteBuffer buffer, Object? value) {
+ if (value is FileSelectorConfig) {
+ buffer.putUint8(128);
+ writeValue(buffer, value.encode());
+ } else {
+ super.writeValue(buffer, value);
+ }
+ }
+
+ @override
+ Object? readValueOfType(int type, ReadBuffer buffer) {
+ switch (type) {
+ case 128:
+ return FileSelectorConfig.decode(readValue(buffer)!);
+
+ default:
+ return super.readValueOfType(type, buffer);
+ }
+ }
+}
+
+class FileSelectorApi {
+ /// Constructor for [FileSelectorApi]. The [binaryMessenger] named argument is
+ /// available for dependency injection. If it is left null, the default
+ /// BinaryMessenger will be used which routes to the host platform.
+ FileSelectorApi({BinaryMessenger? binaryMessenger})
+ : _binaryMessenger = binaryMessenger;
+
+ final BinaryMessenger? _binaryMessenger;
+
+ static const MessageCodec<Object?> codec = _FileSelectorApiCodec();
+
+ Future<List<String?>> openFile(FileSelectorConfig arg_config) async {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.FileSelectorApi.openFile', codec,
+ binaryMessenger: _binaryMessenger);
+ final Map<Object?, Object?>? replyMap =
+ await channel.send(<Object?>[arg_config]) as Map<Object?, Object?>?;
+ if (replyMap == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ );
+ } else if (replyMap['error'] != null) {
+ final Map<Object?, Object?> error =
+ (replyMap['error'] as Map<Object?, Object?>?)!;
+ throw PlatformException(
+ code: (error['code'] as String?)!,
+ message: error['message'] as String?,
+ details: error['details'],
+ );
+ } else if (replyMap['result'] == null) {
+ throw PlatformException(
+ code: 'null-error',
+ message: 'Host platform returned null value for non-null return value.',
+ );
+ } else {
+ return (replyMap['result'] as List<Object?>?)!.cast<String?>();
+ }
+ }
+}
diff --git a/packages/file_selector/file_selector_ios/pigeons/copyright.txt b/packages/file_selector/file_selector_ios/pigeons/copyright.txt
new file mode 100644
index 0000000..fb682b1
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/pigeons/copyright.txt
@@ -0,0 +1,3 @@
+Copyright 2013 The Flutter Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
\ No newline at end of file
diff --git a/packages/file_selector/file_selector_ios/pigeons/messages.dart b/packages/file_selector/file_selector_ios/pigeons/messages.dart
new file mode 100644
index 0000000..d0ea73c
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/pigeons/messages.dart
@@ -0,0 +1,29 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:pigeon/pigeon.dart';
+
+@ConfigurePigeon(PigeonOptions(
+ dartOut: 'lib/src/messages.g.dart',
+ dartTestOut: 'test/test_api.dart',
+ objcHeaderOut: 'ios/Classes/messages.g.h',
+ objcSourceOut: 'ios/Classes/messages.g.m',
+ objcOptions: ObjcOptions(
+ prefix: 'FFS',
+ ),
+ copyrightHeader: 'pigeons/copyright.txt',
+))
+class FileSelectorConfig {
+ FileSelectorConfig(
+ {this.utis = const <String?>[], this.allowMultiSelection = false});
+ List<String?> utis;
+ bool allowMultiSelection;
+}
+
+@HostApi(dartHostTestHandler: 'TestFileSelectorApi')
+abstract class FileSelectorApi {
+ @async
+ @ObjCSelector('openFileSelectorWithConfig:')
+ List<String> openFile(FileSelectorConfig config);
+}
diff --git a/packages/file_selector/file_selector_ios/pubspec.yaml b/packages/file_selector/file_selector_ios/pubspec.yaml
new file mode 100644
index 0000000..1e4056d
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/pubspec.yaml
@@ -0,0 +1,30 @@
+name: file_selector_ios
+description: iOS implementation of the file_selector plugin.
+repository: https://github.com/flutter/plugins/tree/main/packages/file_selector/file_selector_ios
+issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22
+version: 0.5.0
+
+environment:
+ sdk: ">=2.14.4 <3.0.0"
+ flutter: ">=2.8.0"
+
+flutter:
+ plugin:
+ implements: file_selector
+ platforms:
+ ios:
+ dartPluginClass: FileSelectorIOS
+ pluginClass: FFSFileSelectorPlugin
+
+dependencies:
+ file_selector_platform_interface: ^2.1.0
+ flutter:
+ sdk: flutter
+
+dev_dependencies:
+ build_runner: 2.1.11
+ flutter_test:
+ sdk: flutter
+ mockito: ^5.1.0
+ pigeon: ^3.2.5
+
diff --git a/packages/file_selector/file_selector_ios/test/file_selector_ios_test.dart b/packages/file_selector/file_selector_ios/test/file_selector_ios_test.dart
new file mode 100644
index 0000000..f9ef406
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/test/file_selector_ios_test.dart
@@ -0,0 +1,136 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:file_selector_ios/file_selector_ios.dart';
+import 'package:file_selector_ios/src/messages.g.dart';
+import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
+
+import 'file_selector_ios_test.mocks.dart';
+import 'test_api.dart';
+
+@GenerateMocks(<Type>[TestFileSelectorApi])
+void main() {
+ TestWidgetsFlutterBinding.ensureInitialized();
+
+ final FileSelectorIOS plugin = FileSelectorIOS();
+ late MockTestFileSelectorApi mockApi;
+
+ setUp(() {
+ mockApi = MockTestFileSelectorApi();
+ TestFileSelectorApi.setup(mockApi);
+ });
+
+ test('registered instance', () {
+ FileSelectorIOS.registerWith();
+ expect(FileSelectorPlatform.instance, isA<FileSelectorIOS>());
+ });
+
+ group('openFile', () {
+ setUp(() {
+ when(mockApi.openFile(any)).thenAnswer((_) async => <String>['foo']);
+ });
+
+ test('passes the accepted type groups correctly', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'text',
+ extensions: <String>['txt'],
+ mimeTypes: <String>['text/plain'],
+ macUTIs: <String>['public.text'],
+ );
+
+ final XTypeGroup groupTwo = XTypeGroup(
+ label: 'image',
+ extensions: <String>['jpg'],
+ mimeTypes: <String>['image/jpg'],
+ macUTIs: <String>['public.image'],
+ webWildCards: <String>['image/*']);
+
+ await plugin.openFile(acceptedTypeGroups: <XTypeGroup>[group, groupTwo]);
+
+ final VerificationResult result = verify(mockApi.openFile(captureAny));
+ final FileSelectorConfig config =
+ result.captured[0] as FileSelectorConfig;
+
+ // iOS only accepts macUTIs.
+ expect(listEquals(config.utis, <String>['public.text', 'public.image']),
+ isTrue);
+ expect(config.allowMultiSelection, isFalse);
+ });
+ test('throws for a type group that does not support iOS', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'images',
+ webWildCards: <String>['images/*'],
+ );
+
+ await expectLater(
+ plugin.openFile(acceptedTypeGroups: <XTypeGroup>[group]),
+ throwsArgumentError);
+ });
+
+ test('allows a wildcard group', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'text',
+ );
+
+ await expectLater(
+ plugin.openFile(acceptedTypeGroups: <XTypeGroup>[group]), completes);
+ });
+ });
+
+ group('openFiles', () {
+ setUp(() {
+ when(mockApi.openFile(any)).thenAnswer((_) async => <String>['foo']);
+ });
+
+ test('passes the accepted type groups correctly', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'text',
+ extensions: <String>['txt'],
+ mimeTypes: <String>['text/plain'],
+ macUTIs: <String>['public.text'],
+ );
+
+ final XTypeGroup groupTwo = XTypeGroup(
+ label: 'image',
+ extensions: <String>['jpg'],
+ mimeTypes: <String>['image/jpg'],
+ macUTIs: <String>['public.image'],
+ webWildCards: <String>['image/*']);
+
+ await plugin.openFiles(acceptedTypeGroups: <XTypeGroup>[group, groupTwo]);
+
+ final VerificationResult result = verify(mockApi.openFile(captureAny));
+ final FileSelectorConfig config =
+ result.captured[0] as FileSelectorConfig;
+
+ // iOS only accepts macUTIs.
+ expect(listEquals(config.utis, <String>['public.text', 'public.image']),
+ isTrue);
+ expect(config.allowMultiSelection, isTrue);
+ });
+ test('throws for a type group that does not support iOS', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'images',
+ webWildCards: <String>['images/*'],
+ );
+
+ await expectLater(
+ plugin.openFiles(acceptedTypeGroups: <XTypeGroup>[group]),
+ throwsArgumentError);
+ });
+
+ test('allows a wildcard group', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'text',
+ );
+
+ await expectLater(
+ plugin.openFiles(acceptedTypeGroups: <XTypeGroup>[group]), completes);
+ });
+ });
+}
diff --git a/packages/file_selector/file_selector_ios/test/file_selector_ios_test.mocks.dart b/packages/file_selector/file_selector_ios/test/file_selector_ios_test.mocks.dart
new file mode 100644
index 0000000..38c91b4
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/test/file_selector_ios_test.mocks.dart
@@ -0,0 +1,38 @@
+// Mocks generated by Mockito 5.3.0 from annotations
+// in file_selector_ios/example/ios/.symlinks/plugins/file_selector_ios/test/file_selector_ios_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i3;
+
+import 'package:file_selector_ios/src/messages.g.dart' as _i4;
+import 'package:mockito/mockito.dart' as _i1;
+
+import 'test_api.dart' as _i2;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+/// A class which mocks [TestFileSelectorApi].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockTestFileSelectorApi extends _i1.Mock
+ implements _i2.TestFileSelectorApi {
+ MockTestFileSelectorApi() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i3.Future<List<String?>> openFile(_i4.FileSelectorConfig? config) =>
+ (super.noSuchMethod(Invocation.method(#openFile, [config]),
+ returnValue: _i3.Future<List<String?>>.value(<String?>[]))
+ as _i3.Future<List<String?>>);
+}
diff --git a/packages/file_selector/file_selector_ios/test/test_api.dart b/packages/file_selector/file_selector_ios/test/test_api.dart
new file mode 100644
index 0000000..69f6c19
--- /dev/null
+++ b/packages/file_selector/file_selector_ios/test/test_api.dart
@@ -0,0 +1,70 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Autogenerated from Pigeon (v3.2.5), do not edit directly.
+// See also: https://pub.dev/packages/pigeon
+// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import
+// ignore_for_file: avoid_relative_lib_imports
+import 'dart:async';
+import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List;
+import 'package:flutter/foundation.dart' show WriteBuffer, ReadBuffer;
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+// This line has been hand-edited due to
+// https://github.com/flutter/flutter/issues/97744
+// ignore: directives_ordering
+import 'package:file_selector_ios/src/messages.g.dart';
+
+class _TestFileSelectorApiCodec extends StandardMessageCodec {
+ const _TestFileSelectorApiCodec();
+ @override
+ void writeValue(WriteBuffer buffer, Object? value) {
+ if (value is FileSelectorConfig) {
+ buffer.putUint8(128);
+ writeValue(buffer, value.encode());
+ } else {
+ super.writeValue(buffer, value);
+ }
+ }
+
+ @override
+ Object? readValueOfType(int type, ReadBuffer buffer) {
+ switch (type) {
+ case 128:
+ return FileSelectorConfig.decode(readValue(buffer)!);
+
+ default:
+ return super.readValueOfType(type, buffer);
+ }
+ }
+}
+
+abstract class TestFileSelectorApi {
+ static const MessageCodec<Object?> codec = _TestFileSelectorApiCodec();
+
+ Future<List<String?>> openFile(FileSelectorConfig config);
+ static void setup(TestFileSelectorApi? api,
+ {BinaryMessenger? binaryMessenger}) {
+ {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.FileSelectorApi.openFile', codec,
+ binaryMessenger: binaryMessenger);
+ if (api == null) {
+ channel.setMockMessageHandler(null);
+ } else {
+ channel.setMockMessageHandler((Object? message) async {
+ assert(message != null,
+ 'Argument for dev.flutter.pigeon.FileSelectorApi.openFile was null.');
+ final List<Object?> args = (message as List<Object?>?)!;
+ final FileSelectorConfig? arg_config =
+ (args[0] as FileSelectorConfig?);
+ assert(arg_config != null,
+ 'Argument for dev.flutter.pigeon.FileSelectorApi.openFile was null, expected non-null FileSelectorConfig.');
+ final List<String?> output = await api.openFile(arg_config!);
+ return <Object?, Object?>{'result': output};
+ });
+ }
+ }
+ }
+}
diff --git a/script/configs/exclude_integration_ios.yaml b/script/configs/exclude_integration_ios.yaml
index 06283ae..3df22b9 100644
--- a/script/configs/exclude_integration_ios.yaml
+++ b/script/configs/exclude_integration_ios.yaml
@@ -2,3 +2,5 @@
- in_app_purchase_storekit
# Currently missing: https://github.com/flutter/flutter/issues/82208
- ios_platform_images
+# Can't use Flutter integration tests due to native modal UI.
+- file_selector_ios
\ No newline at end of file