diff --git a/packages/path_provider/path_provider_android/CHANGELOG.md b/packages/path_provider/path_provider_android/CHANGELOG.md index 816457564de8..f829dcc73b6f 100644 --- a/packages/path_provider/path_provider_android/CHANGELOG.md +++ b/packages/path_provider/path_provider_android/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 2.1.0 +* Adds getApplicationCachePath() for storing app-specific cache files. * Updates minimum supported SDK version to Flutter 3.3/Dart 2.18. ## 2.0.27 diff --git a/packages/path_provider/path_provider_android/android/src/main/java/io/flutter/plugins/pathprovider/Messages.java b/packages/path_provider/path_provider_android/android/src/main/java/io/flutter/plugins/pathprovider/Messages.java index 11cda6b42806..1bfa729157db 100644 --- a/packages/path_provider/path_provider_android/android/src/main/java/io/flutter/plugins/pathprovider/Messages.java +++ b/packages/path_provider/path_provider_android/android/src/main/java/io/flutter/plugins/pathprovider/Messages.java @@ -1,7 +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. -// Autogenerated from Pigeon (v9.2.4), do not edit directly. +// Autogenerated from Pigeon (v9.2.5), do not edit directly. // See also: https://pub.dev/packages/pigeon package io.flutter.plugins.pathprovider; @@ -84,6 +84,9 @@ public interface PathProviderApi { @Nullable String getApplicationDocumentsPath(); + @Nullable + String getApplicationCachePath(); + @Nullable String getExternalStoragePath(); @@ -176,6 +179,31 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable PathProvid channel.setMessageHandler(null); } } + { + BinaryMessenger.TaskQueue taskQueue = binaryMessenger.makeBackgroundTaskQueue(); + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.PathProviderApi.getApplicationCachePath", + getCodec(), + taskQueue); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + try { + String output = api.getApplicationCachePath(); + wrapped.add(0, output); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } { BinaryMessenger.TaskQueue taskQueue = binaryMessenger.makeBackgroundTaskQueue(); BasicMessageChannel channel = diff --git a/packages/path_provider/path_provider_android/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java b/packages/path_provider/path_provider_android/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java index 6e259cf5128f..4ce1ba06cfb5 100644 --- a/packages/path_provider/path_provider_android/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java +++ b/packages/path_provider/path_provider_android/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java @@ -66,6 +66,11 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { return getPathProviderApplicationDocumentsDirectory(); } + @Override + public @Nullable String getApplicationCachePath() { + return context.getCacheDir().getPath(); + } + @Override public @Nullable String getExternalStoragePath() { return getPathProviderStorageDirectory(); diff --git a/packages/path_provider/path_provider_android/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_android/example/integration_test/path_provider_test.dart index ecd0b973343b..1403d932d292 100644 --- a/packages/path_provider/path_provider_android/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_android/example/integration_test/path_provider_test.dart @@ -28,6 +28,12 @@ void main() { _verifySampleFile(result, 'applicationSupport'); }); + testWidgets('getApplicationCacheDirectory', (WidgetTester tester) async { + final PathProviderPlatform provider = PathProviderPlatform.instance; + final String? result = await provider.getApplicationCachePath(); + _verifySampleFile(result, 'applicationCache'); + }); + testWidgets('getLibraryDirectory', (WidgetTester tester) async { final PathProviderPlatform provider = PathProviderPlatform.instance; expect(() => provider.getLibraryPath(), diff --git a/packages/path_provider/path_provider_android/example/lib/main.dart b/packages/path_provider/path_provider_android/example/lib/main.dart index d0bc13bc0643..79293e155c01 100644 --- a/packages/path_provider/path_provider_android/example/lib/main.dart +++ b/packages/path_provider/path_provider_android/example/lib/main.dart @@ -39,6 +39,7 @@ class _MyHomePageState extends State { Future? _tempDirectory; Future? _appSupportDirectory; Future? _appDocumentsDirectory; + Future? _appCacheDirectory; Future? _externalDocumentsDirectory; Future?>? _externalStorageDirectories; Future?>? _externalCacheDirectories; @@ -92,6 +93,12 @@ class _MyHomePageState extends State { }); } + void _requestAppCacheDirectory() { + setState(() { + _appCacheDirectory = provider.getApplicationCachePath(); + }); + } + void _requestExternalStorageDirectory() { setState(() { _externalDocumentsDirectory = provider.getExternalStoragePath(); @@ -147,6 +154,15 @@ class _MyHomePageState extends State { ), FutureBuilder( future: _appSupportDirectory, builder: _buildDirectory), + Padding( + padding: const EdgeInsets.all(16.0), + child: ElevatedButton( + onPressed: _requestAppCacheDirectory, + child: const Text('Get Application Cache Directory'), + ), + ), + FutureBuilder( + future: _appCacheDirectory, builder: _buildDirectory), Padding( padding: const EdgeInsets.all(16.0), child: ElevatedButton( diff --git a/packages/path_provider/path_provider_android/example/pubspec.yaml b/packages/path_provider/path_provider_android/example/pubspec.yaml index 852d1cd77128..df9d0e362689 100644 --- a/packages/path_provider/path_provider_android/example/pubspec.yaml +++ b/packages/path_provider/path_provider_android/example/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: # 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: flutter_test: diff --git a/packages/path_provider/path_provider_android/lib/messages.g.dart b/packages/path_provider/path_provider_android/lib/messages.g.dart index ec5c1f9506fa..20d4368d5d44 100644 --- a/packages/path_provider/path_provider_android/lib/messages.g.dart +++ b/packages/path_provider/path_provider_android/lib/messages.g.dart @@ -1,7 +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. -// Autogenerated from Pigeon (v9.2.4), do not edit directly. +// Autogenerated from Pigeon (v9.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 @@ -98,6 +98,27 @@ class PathProviderApi { } } + Future getApplicationCachePath() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.PathProviderApi.getApplicationCachePath', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return (replyList[0] as String?); + } + } + Future getExternalStoragePath() async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.PathProviderApi.getExternalStoragePath', codec, diff --git a/packages/path_provider/path_provider_android/lib/path_provider_android.dart b/packages/path_provider/path_provider_android/lib/path_provider_android.dart index f5c74f540253..c65b0abc30b9 100644 --- a/packages/path_provider/path_provider_android/lib/path_provider_android.dart +++ b/packages/path_provider/path_provider_android/lib/path_provider_android.dart @@ -62,6 +62,11 @@ class PathProviderAndroid extends PathProviderPlatform { return _api.getApplicationDocumentsPath(); } + @override + Future getApplicationCachePath() { + return _api.getApplicationCachePath(); + } + @override Future getExternalStoragePath() { return _api.getExternalStoragePath(); diff --git a/packages/path_provider/path_provider_android/pigeons/messages.dart b/packages/path_provider/path_provider_android/pigeons/messages.dart index 96ad6343d3b0..6e4eb8f1956e 100644 --- a/packages/path_provider/path_provider_android/pigeons/messages.dart +++ b/packages/path_provider/path_provider_android/pigeons/messages.dart @@ -36,6 +36,8 @@ abstract class PathProviderApi { @TaskQueue(type: TaskQueueType.serialBackgroundThread) String? getApplicationDocumentsPath(); @TaskQueue(type: TaskQueueType.serialBackgroundThread) + String? getApplicationCachePath(); + @TaskQueue(type: TaskQueueType.serialBackgroundThread) String? getExternalStoragePath(); @TaskQueue(type: TaskQueueType.serialBackgroundThread) List getExternalCachePaths(); diff --git a/packages/path_provider/path_provider_android/pubspec.yaml b/packages/path_provider/path_provider_android/pubspec.yaml index ee8317394652..42c4ba1b1a1d 100644 --- a/packages/path_provider/path_provider_android/pubspec.yaml +++ b/packages/path_provider/path_provider_android/pubspec.yaml @@ -2,7 +2,7 @@ name: path_provider_android description: Android implementation of the path_provider plugin. repository: https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22 -version: 2.0.27 +version: 2.1.0 environment: sdk: ">=2.18.0 <4.0.0" @@ -20,7 +20,7 @@ flutter: dependencies: flutter: sdk: flutter - path_provider_platform_interface: ^2.0.1 + path_provider_platform_interface: ^2.1.0 dev_dependencies: flutter_test: diff --git a/packages/path_provider/path_provider_android/test/messages_test.g.dart b/packages/path_provider/path_provider_android/test/messages_test.g.dart index 515f6b549fe1..e18fc9699969 100644 --- a/packages/path_provider/path_provider_android/test/messages_test.g.dart +++ b/packages/path_provider/path_provider_android/test/messages_test.g.dart @@ -1,7 +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. -// Autogenerated from Pigeon (v9.2.4), do not edit directly. +// Autogenerated from Pigeon (v9.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 @@ -24,6 +24,8 @@ abstract class TestPathProviderApi { String? getApplicationDocumentsPath(); + String? getApplicationCachePath(); + String? getExternalStoragePath(); List getExternalCachePaths(); @@ -84,6 +86,23 @@ abstract class TestPathProviderApi { }); } } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.PathProviderApi.getApplicationCachePath', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, + (Object? message) async { + // ignore message + final String? output = api.getApplicationCachePath(); + return [output]; + }); + } + } { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.PathProviderApi.getExternalStoragePath', codec, diff --git a/packages/path_provider/path_provider_android/test/path_provider_android_test.dart b/packages/path_provider/path_provider_android/test/path_provider_android_test.dart index e3011474a2a3..5f94da6c4f3c 100644 --- a/packages/path_provider/path_provider_android/test/path_provider_android_test.dart +++ b/packages/path_provider/path_provider_android/test/path_provider_android_test.dart @@ -12,6 +12,7 @@ const String kTemporaryPath = 'temporaryPath'; const String kApplicationSupportPath = 'applicationSupportPath'; const String kLibraryPath = 'libraryPath'; const String kApplicationDocumentsPath = 'applicationDocumentsPath'; +const String kApplicationCachePath = 'applicationCachePath'; const String kExternalCachePaths = 'externalCachePaths'; const String kExternalStoragePaths = 'externalStoragePaths'; const String kDownloadsPath = 'downloadsPath'; @@ -23,6 +24,9 @@ class _Api implements TestPathProviderApi { @override String? getApplicationSupportPath() => kApplicationSupportPath; + @override + String? getApplicationCachePath() => kApplicationCachePath; + @override List getExternalCachePaths() => [kExternalCachePaths]; @@ -58,6 +62,11 @@ void main() { expect(path, kApplicationSupportPath); }); + test('getApplicationCachePath', () async { + final String? path = await pathProvider.getApplicationCachePath(); + expect(path, kApplicationCachePath); + }); + test('getLibraryPath fails', () async { try { await pathProvider.getLibraryPath(); diff --git a/packages/path_provider/path_provider_foundation/CHANGELOG.md b/packages/path_provider/path_provider_foundation/CHANGELOG.md index 1bbba4de2215..0142c0408cbc 100644 --- a/packages/path_provider/path_provider_foundation/CHANGELOG.md +++ b/packages/path_provider/path_provider_foundation/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.3.0 + +* Adds getApplicationCachePath() for storing app-specific cache files. + ## 2.2.4 * Updates to the latest version of `pigeon`. diff --git a/packages/path_provider/path_provider_foundation/darwin/Classes/PathProviderPlugin.swift b/packages/path_provider/path_provider_foundation/darwin/Classes/PathProviderPlugin.swift index e2346b0f14b5..5530b8be026d 100644 --- a/packages/path_provider/path_provider_foundation/darwin/Classes/PathProviderPlugin.swift +++ b/packages/path_provider/path_provider_foundation/darwin/Classes/PathProviderPlugin.swift @@ -25,12 +25,12 @@ public class PathProviderPlugin: NSObject, FlutterPlugin, PathProviderApi { func getDirectoryPath(type: DirectoryType) -> String? { var path = getDirectory(ofType: fileManagerDirectoryForType(type)) #if os(macOS) - // In a non-sandboxed app, this is a shared directory where applications are + // In a non-sandboxed app, these are shared directories where applications are // expected to use its bundle ID as a subdirectory. (For non-sandboxed apps, // adding the extra path is harmless). // This is not done for iOS, for compatibility with older versions of the // plugin. - if type == .applicationSupport { + if type == .applicationSupport || type == .applicationCache { if let basePath = path { let basePathURL = URL.init(fileURLWithPath: basePath) path = basePathURL.appendingPathComponent(Bundle.main.bundleIdentifier!).path @@ -49,6 +49,8 @@ public class PathProviderPlugin: NSObject, FlutterPlugin, PathProviderApi { /// Returns the FileManager constant corresponding to the given type. private func fileManagerDirectoryForType(_ type: DirectoryType) -> FileManager.SearchPathDirectory { switch type { + case .applicationCache: + return FileManager.SearchPathDirectory.cachesDirectory case .applicationDocuments: return FileManager.SearchPathDirectory.documentDirectory case .applicationSupport: diff --git a/packages/path_provider/path_provider_foundation/darwin/Classes/messages.g.swift b/packages/path_provider/path_provider_foundation/darwin/Classes/messages.g.swift index 402e14f2d32d..4af5ac366630 100644 --- a/packages/path_provider/path_provider_foundation/darwin/Classes/messages.g.swift +++ b/packages/path_provider/path_provider_foundation/darwin/Classes/messages.g.swift @@ -44,6 +44,7 @@ enum DirectoryType: Int { case downloads = 2 case library = 3 case temp = 4 + case applicationCache = 5 } /// Generated protocol from Pigeon that represents a handler of messages from Flutter. protocol PathProviderApi { diff --git a/packages/path_provider/path_provider_foundation/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_foundation/example/integration_test/path_provider_test.dart index b67730a781fd..0d05745127aa 100644 --- a/packages/path_provider/path_provider_foundation/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_foundation/example/integration_test/path_provider_test.dart @@ -29,6 +29,12 @@ void main() { _verifySampleFile(result, 'applicationSupport'); }); + testWidgets('getApplicationCacheDirectory', (WidgetTester tester) async { + final PathProviderPlatform provider = PathProviderPlatform.instance; + final String? result = await provider.getApplicationCachePath(); + _verifySampleFile(result, 'applicationCache'); + }); + testWidgets('getLibraryDirectory', (WidgetTester tester) async { final PathProviderPlatform provider = PathProviderPlatform.instance; final String? result = await provider.getLibraryPath(); diff --git a/packages/path_provider/path_provider_foundation/example/lib/main.dart b/packages/path_provider/path_provider_foundation/example/lib/main.dart index 3e3a599f9198..c766ccf96e90 100644 --- a/packages/path_provider/path_provider_foundation/example/lib/main.dart +++ b/packages/path_provider/path_provider_foundation/example/lib/main.dart @@ -27,6 +27,7 @@ class _MyAppState extends State { String? _appSupportDirectory = 'Unknown'; String? _documentsDirectory = 'Unknown'; String? _containerDirectory = 'Unknown'; + String? _cacheDirectory = 'Unknown'; @override void initState() { @@ -42,6 +43,7 @@ class _MyAppState extends State { String? libraryDirectory; String? documentsDirectory; String? containerDirectory; + String? cacheDirectory; final PathProviderPlatform provider = PathProviderPlatform.instance; final PathProviderFoundation providerFoundation = PathProviderFoundation(); @@ -82,6 +84,12 @@ class _MyAppState extends State { 'Failed to get app group container directory: $exception'; } + try { + cacheDirectory = await provider.getApplicationCachePath(); + } catch (exception) { + cacheDirectory = 'Failed to get cache directory: $exception'; + } + setState(() { _tempDirectory = tempDirectory; _downloadsDirectory = downloadsDirectory; @@ -89,6 +97,7 @@ class _MyAppState extends State { _appSupportDirectory = appSupportDirectory; _documentsDirectory = documentsDirectory; _containerDirectory = containerDirectory; + _cacheDirectory = cacheDirectory; }); } @@ -108,6 +117,7 @@ class _MyAppState extends State { Text('Library Directory: $_libraryDirectory\n'), Text('Application Support Directory: $_appSupportDirectory\n'), Text('App Group Container Directory: $_containerDirectory\n'), + Text('Cache Directory: $_cacheDirectory\n'), ], ), ), diff --git a/packages/path_provider/path_provider_foundation/example/pubspec.yaml b/packages/path_provider/path_provider_foundation/example/pubspec.yaml index 65feace0df43..51bc61d822e1 100644 --- a/packages/path_provider/path_provider_foundation/example/pubspec.yaml +++ b/packages/path_provider/path_provider_foundation/example/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: # 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: flutter_test: diff --git a/packages/path_provider/path_provider_foundation/lib/messages.g.dart b/packages/path_provider/path_provider_foundation/lib/messages.g.dart index 7893dbd25e6c..3fdbadd5ae25 100644 --- a/packages/path_provider/path_provider_foundation/lib/messages.g.dart +++ b/packages/path_provider/path_provider_foundation/lib/messages.g.dart @@ -17,6 +17,7 @@ enum DirectoryType { downloads, library, temp, + applicationCache, } class PathProviderApi { diff --git a/packages/path_provider/path_provider_foundation/lib/path_provider_foundation.dart b/packages/path_provider/path_provider_foundation/lib/path_provider_foundation.dart index 32bbf020ea9d..55e24c4f2592 100644 --- a/packages/path_provider/path_provider_foundation/lib/path_provider_foundation.dart +++ b/packages/path_provider/path_provider_foundation/lib/path_provider_foundation.dart @@ -51,6 +51,18 @@ class PathProviderFoundation extends PathProviderPlatform { return _pathProvider.getDirectoryPath(DirectoryType.applicationDocuments); } + @override + Future getApplicationCachePath() async { + final String? path = + await _pathProvider.getDirectoryPath(DirectoryType.applicationCache); + if (path != null) { + // Ensure the directory exists before returning it, for consistency with + // other platforms. + await Directory(path).create(recursive: true); + } + return path; + } + @override Future getExternalStoragePath() async { throw UnsupportedError( diff --git a/packages/path_provider/path_provider_foundation/pigeons/messages.dart b/packages/path_provider/path_provider_foundation/pigeons/messages.dart index e3d9d0dc3b7d..ae4e7c144b35 100644 --- a/packages/path_provider/path_provider_foundation/pigeons/messages.dart +++ b/packages/path_provider/path_provider_foundation/pigeons/messages.dart @@ -16,6 +16,7 @@ enum DirectoryType { downloads, library, temp, + applicationCache, } @HostApi(dartHostTestHandler: 'TestPathProviderApi') diff --git a/packages/path_provider/path_provider_foundation/pubspec.yaml b/packages/path_provider/path_provider_foundation/pubspec.yaml index 936e182f263a..6117963b0162 100644 --- a/packages/path_provider/path_provider_foundation/pubspec.yaml +++ b/packages/path_provider/path_provider_foundation/pubspec.yaml @@ -2,7 +2,7 @@ name: path_provider_foundation description: iOS and macOS implementation of the path_provider plugin repository: https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_foundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22 -version: 2.2.4 +version: 2.3.0 environment: sdk: ">=2.18.0 <4.0.0" @@ -24,7 +24,7 @@ flutter: dependencies: flutter: sdk: flutter - path_provider_platform_interface: ^2.0.1 + path_provider_platform_interface: ^2.1.0 dev_dependencies: build_runner: ^2.3.2 diff --git a/packages/path_provider/path_provider_foundation/test/path_provider_foundation_test.dart b/packages/path_provider/path_provider_foundation/test/path_provider_foundation_test.dart index e8337a7e0948..e13e182a4132 100644 --- a/packages/path_provider/path_provider_foundation/test/path_provider_foundation_test.dart +++ b/packages/path_provider/path_provider_foundation/test/path_provider_foundation_test.dart @@ -98,6 +98,32 @@ void main() { expect(path, applicationDocumentsPath); }); + test('getApplicationCachePath', () async { + final PathProviderFoundation pathProvider = PathProviderFoundation(); + final String applicationCachePath = + p.join(testRoot.path, 'application', 'cache', 'path'); + when(mockApi.getDirectoryPath(DirectoryType.applicationCache)) + .thenReturn(applicationCachePath); + + final String? path = await pathProvider.getApplicationCachePath(); + + verify(mockApi.getDirectoryPath(DirectoryType.applicationCache)); + expect(path, applicationCachePath); + }); + + test('getApplicationCachePath creates the directory if necessary', + () async { + final PathProviderFoundation pathProvider = PathProviderFoundation(); + final String applicationCachePath = + p.join(testRoot.path, 'application', 'cache', 'path'); + when(mockApi.getDirectoryPath(DirectoryType.applicationCache)) + .thenReturn(applicationCachePath); + + final String? path = await pathProvider.getApplicationCachePath(); + + expect(Directory(path!).existsSync(), isTrue); + }); + test('getDownloadsPath', () async { final PathProviderFoundation pathProvider = PathProviderFoundation(); final String downloadsPath = p.join(testRoot.path, 'downloads', 'path'); diff --git a/packages/path_provider/path_provider_linux/CHANGELOG.md b/packages/path_provider/path_provider_linux/CHANGELOG.md index 7b4f83da3fd9..09a9d94a4558 100644 --- a/packages/path_provider/path_provider_linux/CHANGELOG.md +++ b/packages/path_provider/path_provider_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.2.0 + +* Adds getApplicationCachePath() for storing app-specific cache files. + ## 2.1.11 * Removes obsolete null checks on non-nullable values. diff --git a/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart index 3bd644f69763..3353f5617ce8 100644 --- a/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart @@ -36,6 +36,12 @@ void main() { final String? result = await provider.getApplicationSupportPath(); _verifySampleFile(result, 'applicationSupport'); }); + + testWidgets('getApplicationCacheDirectory', (WidgetTester tester) async { + final PathProviderLinux provider = PathProviderLinux(); + final String? result = await provider.getApplicationCachePath(); + _verifySampleFile(result, 'applicationCache'); + }); } /// Verify a file called [name] in [directoryPath] by recreating it with test diff --git a/packages/path_provider/path_provider_linux/example/lib/main.dart b/packages/path_provider/path_provider_linux/example/lib/main.dart index 254360cae4ee..3cbb6915277f 100644 --- a/packages/path_provider/path_provider_linux/example/lib/main.dart +++ b/packages/path_provider/path_provider_linux/example/lib/main.dart @@ -23,6 +23,7 @@ class _MyAppState extends State { String? _tempDirectory = 'Unknown'; String? _downloadsDirectory = 'Unknown'; String? _appSupportDirectory = 'Unknown'; + String? _appCacheDirectory = 'Unknown'; String? _documentsDirectory = 'Unknown'; final PathProviderLinux _provider = PathProviderLinux(); @@ -37,6 +38,7 @@ class _MyAppState extends State { String? tempDirectory; String? downloadsDirectory; String? appSupportDirectory; + String? appCacheDirectory; String? documentsDirectory; // Platform messages may fail, so we use a try/catch PlatformException. try { @@ -61,6 +63,12 @@ class _MyAppState extends State { } on PlatformException { appSupportDirectory = 'Failed to get documents directory.'; } + + try { + appCacheDirectory = await _provider.getApplicationCachePath(); + } on PlatformException { + appCacheDirectory = 'Failed to get cache directory.'; + } // If the widget was removed from the tree while the asynchronous platform // message was in flight, we want to discard the reply rather than calling // setState to update our non-existent appearance. @@ -72,6 +80,7 @@ class _MyAppState extends State { _tempDirectory = tempDirectory; _downloadsDirectory = downloadsDirectory; _appSupportDirectory = appSupportDirectory; + _appCacheDirectory = appCacheDirectory; _documentsDirectory = documentsDirectory; }); } @@ -90,6 +99,7 @@ class _MyAppState extends State { Text('Documents Directory: $_documentsDirectory\n'), Text('Downloads Directory: $_downloadsDirectory\n'), Text('Application Support Directory: $_appSupportDirectory\n'), + Text('Application Cache Directory: $_appCacheDirectory\n'), ], ), ), diff --git a/packages/path_provider/path_provider_linux/lib/src/path_provider_linux.dart b/packages/path_provider/path_provider_linux/lib/src/path_provider_linux.dart index 1544dcea2984..59097114d3ad 100644 --- a/packages/path_provider/path_provider_linux/lib/src/path_provider_linux.dart +++ b/packages/path_provider/path_provider_linux/lib/src/path_provider_linux.dart @@ -71,6 +71,16 @@ class PathProviderLinux extends PathProviderPlatform { return Future.value(xdg.getUserDirectory('DOCUMENTS')?.path); } + @override + Future getApplicationCachePath() async { + final Directory directory = + Directory(path.join(xdg.cacheHome.path, await _getId())); + if (!directory.existsSync()) { + await directory.create(recursive: true); + } + return directory.path; + } + @override Future getDownloadsPath() { return Future.value(xdg.getUserDirectory('DOWNLOAD')?.path); diff --git a/packages/path_provider/path_provider_linux/pubspec.yaml b/packages/path_provider/path_provider_linux/pubspec.yaml index a72228fd93d4..b1c3e7fab8c3 100644 --- a/packages/path_provider/path_provider_linux/pubspec.yaml +++ b/packages/path_provider/path_provider_linux/pubspec.yaml @@ -2,7 +2,7 @@ name: path_provider_linux description: Linux implementation of the path_provider plugin repository: https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_linux issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22 -version: 2.1.11 +version: 2.2.0 environment: sdk: ">=2.18.0 <4.0.0" @@ -20,7 +20,7 @@ dependencies: flutter: sdk: flutter path: ^1.8.0 - path_provider_platform_interface: ^2.0.0 + path_provider_platform_interface: ^2.1.0 xdg_directories: ">=0.2.0 <2.0.0" dev_dependencies: diff --git a/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart b/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart index 1f567c00513d..b5dfcce15012 100644 --- a/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart +++ b/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart @@ -57,6 +57,13 @@ void main() { expect(await plugin.getApplicationDocumentsPath(), startsWith('/')); }); + test('getApplicationCachePath', () async { + final PathProviderPlatform plugin = PathProviderLinux.private( + executableName: 'path_provider_linux_test_binary'); + expect(await plugin.getApplicationCachePath(), + '${xdg.cacheHome.path}/path_provider_linux_test_binary'); + }); + test('getDownloadsPath', () async { final PathProviderPlatform plugin = PathProviderPlatform.instance; expect(await plugin.getDownloadsPath(), startsWith('/')); diff --git a/packages/path_provider/path_provider_windows/CHANGELOG.md b/packages/path_provider/path_provider_windows/CHANGELOG.md index 6011789c0c01..04a201f11280 100644 --- a/packages/path_provider/path_provider_windows/CHANGELOG.md +++ b/packages/path_provider/path_provider_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.2.0 + +* Adds getApplicationCachePath() for storing app-specific cache files. + ## 2.1.7 * Adds compatibility with `win32` 5.x. diff --git a/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart index a8285963adb6..0e900224be7a 100644 --- a/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart @@ -28,6 +28,12 @@ void main() { _verifySampleFile(result, 'applicationSupport'); }); + testWidgets('getApplicationCacheDirectory', (WidgetTester tester) async { + final PathProviderWindows provider = PathProviderWindows(); + final String? result = await provider.getApplicationCachePath(); + _verifySampleFile(result, 'applicationCache'); + }); + testWidgets('getDownloadsDirectory', (WidgetTester tester) async { final PathProviderWindows provider = PathProviderWindows(); final String? result = await provider.getDownloadsPath(); diff --git a/packages/path_provider/path_provider_windows/example/lib/main.dart b/packages/path_provider/path_provider_windows/example/lib/main.dart index e910732eb868..53e46e517d06 100644 --- a/packages/path_provider/path_provider_windows/example/lib/main.dart +++ b/packages/path_provider/path_provider_windows/example/lib/main.dart @@ -24,6 +24,7 @@ class _MyAppState extends State { String? _downloadsDirectory = 'Unknown'; String? _appSupportDirectory = 'Unknown'; String? _documentsDirectory = 'Unknown'; + String? _cacheDirectory = 'Unknown'; @override void initState() { @@ -37,6 +38,7 @@ class _MyAppState extends State { String? downloadsDirectory; String? appSupportDirectory; String? documentsDirectory; + String? cacheDirectory; final PathProviderWindows provider = PathProviderWindows(); try { @@ -62,11 +64,18 @@ class _MyAppState extends State { appSupportDirectory = 'Failed to get app support directory: $exception'; } + try { + cacheDirectory = await provider.getApplicationCachePath(); + } catch (exception) { + cacheDirectory = 'Failed to get cache directory: $exception'; + } + setState(() { _tempDirectory = tempDirectory; _downloadsDirectory = downloadsDirectory; _appSupportDirectory = appSupportDirectory; _documentsDirectory = documentsDirectory; + _cacheDirectory = cacheDirectory; }); } @@ -84,6 +93,7 @@ class _MyAppState extends State { Text('Documents Directory: $_documentsDirectory\n'), Text('Downloads Directory: $_downloadsDirectory\n'), Text('Application Support Directory: $_appSupportDirectory\n'), + Text('Cache Directory: $_cacheDirectory\n'), ], ), ), diff --git a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart index 691d7a2da84b..2faa599a5341 100644 --- a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart +++ b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart @@ -114,30 +114,17 @@ class PathProviderWindows extends PathProviderPlatform { } @override - Future getApplicationSupportPath() async { - final String? appDataRoot = - await getPath(WindowsKnownFolder.RoamingAppData); - if (appDataRoot == null) { - return null; - } - final Directory directory = Directory( - path.join(appDataRoot, _getApplicationSpecificSubdirectory())); - // Ensure that the directory exists if possible, since it will on other - // platforms. If the name is longer than MAXPATH, creating will fail, so - // skip that step; it's up to the client to decide what to do with the path - // in that case (e.g., using a short path). - if (directory.path.length <= MAX_PATH) { - if (!directory.existsSync()) { - await directory.create(recursive: true); - } - } - return directory.path; - } + Future getApplicationSupportPath() => + _createApplicationSubdirectory(WindowsKnownFolder.RoamingAppData); @override Future getApplicationDocumentsPath() => getPath(WindowsKnownFolder.Documents); + @override + Future getApplicationCachePath() => + _createApplicationSubdirectory(WindowsKnownFolder.LocalAppData); + @override Future getDownloadsPath() => getPath(WindowsKnownFolder.Downloads); @@ -256,4 +243,23 @@ class PathProviderWindows extends PathProviderPlatform { } return sanitized.isEmpty ? null : sanitized; } + + Future _createApplicationSubdirectory(String folderId) async { + final String? baseDir = await getPath(folderId); + if (baseDir == null) { + return null; + } + final Directory directory = + Directory(path.join(baseDir, _getApplicationSpecificSubdirectory())); + // Ensure that the directory exists if possible, since it will on other + // platforms. If the name is longer than MAXPATH, creating will fail, so + // skip that step; it's up to the client to decide what to do with the path + // in that case (e.g., using a short path). + if (directory.path.length <= MAX_PATH) { + if (!directory.existsSync()) { + await directory.create(recursive: true); + } + } + return directory.path; + } } diff --git a/packages/path_provider/path_provider_windows/pubspec.yaml b/packages/path_provider/path_provider_windows/pubspec.yaml index 4e00b93cd4f6..8062aa5604ee 100644 --- a/packages/path_provider/path_provider_windows/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/pubspec.yaml @@ -2,7 +2,7 @@ name: path_provider_windows description: Windows implementation of the path_provider plugin repository: https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_windows issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22 -version: 2.1.7 +version: 2.2.0 environment: sdk: ">=2.18.0 <4.0.0" @@ -20,7 +20,7 @@ dependencies: flutter: sdk: flutter path: ^1.8.0 - path_provider_platform_interface: ^2.0.0 + path_provider_platform_interface: ^2.1.0 win32: ">=2.1.0 <6.0.0" dev_dependencies: diff --git a/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart b/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart index 48e56406c14f..dd8fead6668c 100644 --- a/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart +++ b/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart @@ -165,6 +165,20 @@ void main() { expect(path, contains(r'Documents')); }, skip: !Platform.isWindows); + test('getApplicationCachePath', () async { + final PathProviderWindows pathProvider = PathProviderWindows(); + pathProvider.versionInfoQuerier = FakeVersionInfoQuerier({ + 'CompanyName': 'A Company', + 'ProductName': 'Amazing App', + }, encoding: encodingCP1252); + final String? path = await pathProvider.getApplicationCachePath(); + expect(path, isNotNull); + if (path != null) { + expect(path, endsWith(r'AppData\Local\A Company\Amazing App')); + expect(Directory(path).existsSync(), isTrue); + } + }, skip: !Platform.isWindows); + test('getDownloadsPath', () async { final PathProviderWindows pathProvider = PathProviderWindows(); final String? path = await pathProvider.getDownloadsPath();