diff --git a/packages/path_provider/path_provider_macos/CHANGELOG.md b/packages/path_provider/path_provider_macos/CHANGELOG.md index d88ed065abb1..49c205882a1b 100644 --- a/packages/path_provider/path_provider_macos/CHANGELOG.md +++ b/packages/path_provider/path_provider_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.4 + +* Switches to a package-internal implementation of the platform interface. + ## 2.0.3 * Fixes link in README. diff --git a/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart b/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart new file mode 100644 index 000000000000..6b3a6fa81b9a --- /dev/null +++ b/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart @@ -0,0 +1,72 @@ +// 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:flutter/services.dart'; +import 'package:meta/meta.dart'; +import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; + +/// The macOS implementation of [PathProviderPlatform]. +class PathProviderMacOS extends PathProviderPlatform { + /// The method channel used to interact with the native platform. + @visibleForTesting + MethodChannel methodChannel = + const MethodChannel('plugins.flutter.io/path_provider_macos'); + + /// Registers this class as the default instance of [PathProviderPlatform] + static void registerWith() { + PathProviderPlatform.instance = PathProviderMacOS(); + } + + @override + Future getTemporaryPath() { + return methodChannel.invokeMethod('getTemporaryDirectory'); + } + + @override + Future getApplicationSupportPath() async { + final String? path = await methodChannel + .invokeMethod('getApplicationSupportDirectory'); + 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 getLibraryPath() { + return methodChannel.invokeMethod('getLibraryDirectory'); + } + + @override + Future getApplicationDocumentsPath() { + return methodChannel + .invokeMethod('getApplicationDocumentsDirectory'); + } + + @override + Future getExternalStoragePath() async { + throw UnsupportedError('getExternalStoragePath is not supported on macOS'); + } + + @override + Future?> getExternalCachePaths() async { + throw UnsupportedError('getExternalCachePaths is not supported on macOS'); + } + + @override + Future?> getExternalStoragePaths({ + StorageDirectory? type, + }) async { + throw UnsupportedError('getExternalStoragePaths is not supported on macOS'); + } + + @override + Future getDownloadsPath() { + return methodChannel.invokeMethod('getDownloadsDirectory'); + } +} diff --git a/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift b/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift index b308793be355..e138eee759ac 100644 --- a/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift +++ b/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift @@ -8,7 +8,7 @@ import Foundation public class PathProviderPlugin: NSObject, FlutterPlugin { public static func register(with registrar: FlutterPluginRegistrar) { let channel = FlutterMethodChannel( - name: "plugins.flutter.io/path_provider", + name: "plugins.flutter.io/path_provider_macos", binaryMessenger: registrar.messenger) let instance = PathProviderPlugin() registrar.addMethodCallDelegate(instance, channel: channel) @@ -25,16 +25,6 @@ public class PathProviderPlugin: NSObject, FlutterPlugin { if let basePath = path { let basePathURL = URL.init(fileURLWithPath: basePath) path = basePathURL.appendingPathComponent(Bundle.main.bundleIdentifier!).path - do { - try FileManager.default.createDirectory(atPath: path!, withIntermediateDirectories: true) - } catch { - result( - FlutterError( - code: "directory_creation_failure", - message: error.localizedDescription, - details: "\(error)")) - return - } } result(path) case "getLibraryDirectory": diff --git a/packages/path_provider/path_provider_macos/pubspec.yaml b/packages/path_provider/path_provider_macos/pubspec.yaml index ac6011d33d6d..9eb1bb4d646b 100644 --- a/packages/path_provider/path_provider_macos/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/pubspec.yaml @@ -2,7 +2,7 @@ name: path_provider_macos description: macOS implementation of the path_provider plugin repository: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_macos issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22 -version: 2.0.3 +version: 2.0.4 environment: sdk: ">=2.12.0 <3.0.0" @@ -14,10 +14,16 @@ flutter: platforms: macos: pluginClass: PathProviderPlugin + dartPluginClass: PathProviderMacOS dependencies: flutter: sdk: flutter + meta: ^1.3.0 + path_provider_platform_interface: ^2.0.1 dev_dependencies: + flutter_test: + sdk: flutter + path: ^1.8.0 pedantic: ^1.10.0 diff --git a/packages/path_provider/path_provider_macos/test/path_provider_macos_test.dart b/packages/path_provider/path_provider_macos/test/path_provider_macos_test.dart new file mode 100644 index 000000000000..7e783aad24e9 --- /dev/null +++ b/packages/path_provider/path_provider_macos/test/path_provider_macos_test.dart @@ -0,0 +1,137 @@ +// 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:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart' as p; +import 'package:path_provider_macos/path_provider_macos.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('PathProviderMacOS', () { + late PathProviderMacOS pathProvider; + late List log; + // These unit tests use the actual filesystem, since an injectable + // filesystem would add a runtime dependency to the package, so everything + // is contained to a temporary directory. + late Directory testRoot; + + late String temporaryPath; + late String applicationSupportPath; + late String libraryPath; + late String applicationDocumentsPath; + late String downloadsPath; + + setUp(() async { + pathProvider = PathProviderMacOS(); + + testRoot = Directory.systemTemp.createTempSync(); + final String basePath = testRoot.path; + temporaryPath = p.join(basePath, 'temporary', 'path'); + applicationSupportPath = + p.join(basePath, 'application', 'support', 'path'); + libraryPath = p.join(basePath, 'library', 'path'); + applicationDocumentsPath = + p.join(basePath, 'application', 'documents', 'path'); + downloadsPath = p.join(basePath, 'downloads', 'path'); + + log = []; + TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger + .setMockMethodCallHandler(pathProvider.methodChannel, + (MethodCall methodCall) async { + log.add(methodCall); + switch (methodCall.method) { + case 'getTemporaryDirectory': + return temporaryPath; + case 'getApplicationSupportDirectory': + return applicationSupportPath; + case 'getLibraryDirectory': + return libraryPath; + case 'getApplicationDocumentsDirectory': + return applicationDocumentsPath; + case 'getDownloadsDirectory': + return downloadsPath; + default: + return null; + } + }); + }); + + tearDown(() { + testRoot.deleteSync(recursive: true); + }); + + test('getTemporaryPath', () async { + final String? path = await pathProvider.getTemporaryPath(); + expect( + log, + [isMethodCall('getTemporaryDirectory', arguments: null)], + ); + expect(path, temporaryPath); + }); + + test('getApplicationSupportPath', () async { + final String? path = await pathProvider.getApplicationSupportPath(); + expect( + log, + [ + isMethodCall('getApplicationSupportDirectory', arguments: null) + ], + ); + expect(path, applicationSupportPath); + }); + + test('getApplicationSupportPath creates the directory if necessary', + () async { + final String? path = await pathProvider.getApplicationSupportPath(); + expect(Directory(path!).existsSync(), isTrue); + }); + + test('getLibraryPath', () async { + final String? path = await pathProvider.getLibraryPath(); + expect( + log, + [isMethodCall('getLibraryDirectory', arguments: null)], + ); + expect(path, libraryPath); + }); + + test('getApplicationDocumentsPath', () async { + final String? path = await pathProvider.getApplicationDocumentsPath(); + expect( + log, + [ + isMethodCall('getApplicationDocumentsDirectory', arguments: null) + ], + ); + expect(path, applicationDocumentsPath); + }); + + test('getDownloadsPath', () async { + final String? result = await pathProvider.getDownloadsPath(); + expect( + log, + [isMethodCall('getDownloadsDirectory', arguments: null)], + ); + expect(result, downloadsPath); + }); + + test('getExternalCachePaths throws', () async { + expect(pathProvider.getExternalCachePaths(), throwsA(isUnsupportedError)); + }); + + test('getExternalStoragePath throws', () async { + expect( + pathProvider.getExternalStoragePath(), throwsA(isUnsupportedError)); + }); + + test('getExternalStoragePaths throws', () async { + expect( + pathProvider.getExternalStoragePaths(), throwsA(isUnsupportedError)); + }); + }); +}