[path_provider] Add getApplicationCachePath() (#4483)

Provides a suitable place for caching application-specific files on all supported platforms.

| Platform | Location |
|---|---|
| Android | `<app>/cache` |
| iOS | `<app>/Library/Caches` |
| Linux | `$XDG_CACHE_HOME/<app>` or `~/.cache/<app>` |
| macOS | `~/Library/Caches/<app>` or `~/Library/Containers/<app>/Data/Library/Caches/<app>` |
| Windows | `%LOCALAPPDATA%/<app>` |

Fixes: flutter/flutter#105386
diff --git a/packages/path_provider/path_provider/CHANGELOG.md b/packages/path_provider/path_provider/CHANGELOG.md
index 9f76a52..3d943fb 100644
--- a/packages/path_provider/path_provider/CHANGELOG.md
+++ b/packages/path_provider/path_provider/CHANGELOG.md
@@ -1,5 +1,6 @@
-## NEXT
+## 2.1.0
 
+* Adds getApplicationCachePath() for storing app-specific cache files.
 * Updates minimum supported macOS version to 10.14.
 * Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
 
diff --git a/packages/path_provider/path_provider/README.md b/packages/path_provider/path_provider/README.md
index 0c658f6..c76ff55 100644
--- a/packages/path_provider/path_provider/README.md
+++ b/packages/path_provider/path_provider/README.md
@@ -35,6 +35,7 @@
 | Application Support | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
 | Application Library | ❌️ | ✔️ | ❌️ | ✔️ | ❌️ |
 | Application Documents | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
+| Application Cache | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
 | External Storage | ✔️ | ❌ | ❌ | ❌️ | ❌️ |
 | External Cache Directories | ✔️ | ❌ | ❌ | ❌️ | ❌️ |
 | External Storage Directories | ✔️ | ❌ | ❌ | ❌️ | ❌️ |
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 f59a8fa..1a70c57 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
@@ -25,6 +25,11 @@
     _verifySampleFile(result, 'applicationSupport');
   });
 
+  testWidgets('getApplicationCacheDirectory', (WidgetTester tester) async {
+    final Directory result = await getApplicationCacheDirectory();
+    _verifySampleFile(result, 'applicationCache');
+  });
+
   testWidgets('getLibraryDirectory', (WidgetTester tester) async {
     if (Platform.isIOS) {
       final Directory result = await getLibraryDirectory();
diff --git a/packages/path_provider/path_provider/example/lib/main.dart b/packages/path_provider/path_provider/example/lib/main.dart
index 2863d2d..fcf0e13 100644
--- a/packages/path_provider/path_provider/example/lib/main.dart
+++ b/packages/path_provider/path_provider/example/lib/main.dart
@@ -41,6 +41,7 @@
   Future<Directory?>? _appSupportDirectory;
   Future<Directory?>? _appLibraryDirectory;
   Future<Directory?>? _appDocumentsDirectory;
+  Future<Directory?>? _appCacheDirectory;
   Future<Directory?>? _externalDocumentsDirectory;
   Future<List<Directory>?>? _externalStorageDirectories;
   Future<List<Directory>?>? _externalCacheDirectories;
@@ -102,6 +103,12 @@
     });
   }
 
+  void _requestAppCacheDirectory() {
+    setState(() {
+      _appCacheDirectory = getApplicationCacheDirectory();
+    });
+  }
+
   void _requestExternalStorageDirectory() {
     setState(() {
       _externalDocumentsDirectory = getExternalStorageDirectory();
@@ -211,6 +218,23 @@
                 Padding(
                   padding: const EdgeInsets.all(16.0),
                   child: ElevatedButton(
+                    onPressed: _requestAppCacheDirectory,
+                    child: const Text(
+                      'Get Application Cache Directory',
+                    ),
+                  ),
+                ),
+                FutureBuilder<Directory?>(
+                  future: _appCacheDirectory,
+                  builder: _buildDirectory,
+                ),
+              ],
+            ),
+            Column(
+              children: <Widget>[
+                Padding(
+                  padding: const EdgeInsets.all(16.0),
+                  child: ElevatedButton(
                     onPressed: !Platform.isAndroid
                         ? null
                         : _requestExternalStorageDirectory,
diff --git a/packages/path_provider/path_provider/example/pubspec.yaml b/packages/path_provider/path_provider/example/pubspec.yaml
index 2dafb42..5179bbf 100644
--- a/packages/path_provider/path_provider/example/pubspec.yaml
+++ b/packages/path_provider/path_provider/example/pubspec.yaml
@@ -16,7 +16,7 @@
     # 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: ../
-  path_provider_platform_interface: ^2.0.0
+  path_provider_platform_interface: ^2.1.0
 
 dev_dependencies:
   build_runner: ^2.1.10
diff --git a/packages/path_provider/path_provider/lib/path_provider.dart b/packages/path_provider/path_provider/lib/path_provider.dart
index b58a7ff..e7ab24f 100644
--- a/packages/path_provider/path_provider/lib/path_provider.dart
+++ b/packages/path_provider/path_provider/lib/path_provider.dart
@@ -107,8 +107,9 @@
 /// Path to a directory where the application may place data that is
 /// user-generated, or that cannot otherwise be recreated by your application.
 ///
-/// Consider using another path, such as [getApplicationSupportDirectory] or
-/// [getExternalStorageDirectory], if the data is not user-generated.
+/// Consider using another path, such as [getApplicationSupportDirectory],
+/// [getApplicationCacheDirectory], or [getExternalStorageDirectory], if the
+/// data is not user-generated.
 ///
 /// Example implementations:
 /// - `NSDocumentDirectory` on iOS and macOS.
@@ -125,6 +126,22 @@
   return Directory(path);
 }
 
+/// Path to a directory where the application may place application-specific
+/// cache files.
+///
+/// If this directory does not exist, it is created automatically.
+///
+/// Throws a [MissingPlatformDirectoryException] if the system is unable to
+/// provide the directory.
+Future<Directory> getApplicationCacheDirectory() async {
+  final String? path = await _platform.getApplicationCachePath();
+  if (path == null) {
+    throw MissingPlatformDirectoryException(
+        'Unable to get application cache directory');
+  }
+  return Directory(path);
+}
+
 /// Path to a directory where the application may access top level storage.
 ///
 /// Example implementation:
diff --git a/packages/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml
index 4e7326a..a450200 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/packages/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.15
+version: 2.1.0
 
 environment:
   sdk: ">=2.18.0 <4.0.0"
@@ -25,11 +25,11 @@
 dependencies:
   flutter:
     sdk: flutter
-  path_provider_android: ^2.0.6
-  path_provider_foundation: ^2.1.0
-  path_provider_linux: ^2.0.1
-  path_provider_platform_interface: ^2.0.0
-  path_provider_windows: ^2.0.2
+  path_provider_android: ^2.1.0
+  path_provider_foundation: ^2.3.0
+  path_provider_linux: ^2.2.0
+  path_provider_platform_interface: ^2.1.0
+  path_provider_windows: ^2.2.0
 
 dev_dependencies:
   flutter_test: