From bfea9cf5dd37b34bab051f27a69d30897c195009 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 24 Nov 2021 12:13:54 -0500 Subject: [PATCH 1/5] Add an internal method channel implementation class --- .../lib/path_provider_macos.dart | 63 +++++++++++++++++++ .../path_provider_macos/pubspec.yaml | 2 + 2 files changed, 65 insertions(+) create mode 100644 packages/path_provider/path_provider_macos/lib/path_provider_macos.dart 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..d462df299365 --- /dev/null +++ b/packages/path_provider/path_provider_macos/lib/path_provider_macos.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/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'); + + /// 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() { + return methodChannel.invokeMethod('getApplicationSupportDirectory'); + } + + @override + Future getLibraryPath() { + return methodChannel.invokeMethod('getLibraryDirectory'); + } + + @override + Future getApplicationDocumentsPath() { + return methodChannel + .invokeMethod('getApplicationDocumentsDirectory'); + } + + @override + Future getExternalStoragePath() { + throw UnsupportedError('getExternalStoragePath is not supported on macOS'); + } + + @override + Future?> getExternalCachePaths() { + 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/pubspec.yaml b/packages/path_provider/path_provider_macos/pubspec.yaml index ac6011d33d6d..e26c20e81d66 100644 --- a/packages/path_provider/path_provider_macos/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/pubspec.yaml @@ -14,10 +14,12 @@ flutter: platforms: macos: pluginClass: PathProviderPlugin + dartPluginClass: PathProviderMacOS dependencies: flutter: sdk: flutter + path_provider_platform_interface: ^2.0.1 dev_dependencies: pedantic: ^1.10.0 From d4fa7955d62327523213bd9e30aaf2b0495d351f Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 24 Nov 2021 12:14:52 -0500 Subject: [PATCH 2/5] version bump --- packages/path_provider/path_provider_macos/CHANGELOG.md | 4 ++++ packages/path_provider/path_provider_macos/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) 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/pubspec.yaml b/packages/path_provider/path_provider_macos/pubspec.yaml index e26c20e81d66..c43943aef227 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" From 2e2ae22532653991b7eca7acdef15a74375490da Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 24 Nov 2021 14:42:07 -0500 Subject: [PATCH 3/5] Add unit tests for Dart code --- .../lib/path_provider_macos.dart | 6 +- .../macos/Classes/PathProviderPlugin.swift | 2 +- .../path_provider_macos/pubspec.yaml | 2 + .../test/path_provider_macos_test.dart | 111 ++++++++++++++++++ 4 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 packages/path_provider/path_provider_macos/test/path_provider_macos_test.dart 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 index d462df299365..9ad393b1ee0a 100644 --- a/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart +++ b/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart @@ -11,7 +11,7 @@ class PathProviderMacOS extends PathProviderPlatform { /// The method channel used to interact with the native platform. @visibleForTesting MethodChannel methodChannel = - const MethodChannel('plugins.flutter.io/path_provider'); + const MethodChannel('plugins.flutter.io/path_provider_macos'); /// Registers this class as the default instance of [PathProviderPlatform] static void registerWith() { @@ -40,12 +40,12 @@ class PathProviderMacOS extends PathProviderPlatform { } @override - Future getExternalStoragePath() { + Future getExternalStoragePath() async { throw UnsupportedError('getExternalStoragePath is not supported on macOS'); } @override - Future?> getExternalCachePaths() { + Future?> getExternalCachePaths() async { throw UnsupportedError('getExternalCachePaths is not supported on macOS'); } 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..7273d8024da7 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) diff --git a/packages/path_provider/path_provider_macos/pubspec.yaml b/packages/path_provider/path_provider_macos/pubspec.yaml index c43943aef227..49d3bf7d62ec 100644 --- a/packages/path_provider/path_provider_macos/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/pubspec.yaml @@ -22,4 +22,6 @@ dependencies: path_provider_platform_interface: ^2.0.1 dev_dependencies: + flutter_test: + sdk: flutter 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..fe5fa1f7ac87 --- /dev/null +++ b/packages/path_provider/path_provider_macos/test/path_provider_macos_test.dart @@ -0,0 +1,111 @@ +// 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/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path_provider_macos/path_provider_macos.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + const String kTemporaryPath = 'temporaryPath'; + const String kApplicationSupportPath = 'applicationSupportPath'; + const String kLibraryPath = 'libraryPath'; + const String kApplicationDocumentsPath = 'applicationDocumentsPath'; + const String kDownloadsPath = 'downloadsPath'; + + group('PathProviderMacOS', () { + late PathProviderMacOS pathProvider; + final List log = []; + + setUp(() async { + pathProvider = PathProviderMacOS(); + TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger + .setMockMethodCallHandler(pathProvider.methodChannel, + (MethodCall methodCall) async { + log.add(methodCall); + switch (methodCall.method) { + case 'getTemporaryDirectory': + return kTemporaryPath; + case 'getApplicationSupportDirectory': + return kApplicationSupportPath; + case 'getLibraryDirectory': + return kLibraryPath; + case 'getApplicationDocumentsDirectory': + return kApplicationDocumentsPath; + case 'getDownloadsDirectory': + return kDownloadsPath; + default: + return null; + } + }); + }); + + tearDown(() { + log.clear(); + }); + + test('getTemporaryPath', () async { + final String? path = await pathProvider.getTemporaryPath(); + expect( + log, + [isMethodCall('getTemporaryDirectory', arguments: null)], + ); + expect(path, kTemporaryPath); + }); + + test('getApplicationSupportPath', () async { + final String? path = await pathProvider.getApplicationSupportPath(); + expect( + log, + [ + isMethodCall('getApplicationSupportDirectory', arguments: null) + ], + ); + expect(path, kApplicationSupportPath); + }); + + test('getLibraryPath', () async { + final String? path = await pathProvider.getLibraryPath(); + expect( + log, + [isMethodCall('getLibraryDirectory', arguments: null)], + ); + expect(path, kLibraryPath); + }); + + test('getApplicationDocumentsPath', () async { + final String? path = await pathProvider.getApplicationDocumentsPath(); + expect( + log, + [ + isMethodCall('getApplicationDocumentsDirectory', arguments: null) + ], + ); + expect(path, kApplicationDocumentsPath); + }); + + test('getDownloadsPath', () async { + final String? result = await pathProvider.getDownloadsPath(); + expect( + log, + [isMethodCall('getDownloadsDirectory', arguments: null)], + ); + expect(result, kDownloadsPath); + }); + + 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)); + }); + }); +} From 1b76a813cf972b7376572cecfe22726e59aaf6fd Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 25 Nov 2021 12:43:21 -0500 Subject: [PATCH 4/5] Move directory creation to the Dart side, and unit test it --- .../lib/path_provider_macos.dart | 13 +++- .../macos/Classes/PathProviderPlugin.swift | 10 ---- .../path_provider_macos/pubspec.yaml | 1 + .../test/path_provider_macos_test.dart | 60 +++++++++++++------ 4 files changed, 55 insertions(+), 29 deletions(-) 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 index 9ad393b1ee0a..6b3a6fa81b9a 100644 --- a/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart +++ b/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart @@ -2,6 +2,8 @@ // 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'; @@ -24,8 +26,15 @@ class PathProviderMacOS extends PathProviderPlatform { } @override - Future getApplicationSupportPath() { - return methodChannel.invokeMethod('getApplicationSupportDirectory'); + 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 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 7273d8024da7..e138eee759ac 100644 --- a/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift +++ b/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift @@ -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 49d3bf7d62ec..bdd9729bb6a8 100644 --- a/packages/path_provider/path_provider_macos/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/pubspec.yaml @@ -24,4 +24,5 @@ dependencies: 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 index fe5fa1f7ac87..7e783aad24e9 100644 --- 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 @@ -2,39 +2,59 @@ // 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(); - const String kTemporaryPath = 'temporaryPath'; - const String kApplicationSupportPath = 'applicationSupportPath'; - const String kLibraryPath = 'libraryPath'; - const String kApplicationDocumentsPath = 'applicationDocumentsPath'; - const String kDownloadsPath = 'downloadsPath'; group('PathProviderMacOS', () { late PathProviderMacOS pathProvider; - final List log = []; + 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 kTemporaryPath; + return temporaryPath; case 'getApplicationSupportDirectory': - return kApplicationSupportPath; + return applicationSupportPath; case 'getLibraryDirectory': - return kLibraryPath; + return libraryPath; case 'getApplicationDocumentsDirectory': - return kApplicationDocumentsPath; + return applicationDocumentsPath; case 'getDownloadsDirectory': - return kDownloadsPath; + return downloadsPath; default: return null; } @@ -42,7 +62,7 @@ void main() { }); tearDown(() { - log.clear(); + testRoot.deleteSync(recursive: true); }); test('getTemporaryPath', () async { @@ -51,7 +71,7 @@ void main() { log, [isMethodCall('getTemporaryDirectory', arguments: null)], ); - expect(path, kTemporaryPath); + expect(path, temporaryPath); }); test('getApplicationSupportPath', () async { @@ -62,7 +82,13 @@ void main() { isMethodCall('getApplicationSupportDirectory', arguments: null) ], ); - expect(path, kApplicationSupportPath); + 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 { @@ -71,7 +97,7 @@ void main() { log, [isMethodCall('getLibraryDirectory', arguments: null)], ); - expect(path, kLibraryPath); + expect(path, libraryPath); }); test('getApplicationDocumentsPath', () async { @@ -82,7 +108,7 @@ void main() { isMethodCall('getApplicationDocumentsDirectory', arguments: null) ], ); - expect(path, kApplicationDocumentsPath); + expect(path, applicationDocumentsPath); }); test('getDownloadsPath', () async { @@ -91,7 +117,7 @@ void main() { log, [isMethodCall('getDownloadsDirectory', arguments: null)], ); - expect(result, kDownloadsPath); + expect(result, downloadsPath); }); test('getExternalCachePaths throws', () async { From 4f3a5c7165a0733ddd114416e4f412d8c5cc3f36 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 26 Nov 2021 12:44:43 -0500 Subject: [PATCH 5/5] Add meta --- packages/path_provider/path_provider_macos/pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/path_provider/path_provider_macos/pubspec.yaml b/packages/path_provider/path_provider_macos/pubspec.yaml index bdd9729bb6a8..9eb1bb4d646b 100644 --- a/packages/path_provider/path_provider_macos/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/pubspec.yaml @@ -19,6 +19,7 @@ flutter: dependencies: flutter: sdk: flutter + meta: ^1.3.0 path_provider_platform_interface: ^2.0.1 dev_dependencies: