[path_provider] Switch to `path_provider_foundation` (#6989)

* [path_provider] Switch to `path_provider_foundation`

Switches to using the new combined `path_provider_foundation` for iOS
and macOS.

Also updates the code documentation to make it less Android and iOS
specific. The original goal was to make the documentation for
the download directory not be actively wrong for the new implementation,
but it seemed like a good time to fix 76427 more generally.
(The fact that the docs are kind of a mess because the API itself
is kind of a mess is now
https://github.com/flutter/flutter/issues/118712.)

Fixes flutter/flutter#117941
Fixes https://github.com/flutter/flutter/issues/76427

* Remove exclusion

* Update test expectations and README

* Update test expectations again, and update docs
diff --git a/packages/path_provider/path_provider/CHANGELOG.md b/packages/path_provider/path_provider/CHANGELOG.md
index 4365235..70916ae 100644
--- a/packages/path_provider/path_provider/CHANGELOG.md
+++ b/packages/path_provider/path_provider/CHANGELOG.md
@@ -1,5 +1,7 @@
-## NEXT
+## 2.0.12
 
+* Switches to the new `path_provider_foundation` implementation package
+  for iOS and macOS.
 * Updates code for `no_leading_underscores_for_local_identifiers` lint.
 * Updates minimum Flutter version to 2.10.
 * Fixes avoid_redundant_argument_values lint warnings and minor typos.
diff --git a/packages/path_provider/path_provider/README.md b/packages/path_provider/path_provider/README.md
index 3a52e3e..6a954d2 100644
--- a/packages/path_provider/path_provider/README.md
+++ b/packages/path_provider/path_provider/README.md
@@ -36,7 +36,7 @@
 | External Storage | ✔️ | ❌ | ❌ | ❌️ | ❌️ |
 | External Cache Directories | ✔️ | ❌ | ❌ | ❌️ | ❌️ |
 | External Storage Directories | ✔️ | ❌ | ❌ | ❌️ | ❌️ |
-| Downloads | ❌ | ❌ | ✔️ | ✔️ | ✔️ |
+| Downloads | ❌ | ✔️ | ✔️ | ✔️ | ✔️ |
 
 ## Testing
 
diff --git a/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart
index bf150f6..f59a8fa 100644
--- a/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart
+++ b/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart
@@ -87,19 +87,16 @@
   }
 
   testWidgets('getDownloadsDirectory', (WidgetTester tester) async {
-    if (Platform.isIOS || Platform.isAndroid) {
+    if (Platform.isAndroid) {
       final Future<Directory?> result = getDownloadsDirectory();
       expect(result, throwsA(isInstanceOf<UnsupportedError>()));
     } else {
       final Directory? result = await getDownloadsDirectory();
-      if (Platform.isMacOS) {
-        // On recent versions of macOS, actually using the downloads directory
-        // requires a user prompt, so will fail on CI. Instead, just check that
-        // it returned a path with the expected directory name.
-        expect(result?.path, endsWith('Downloads'));
-      } else {
-        _verifySampleFile(result, 'downloads');
-      }
+      // On recent versions of macOS, actually using the downloads directory
+      // requires a user prompt (so will fail on CI), and on some platforms the
+      // directory may not exist. Instead of verifying that it exists, just
+      // check that it returned a path.
+      expect(result?.path, isNotEmpty);
     }
   });
 }
diff --git a/packages/path_provider/path_provider/lib/path_provider.dart b/packages/path_provider/path_provider/lib/path_provider.dart
index e89d29d..b58a7ff 100644
--- a/packages/path_provider/path_provider/lib/path_provider.dart
+++ b/packages/path_provider/path_provider/lib/path_provider.dart
@@ -45,11 +45,11 @@
 /// (and cleaning up) files or directories within this directory. This
 /// directory is scoped to the calling application.
 ///
-/// On iOS, this uses the `NSCachesDirectory` API.
+/// Example implementations:
+/// - `NSCachesDirectory` on iOS and macOS.
+/// - `Context.getCacheDir` on Android.
 ///
-/// On Android, this uses the `getCacheDir` API on the context.
-///
-/// Throws a `MissingPlatformDirectoryException` if the system is unable to
+/// Throws a [MissingPlatformDirectoryException] if the system is unable to
 /// provide the directory.
 Future<Directory> getTemporaryDirectory() async {
   final String? path = await _platform.getTemporaryPath();
@@ -63,15 +63,16 @@
 /// Path to a directory where the application may place application support
 /// files.
 ///
+/// If this directory does not exist, it is created automatically.
+///
 /// Use this for files you don’t want exposed to the user. Your app should not
 /// use this directory for user data files.
 ///
-/// On iOS, this uses the `NSApplicationSupportDirectory` API.
-/// If this directory does not exist, it is created automatically.
+/// Example implementations:
+/// - `NSApplicationSupportDirectory` on iOS and macOS.
+/// - The Flutter engine's `PathUtils.getFilesDir` API on Android.
 ///
-/// On Android, this function uses the `getFilesDir` API on the context.
-///
-/// Throws a `MissingPlatformDirectoryException` if the system is unable to
+/// Throws a [MissingPlatformDirectoryException] if the system is unable to
 /// provide the directory.
 Future<Directory> getApplicationSupportDirectory() async {
   final String? path = await _platform.getApplicationSupportPath();
@@ -86,10 +87,14 @@
 /// Path to the directory where application can store files that are persistent,
 /// backed up, and not visible to the user, such as sqlite.db.
 ///
-/// On Android, this function throws an [UnsupportedError] as no equivalent
-/// path exists.
+/// Example implementations:
+/// - `NSApplicationSupportDirectory` on iOS and macOS.
 ///
-/// Throws a `MissingPlatformDirectoryException` if the system is unable to
+/// Throws an [UnsupportedError] if this is not supported on the current
+/// platform. For example, this is unlikely to ever be supported on Android,
+/// as no equivalent path exists.
+///
+/// Throws a [MissingPlatformDirectoryException] if the system is unable to
 /// provide the directory on a supported platform.
 Future<Directory> getLibraryDirectory() async {
   final String? path = await _platform.getLibraryPath();
@@ -102,14 +107,14 @@
 /// Path to a directory where the application may place data that is
 /// user-generated, or that cannot otherwise be recreated by your application.
 ///
-/// On iOS, this uses the `NSDocumentDirectory` API. Consider using
-/// [getApplicationSupportDirectory] instead if the data is not user-generated.
+/// Consider using another path, such as [getApplicationSupportDirectory] or
+/// [getExternalStorageDirectory], if the data is not user-generated.
 ///
-/// On Android, this uses the `getDataDirectory` API on the context. Consider
-/// using [getExternalStorageDirectory] instead if data is intended to be visible
-/// to the user.
+/// Example implementations:
+/// - `NSDocumentDirectory` on iOS and macOS.
+/// - The Flutter engine's `PathUtils.getDataDirectory` API on Android.
 ///
-/// Throws a `MissingPlatformDirectoryException` if the system is unable to
+/// Throws a [MissingPlatformDirectoryException] if the system is unable to
 /// provide the directory.
 Future<Directory> getApplicationDocumentsDirectory() async {
   final String? path = await _platform.getApplicationDocumentsPath();
@@ -121,13 +126,13 @@
 }
 
 /// Path to a directory where the application may access top level storage.
-/// The current operating system should be determined before issuing this
-/// function call, as this functionality is only available on Android.
 ///
-/// On iOS, this function throws an [UnsupportedError] as it is not possible
-/// to access outside the app's sandbox.
+/// Example implementation:
+/// - `getExternalFilesDir(null)` on Android.
 ///
-/// On Android this uses the `getExternalFilesDir(null)`.
+/// Throws an [UnsupportedError] if this is not supported on the current
+/// platform (for example, on iOS where it is not possible to access outside
+/// the app's sandbox).
 Future<Directory?> getExternalStorageDirectory() async {
   final String? path = await _platform.getExternalStoragePath();
   if (path == null) {
@@ -136,19 +141,19 @@
   return Directory(path);
 }
 
-/// Paths to directories where application specific external cache data can be
-/// stored. These paths typically reside on external storage like separate
-/// partitions or SD cards. Phones may have multiple storage directories
-/// available.
+/// Paths to directories where application specific cache data can be stored
+/// externally.
 ///
-/// The current operating system should be determined before issuing this
-/// function call, as this functionality is only available on Android.
+/// These paths typically reside on external storage like separate partitions
+/// or SD cards. Phones may have multiple storage directories available.
 ///
-/// On iOS, this function throws an UnsupportedError as it is not possible
-/// to access outside the app's sandbox.
+/// Example implementation:
+/// - Context.getExternalCacheDirs() on Android (or
+///   Context.getExternalCacheDir() on API levels below 19).
 ///
-/// On Android this returns Context.getExternalCacheDirs() or
-/// Context.getExternalCacheDir() on API levels below 19.
+/// Throws an [UnsupportedError] if this is not supported on the current
+/// platform. This is unlikely to ever be supported on any platform other than
+/// Android.
 Future<List<Directory>?> getExternalCacheDirectories() async {
   final List<String>? paths = await _platform.getExternalCachePaths();
   if (paths == null) {
@@ -158,18 +163,19 @@
   return paths.map((String path) => Directory(path)).toList();
 }
 
-/// Paths to directories where application specific data can be stored.
+/// Paths to directories where application specific data can be stored
+/// externally.
+///
 /// These paths typically reside on external storage like separate partitions
 /// or SD cards. Phones may have multiple storage directories available.
 ///
-/// The current operating system should be determined before issuing this
-/// function call, as this functionality is only available on Android.
+/// Example implementation:
+/// - Context.getExternalFilesDirs(type) on Android (or
+///   Context.getExternalFilesDir(type) on API levels below 19).
 ///
-/// On iOS, this function throws an UnsupportedError as it is not possible
-/// to access outside the app's sandbox.
-///
-/// On Android this returns Context.getExternalFilesDirs(String type) or
-/// Context.getExternalFilesDir(String type) on API levels below 19.
+/// Throws an [UnsupportedError] if this is not supported on the current
+/// platform. This is unlikely to ever be supported on any platform other than
+/// Android.
 Future<List<Directory>?> getExternalStorageDirectories({
   /// Optional parameter. See [StorageDirectory] for more informations on
   /// how this type translates to Android storage directories.
@@ -185,10 +191,12 @@
 }
 
 /// Path to the directory where downloaded files can be stored.
-/// This is typically only relevant on desktop operating systems.
 ///
-/// On Android and on iOS, this function throws an [UnsupportedError] as no equivalent
-/// path exists.
+/// The returned directory is not guaranteed to exist, so clients should verify
+/// that it does before using it, and potentially create it if necessary.
+///
+/// Throws an [UnsupportedError] if this is not supported on the current
+/// platform.
 Future<Directory?> getDownloadsDirectory() async {
   final String? path = await _platform.getDownloadsPath();
   if (path == null) {
diff --git a/packages/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml
index 8b68e12..ad39a3b 100644
--- a/packages/path_provider/path_provider/pubspec.yaml
+++ b/packages/path_provider/path_provider/pubspec.yaml
@@ -2,7 +2,7 @@
 description: Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories.
 repository: https://github.com/flutter/plugins/tree/main/packages/path_provider/path_provider
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22
-version: 2.0.11
+version: 2.0.12
 
 environment:
   sdk: ">=2.14.0 <3.0.0"
@@ -14,11 +14,11 @@
       android:
         default_package: path_provider_android
       ios:
-        default_package: path_provider_ios
-      macos:
-        default_package: path_provider_macos
+        default_package: path_provider_foundation
       linux:
         default_package: path_provider_linux
+      macos:
+        default_package: path_provider_foundation
       windows:
         default_package: path_provider_windows
 
@@ -26,9 +26,8 @@
   flutter:
     sdk: flutter
   path_provider_android: ^2.0.6
-  path_provider_ios: ^2.0.6
+  path_provider_foundation: ^2.1.0
   path_provider_linux: ^2.0.1
-  path_provider_macos: ^2.0.0
   path_provider_platform_interface: ^2.0.0
   path_provider_windows: ^2.0.2
 
diff --git a/script/configs/exclude_all_plugins_app.yaml b/script/configs/exclude_all_plugins_app.yaml
index c116402..8dd0fde 100644
--- a/script/configs/exclude_all_plugins_app.yaml
+++ b/script/configs/exclude_all_plugins_app.yaml
@@ -8,8 +8,3 @@
 
 # This is a permament entry, as it should never be a direct app dependency.
 - plugin_platform_interface
-# Temporarily excluded to avoid runtime conflicts with
-# path_provider_macos and _ios, which are still what path_provider
-# uses. This will be removed when the switch to path_provider_foundation
-# is complete. See https://github.com/flutter/flutter/issues/117941
-- path_provider_foundation