diff --git a/packages/path_provider/path_provider_foundation/CHANGELOG.md b/packages/path_provider/path_provider_foundation/CHANGELOG.md
index 1c0ffee40bf..f8f1e75dcb3 100644
--- a/packages/path_provider/path_provider_foundation/CHANGELOG.md
+++ b/packages/path_provider/path_provider_foundation/CHANGELOG.md
@@ -1,5 +1,10 @@
+## 2.5.1
+
+* Reverts to plugin-based implementation while FFI issues are investigated.
+
## 2.5.0
+* **Retracted** due to production build issues.
* Replaces Flutter-plugin-based implementation with direct FFI calls to
Foundation.
diff --git a/packages/path_provider/path_provider_foundation/CONTRIBUTING.md b/packages/path_provider/path_provider_foundation/CONTRIBUTING.md
deleted file mode 100644
index e5c45fb48bf..00000000000
--- a/packages/path_provider/path_provider_foundation/CONTRIBUTING.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# Contributing
-
-## `ffigen`
-
-This package uses [ffigen](https://pub.dev/packages/ffigen) to call Foundation
-methods, rather than using the standard Flutter plugin structure. To add new
-functionality to the FFI interface, update `tool/ffigen.dart`, then run:
-
-```bash
-dart run tool/ffigen.dart
-```
-
-### Configuration philosophy
-
-This package intentionally uses very strict filtering rules to include only the
-necessary methods and functions. This is partially to keep the package small,
-but mostly to avoid unnecessarily generating anything that requires native code
-helpers, which would require setting up a native compilation step.
diff --git a/packages/path_provider/path_provider_foundation/darwin/RunnerTests/RunnerTests.swift b/packages/path_provider/path_provider_foundation/darwin/RunnerTests/RunnerTests.swift
new file mode 100644
index 00000000000..608b7f05971
--- /dev/null
+++ b/packages/path_provider/path_provider_foundation/darwin/RunnerTests/RunnerTests.swift
@@ -0,0 +1,90 @@
+// Copyright 2013 The Flutter Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import XCTest
+
+@testable import path_provider_foundation
+
+#if os(iOS)
+ import Flutter
+#elseif os(macOS)
+ import FlutterMacOS
+#endif
+
+class RunnerTests: XCTestCase {
+ func testGetTemporaryDirectory() throws {
+ let plugin = PathProviderPlugin()
+ let path = plugin.getDirectoryPath(type: .temp)
+ XCTAssertEqual(
+ path,
+ NSSearchPathForDirectoriesInDomains(
+ FileManager.SearchPathDirectory.cachesDirectory,
+ FileManager.SearchPathDomainMask.userDomainMask,
+ true
+ ).first)
+ }
+
+ func testGetApplicationDocumentsDirectory() throws {
+ let plugin = PathProviderPlugin()
+ let path = plugin.getDirectoryPath(type: .applicationDocuments)
+ XCTAssertEqual(
+ path,
+ NSSearchPathForDirectoriesInDomains(
+ FileManager.SearchPathDirectory.documentDirectory,
+ FileManager.SearchPathDomainMask.userDomainMask,
+ true
+ ).first)
+ }
+
+ func testGetApplicationSupportDirectory() throws {
+ let plugin = PathProviderPlugin()
+ let path = plugin.getDirectoryPath(type: .applicationSupport)
+ #if os(iOS)
+ // On iOS, the application support directory path should be just the system application
+ // support path.
+ XCTAssertEqual(
+ path,
+ NSSearchPathForDirectoriesInDomains(
+ FileManager.SearchPathDirectory.applicationSupportDirectory,
+ FileManager.SearchPathDomainMask.userDomainMask,
+ true
+ ).first)
+ #else
+ // On macOS, the application support directory path should be the system application
+ // support path with an added subdirectory based on the app name.
+ XCTAssert(
+ path!.hasPrefix(
+ NSSearchPathForDirectoriesInDomains(
+ FileManager.SearchPathDirectory.applicationSupportDirectory,
+ FileManager.SearchPathDomainMask.userDomainMask,
+ true
+ ).first!))
+ XCTAssert(path!.hasSuffix("Example"))
+ #endif
+ }
+
+ func testGetLibraryDirectory() throws {
+ let plugin = PathProviderPlugin()
+ let path = plugin.getDirectoryPath(type: .library)
+ XCTAssertEqual(
+ path,
+ NSSearchPathForDirectoriesInDomains(
+ FileManager.SearchPathDirectory.libraryDirectory,
+ FileManager.SearchPathDomainMask.userDomainMask,
+ true
+ ).first)
+ }
+
+ func testGetDownloadsDirectory() throws {
+ let plugin = PathProviderPlugin()
+ let path = plugin.getDirectoryPath(type: .downloads)
+ XCTAssertEqual(
+ path,
+ NSSearchPathForDirectoriesInDomains(
+ FileManager.SearchPathDirectory.downloadsDirectory,
+ FileManager.SearchPathDomainMask.userDomainMask,
+ true
+ ).first)
+ }
+}
diff --git a/packages/path_provider/path_provider_foundation/darwin/path_provider_foundation.podspec b/packages/path_provider/path_provider_foundation/darwin/path_provider_foundation.podspec
new file mode 100644
index 00000000000..5a20d27dfc6
--- /dev/null
+++ b/packages/path_provider/path_provider_foundation/darwin/path_provider_foundation.podspec
@@ -0,0 +1,26 @@
+#
+# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
+#
+Pod::Spec.new do |s|
+ s.name = 'path_provider_foundation'
+ s.version = '0.0.1'
+ s.summary = 'An iOS and macOS implementation of the path_provider plugin.'
+ s.description = <<-DESC
+ An iOS and macOS implementation of the Flutter plugin for getting commonly used locations on the filesystem.
+ DESC
+ s.homepage = 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_foundation'
+ s.license = { :type => 'BSD', :file => '../LICENSE' }
+ s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
+ s.source = { :http => 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_foundation' }
+ s.source_files = 'path_provider_foundation/Sources/path_provider_foundation/**/*.swift'
+ s.ios.dependency 'Flutter'
+ s.osx.dependency 'FlutterMacOS'
+ s.ios.deployment_target = '13.0'
+ s.osx.deployment_target = '10.15'
+ s.ios.xcconfig = {
+ 'LIBRARY_SEARCH_PATHS' => '$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)/ $(SDKROOT)/usr/lib/swift',
+ 'LD_RUNPATH_SEARCH_PATHS' => '/usr/lib/swift',
+ }
+ s.swift_version = '5.0'
+ s.resource_bundles = {'path_provider_foundation_privacy' => ['path_provider_foundation/Sources/path_provider_foundation/Resources/PrivacyInfo.xcprivacy']}
+end
diff --git a/packages/path_provider/path_provider_foundation/darwin/path_provider_foundation/Package.swift b/packages/path_provider/path_provider_foundation/darwin/path_provider_foundation/Package.swift
new file mode 100644
index 00000000000..88e470e06a2
--- /dev/null
+++ b/packages/path_provider/path_provider_foundation/darwin/path_provider_foundation/Package.swift
@@ -0,0 +1,28 @@
+// swift-tools-version: 5.9
+
+// Copyright 2013 The Flutter Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import PackageDescription
+
+let package = Package(
+ name: "path_provider_foundation",
+ platforms: [
+ .iOS("13.0"),
+ .macOS("10.15"),
+ ],
+ products: [
+ .library(name: "path-provider-foundation", targets: ["path_provider_foundation"])
+ ],
+ dependencies: [],
+ targets: [
+ .target(
+ name: "path_provider_foundation",
+ dependencies: [],
+ resources: [
+ .process("Resources")
+ ]
+ )
+ ]
+)
diff --git a/packages/path_provider/path_provider_foundation/darwin/path_provider_foundation/Sources/path_provider_foundation/PathProviderPlugin.swift b/packages/path_provider/path_provider_foundation/darwin/path_provider_foundation/Sources/path_provider_foundation/PathProviderPlugin.swift
new file mode 100644
index 00000000000..0dc61bc8d9a
--- /dev/null
+++ b/packages/path_provider/path_provider_foundation/darwin/path_provider_foundation/Sources/path_provider_foundation/PathProviderPlugin.swift
@@ -0,0 +1,75 @@
+// Copyright 2013 The Flutter Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import Foundation
+
+#if os(iOS)
+ import Flutter
+#elseif os(macOS)
+ import FlutterMacOS
+#endif
+
+public class PathProviderPlugin: NSObject, FlutterPlugin, PathProviderApi {
+ public static func register(with registrar: FlutterPluginRegistrar) {
+ let instance = PathProviderPlugin()
+ // Workaround for https://github.com/flutter/flutter/issues/118103.
+ #if os(iOS)
+ let messenger = registrar.messenger()
+ #else
+ let messenger = registrar.messenger
+ #endif
+ PathProviderApiSetup.setUp(binaryMessenger: messenger, api: instance)
+ }
+
+ func getDirectoryPath(type: DirectoryType) -> String? {
+ var path = getDirectory(ofType: fileManagerDirectoryForType(type))
+ #if os(macOS)
+ // 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 || type == .applicationCache {
+ if let basePath = path {
+ let basePathURL = URL.init(fileURLWithPath: basePath)
+ path = basePathURL.appendingPathComponent(Bundle.main.bundleIdentifier!).path
+ }
+ }
+ #endif
+ return path
+ }
+
+ // Returns the path for the container of the specified app group.
+ func getContainerPath(appGroupIdentifier: String) -> String? {
+ return FileManager.default.containerURL(
+ forSecurityApplicationGroupIdentifier: appGroupIdentifier)?.path
+ }
+}
+
+/// 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:
+ return FileManager.SearchPathDirectory.applicationSupportDirectory
+ case .downloads:
+ return FileManager.SearchPathDirectory.downloadsDirectory
+ case .library:
+ return FileManager.SearchPathDirectory.libraryDirectory
+ case .temp:
+ return FileManager.SearchPathDirectory.cachesDirectory
+ }
+}
+
+/// Returns the user-domain directory of the given type.
+private func getDirectory(ofType directory: FileManager.SearchPathDirectory) -> String? {
+ let paths = NSSearchPathForDirectoriesInDomains(
+ directory,
+ FileManager.SearchPathDomainMask.userDomainMask,
+ true)
+ return paths.first
+}
diff --git a/packages/path_provider/path_provider_foundation/darwin/path_provider_foundation/Sources/path_provider_foundation/Resources/PrivacyInfo.xcprivacy b/packages/path_provider/path_provider_foundation/darwin/path_provider_foundation/Sources/path_provider_foundation/Resources/PrivacyInfo.xcprivacy
new file mode 100644
index 00000000000..a34b7e2e60c
--- /dev/null
+++ b/packages/path_provider/path_provider_foundation/darwin/path_provider_foundation/Sources/path_provider_foundation/Resources/PrivacyInfo.xcprivacy
@@ -0,0 +1,14 @@
+
+
+
+
+ NSPrivacyTrackingDomains
+
+ NSPrivacyAccessedAPITypes
+
+ NSPrivacyCollectedDataTypes
+
+ NSPrivacyTracking
+
+
+
diff --git a/packages/path_provider/path_provider_foundation/darwin/path_provider_foundation/Sources/path_provider_foundation/messages.g.swift b/packages/path_provider/path_provider_foundation/darwin/path_provider_foundation/Sources/path_provider_foundation/messages.g.swift
new file mode 100644
index 00000000000..3c045880dc6
--- /dev/null
+++ b/packages/path_provider/path_provider_foundation/darwin/path_provider_foundation/Sources/path_provider_foundation/messages.g.swift
@@ -0,0 +1,171 @@
+// Copyright 2013 The Flutter Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Autogenerated from Pigeon (v26.1.0), do not edit directly.
+// See also: https://pub.dev/packages/pigeon
+
+import Foundation
+
+#if os(iOS)
+ import Flutter
+#elseif os(macOS)
+ import FlutterMacOS
+#else
+ #error("Unsupported platform.")
+#endif
+
+/// Error class for passing custom error details to Dart side.
+final class PigeonError: Error {
+ let code: String
+ let message: String?
+ let details: Sendable?
+
+ init(code: String, message: String?, details: Sendable?) {
+ self.code = code
+ self.message = message
+ self.details = details
+ }
+
+ var localizedDescription: String {
+ return
+ "PigeonError(code: \(code), message: \(message ?? ""), details: \(details ?? "")"
+ }
+}
+
+private func wrapResult(_ result: Any?) -> [Any?] {
+ return [result]
+}
+
+private func wrapError(_ error: Any) -> [Any?] {
+ if let pigeonError = error as? PigeonError {
+ return [
+ pigeonError.code,
+ pigeonError.message,
+ pigeonError.details,
+ ]
+ }
+ if let flutterError = error as? FlutterError {
+ return [
+ flutterError.code,
+ flutterError.message,
+ flutterError.details,
+ ]
+ }
+ return [
+ "\(error)",
+ "\(type(of: error))",
+ "Stacktrace: \(Thread.callStackSymbols)",
+ ]
+}
+
+private func isNullish(_ value: Any?) -> Bool {
+ return value is NSNull || value == nil
+}
+
+private func nilOrValue(_ value: Any?) -> T? {
+ if value is NSNull { return nil }
+ return value as! T?
+}
+
+enum DirectoryType: Int {
+ case applicationDocuments = 0
+ case applicationSupport = 1
+ case downloads = 2
+ case library = 3
+ case temp = 4
+ case applicationCache = 5
+}
+
+private class MessagesPigeonCodecReader: FlutterStandardReader {
+ override func readValue(ofType type: UInt8) -> Any? {
+ switch type {
+ case 129:
+ let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?)
+ if let enumResultAsInt = enumResultAsInt {
+ return DirectoryType(rawValue: enumResultAsInt)
+ }
+ return nil
+ default:
+ return super.readValue(ofType: type)
+ }
+ }
+}
+
+private class MessagesPigeonCodecWriter: FlutterStandardWriter {
+ override func writeValue(_ value: Any) {
+ if let value = value as? DirectoryType {
+ super.writeByte(129)
+ super.writeValue(value.rawValue)
+ } else {
+ super.writeValue(value)
+ }
+ }
+}
+
+private class MessagesPigeonCodecReaderWriter: FlutterStandardReaderWriter {
+ override func reader(with data: Data) -> FlutterStandardReader {
+ return MessagesPigeonCodecReader(data: data)
+ }
+
+ override func writer(with data: NSMutableData) -> FlutterStandardWriter {
+ return MessagesPigeonCodecWriter(data: data)
+ }
+}
+
+class MessagesPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable {
+ static let shared = MessagesPigeonCodec(readerWriter: MessagesPigeonCodecReaderWriter())
+}
+
+/// Generated protocol from Pigeon that represents a handler of messages from Flutter.
+protocol PathProviderApi {
+ func getDirectoryPath(type: DirectoryType) throws -> String?
+ func getContainerPath(appGroupIdentifier: String) throws -> String?
+}
+
+/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
+class PathProviderApiSetup {
+ static var codec: FlutterStandardMessageCodec { MessagesPigeonCodec.shared }
+ /// Sets up an instance of `PathProviderApi` to handle messages through the `binaryMessenger`.
+ static func setUp(
+ binaryMessenger: FlutterBinaryMessenger, api: PathProviderApi?,
+ messageChannelSuffix: String = ""
+ ) {
+ let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : ""
+ let getDirectoryPathChannel = FlutterBasicMessageChannel(
+ name:
+ "dev.flutter.pigeon.path_provider_foundation.PathProviderApi.getDirectoryPath\(channelSuffix)",
+ binaryMessenger: binaryMessenger, codec: codec)
+ if let api = api {
+ getDirectoryPathChannel.setMessageHandler { message, reply in
+ let args = message as! [Any?]
+ let typeArg = args[0] as! DirectoryType
+ do {
+ let result = try api.getDirectoryPath(type: typeArg)
+ reply(wrapResult(result))
+ } catch {
+ reply(wrapError(error))
+ }
+ }
+ } else {
+ getDirectoryPathChannel.setMessageHandler(nil)
+ }
+ let getContainerPathChannel = FlutterBasicMessageChannel(
+ name:
+ "dev.flutter.pigeon.path_provider_foundation.PathProviderApi.getContainerPath\(channelSuffix)",
+ binaryMessenger: binaryMessenger, codec: codec)
+ if let api = api {
+ getContainerPathChannel.setMessageHandler { message, reply in
+ let args = message as! [Any?]
+ let appGroupIdentifierArg = args[0] as! String
+ do {
+ let result = try api.getContainerPath(appGroupIdentifier: appGroupIdentifierArg)
+ reply(wrapResult(result))
+ } catch {
+ reply(wrapError(error))
+ }
+ }
+ } else {
+ getContainerPathChannel.setMessageHandler(nil)
+ }
+ }
+}
diff --git a/packages/path_provider/path_provider_foundation/example/build.yaml b/packages/path_provider/path_provider_foundation/example/build.yaml
deleted file mode 100644
index ef6f032afd8..00000000000
--- a/packages/path_provider/path_provider_foundation/example/build.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-targets:
- $default:
- sources:
- - $package$
- - lib/$lib$
- - lib/**.dart
- - test/**.dart
- - integration_test/**.dart
- builders:
- mockito|mockBuilder:
- generate_for:
- - test/**.dart
- - integration_test/**.dart
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 9ad8b748b97..6e63e0478f9 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
@@ -5,419 +5,69 @@
import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
-import 'package:mockito/annotations.dart';
-import 'package:mockito/mockito.dart';
-import 'package:objective_c/objective_c.dart';
-import 'package:path/path.dart' as p;
-import 'package:path_provider_foundation/src/ffi_bindings.g.dart';
-import 'package:path_provider_foundation/src/path_provider_foundation_real.dart';
+import 'package:path_provider_foundation/path_provider_foundation.dart';
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
-import 'path_provider_test.mocks.dart';
-
-@GenerateNiceMocks(>[
- MockSpec(),
- MockSpec(),
- MockSpec(),
-])
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
- // This group contains standard integration tests that do end-to-end testing
- // of the calls into the platform.
- group('end-to-end', () {
- testWidgets('getTemporaryDirectory', (WidgetTester tester) async {
- final PathProviderPlatform provider = PathProviderPlatform.instance;
- final String? result = await provider.getTemporaryPath();
- _verifySampleFile(result, 'temporaryDirectory');
- });
-
- testWidgets('getApplicationDocumentsDirectory', (
- WidgetTester tester,
- ) async {
- final PathProviderPlatform provider = PathProviderPlatform.instance;
- final String? result = await provider.getApplicationDocumentsPath();
- if (Platform.isMacOS) {
- // _verifySampleFile causes hangs in driver when sandboxing is disabled
- // because the path changes from an app specific directory to
- // ~/Documents, which requires additional permissions to access on macOS.
- // Instead, validate that a non-empty path was returned.
- expect(result, isNotEmpty);
- } else {
- _verifySampleFile(result, 'applicationDocuments');
- }
- });
-
- testWidgets('getApplicationSupportDirectory', (WidgetTester tester) async {
- final PathProviderPlatform provider = PathProviderPlatform.instance;
- final String? result = await provider.getApplicationSupportPath();
- _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();
- _verifySampleFile(result, 'library');
- });
+ testWidgets('getTemporaryDirectory', (WidgetTester tester) async {
+ final PathProviderPlatform provider = PathProviderPlatform.instance;
+ final String? result = await provider.getTemporaryPath();
+ _verifySampleFile(result, 'temporaryDirectory');
+ });
- testWidgets('getDownloadsDirectory', (WidgetTester tester) async {
- final PathProviderPlatform provider = PathProviderPlatform.instance;
- final String? result = await provider.getDownloadsPath();
- // _verifySampleFile causes hangs in driver for some reason, so just
- // validate that a non-empty path was returned.
+ testWidgets('getApplicationDocumentsDirectory', (WidgetTester tester) async {
+ final PathProviderPlatform provider = PathProviderPlatform.instance;
+ final String? result = await provider.getApplicationDocumentsPath();
+ if (Platform.isMacOS) {
+ // _verifySampleFile causes hangs in driver when sandboxing is disabled
+ // because the path changes from an app specific directory to
+ // ~/Documents, which requires additional permissions to access on macOS.
+ // Instead, validate that a non-empty path was returned.
expect(result, isNotEmpty);
- });
-
- testWidgets('getContainerDirectory', (WidgetTester tester) async {
- if (Platform.isIOS) {
- final provider = PathProviderFoundation();
- final String? result = await provider.getContainerPath(
- appGroupIdentifier: 'group.flutter.appGroupTest',
- );
- _verifySampleFile(result, 'appGroup');
- }
- });
+ } else {
+ _verifySampleFile(result, 'applicationDocuments');
+ }
});
- // This group contains tests that would normally be Dart unit tests in the
- // test/ directory, but can't be because they use Objective-C types (NSURL,
- // NSString, etc.) that aren't available in an actual unit test. For these
- // tests, the platform is stubbed out.
- group('unit', () {
- final platformVariants = ValueVariant(
- {
- FakePlatformProvider(isIOS: true),
- FakePlatformProvider(isMacOS: true),
- },
- );
-
- // These 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;
-
- setUp(() async {
- testRoot = Directory.systemTemp.createTempSync();
- });
-
- tearDown(() {
- testRoot.deleteSync(recursive: true);
- });
-
- testWidgets('getTemporaryPath iOS', (_) async {
- final mockFfiLib = MockFoundationFFI();
- final pathProvider = PathProviderFoundation(
- ffiLib: mockFfiLib,
- platform: FakePlatformProvider(isIOS: true),
- );
-
- final String temporaryPath = p.join(testRoot.path, 'temporary', 'path');
- when(
- mockFfiLib.NSSearchPathForDirectoriesInDomains(
- NSSearchPathDirectory.NSCachesDirectory,
- NSSearchPathDomainMask.NSUserDomainMask,
- true,
- ),
- ).thenReturn(_arrayWithString(temporaryPath));
-
- final String? path = await pathProvider.getTemporaryPath();
-
- expect(path, temporaryPath);
- });
-
- testWidgets('getTemporaryPath macOS', (_) async {
- final mockFfiLib = MockFoundationFFI();
- final pathProvider = PathProviderFoundation(
- ffiLib: mockFfiLib,
- platform: FakePlatformProvider(isMacOS: true),
- );
-
- final String temporaryPath = p.join(testRoot.path, 'temporary', 'path');
- when(
- mockFfiLib.NSSearchPathForDirectoriesInDomains(
- NSSearchPathDirectory.NSCachesDirectory,
- NSSearchPathDomainMask.NSUserDomainMask,
- true,
- ),
- ).thenReturn(_arrayWithString(temporaryPath));
-
- final String? path = await pathProvider.getTemporaryPath();
-
- // On macOS, the bundle ID should be appended to the path.
- expect(path, '$temporaryPath/dev.flutter.plugins.pathProviderExample');
- });
-
- testWidgets('getApplicationSupportPath iOS', (_) async {
- final mockFfiLib = MockFoundationFFI();
- final pathProvider = PathProviderFoundation(
- ffiLib: mockFfiLib,
- platform: FakePlatformProvider(isIOS: true),
- );
-
- final String applicationSupportPath = p.join(
- testRoot.path,
- 'application',
- 'support',
- 'path',
- );
- when(
- mockFfiLib.NSSearchPathForDirectoriesInDomains(
- NSSearchPathDirectory.NSApplicationSupportDirectory,
- NSSearchPathDomainMask.NSUserDomainMask,
- true,
- ),
- ).thenReturn(_arrayWithString(applicationSupportPath));
-
- final String? path = await pathProvider.getApplicationSupportPath();
-
- expect(path, applicationSupportPath);
- });
-
- testWidgets('getApplicationSupportPath macOS', (_) async {
- final mockFfiLib = MockFoundationFFI();
- final pathProvider = PathProviderFoundation(
- ffiLib: mockFfiLib,
- platform: FakePlatformProvider(isMacOS: true),
- );
-
- final String applicationSupportPath = p.join(
- testRoot.path,
- 'application',
- 'support',
- 'path',
- );
- when(
- mockFfiLib.NSSearchPathForDirectoriesInDomains(
- NSSearchPathDirectory.NSApplicationSupportDirectory,
- NSSearchPathDomainMask.NSUserDomainMask,
- true,
- ),
- ).thenReturn(_arrayWithString(applicationSupportPath));
-
- final String? path = await pathProvider.getApplicationSupportPath();
-
- // On macOS, the bundle ID should be appended to the path.
- expect(
- path,
- '$applicationSupportPath/dev.flutter.plugins.pathProviderExample',
- );
- });
-
- testWidgets(
- 'getApplicationSupportPath creates the directory if necessary',
- (_) async {
- final mockFfiLib = MockFoundationFFI();
- final pathProvider = PathProviderFoundation(
- ffiLib: mockFfiLib,
- platform: platformVariants.currentValue,
- );
-
- final String applicationSupportPath = p.join(
- testRoot.path,
- 'application',
- 'support',
- 'path',
- );
- when(
- mockFfiLib.NSSearchPathForDirectoriesInDomains(
- NSSearchPathDirectory.NSApplicationSupportDirectory,
- NSSearchPathDomainMask.NSUserDomainMask,
- true,
- ),
- ).thenReturn(_arrayWithString(applicationSupportPath));
-
- final String? path = await pathProvider.getApplicationSupportPath();
-
- expect(Directory(path!).existsSync(), isTrue);
- },
- variant: platformVariants,
- );
-
- testWidgets('getLibraryPath', (_) async {
- final mockFfiLib = MockFoundationFFI();
- final pathProvider = PathProviderFoundation(
- ffiLib: mockFfiLib,
- platform: platformVariants.currentValue,
- );
-
- final String libraryPath = p.join(testRoot.path, 'library', 'path');
- when(
- mockFfiLib.NSSearchPathForDirectoriesInDomains(
- NSSearchPathDirectory.NSLibraryDirectory,
- NSSearchPathDomainMask.NSUserDomainMask,
- true,
- ),
- ).thenReturn(_arrayWithString(libraryPath));
-
- final String? path = await pathProvider.getLibraryPath();
-
- expect(path, libraryPath);
- }, variant: platformVariants);
-
- testWidgets('getApplicationDocumentsPath', (_) async {
- final mockFfiLib = MockFoundationFFI();
- final pathProvider = PathProviderFoundation(
- ffiLib: mockFfiLib,
- platform: platformVariants.currentValue,
- );
-
- final String applicationDocumentsPath = p.join(
- testRoot.path,
- 'application',
- 'documents',
- 'path',
- );
- when(
- mockFfiLib.NSSearchPathForDirectoriesInDomains(
- NSSearchPathDirectory.NSDocumentDirectory,
- NSSearchPathDomainMask.NSUserDomainMask,
- true,
- ),
- ).thenReturn(_arrayWithString(applicationDocumentsPath));
-
- final String? path = await pathProvider.getApplicationDocumentsPath();
-
- expect(path, applicationDocumentsPath);
- }, variant: platformVariants);
-
- testWidgets('getApplicationCachePath iOS', (_) async {
- final mockFfiLib = MockFoundationFFI();
- final pathProvider = PathProviderFoundation(
- ffiLib: mockFfiLib,
- platform: FakePlatformProvider(isIOS: true),
- );
-
- final String applicationCachePath = p.join(
- testRoot.path,
- 'application',
- 'cache',
- 'path',
- );
- when(
- mockFfiLib.NSSearchPathForDirectoriesInDomains(
- NSSearchPathDirectory.NSCachesDirectory,
- NSSearchPathDomainMask.NSUserDomainMask,
- true,
- ),
- ).thenReturn(_arrayWithString(applicationCachePath));
-
- final String? path = await pathProvider.getApplicationCachePath();
-
- expect(path, applicationCachePath);
- });
-
- testWidgets('getApplicationCachePath macOS', (_) async {
- final mockFfiLib = MockFoundationFFI();
- final pathProvider = PathProviderFoundation(
- ffiLib: mockFfiLib,
- platform: FakePlatformProvider(isMacOS: true),
- );
-
- final String applicationCachePath = p.join(
- testRoot.path,
- 'application',
- 'cache',
- 'path',
- );
- when(
- mockFfiLib.NSSearchPathForDirectoriesInDomains(
- NSSearchPathDirectory.NSCachesDirectory,
- NSSearchPathDomainMask.NSUserDomainMask,
- true,
- ),
- ).thenReturn(_arrayWithString(applicationCachePath));
-
- final String? path = await pathProvider.getApplicationCachePath();
-
- // On macOS, the bundle ID should be appended to the path.
- expect(
- path,
- '$applicationCachePath/dev.flutter.plugins.pathProviderExample',
- );
- });
-
- testWidgets(
- 'getApplicationCachePath creates the directory if necessary',
- (_) async {
- final mockFfiLib = MockFoundationFFI();
- final pathProvider = PathProviderFoundation(
- ffiLib: mockFfiLib,
- platform: platformVariants.currentValue,
- );
-
- final String applicationCachePath = p.join(
- testRoot.path,
- 'application',
- 'cache',
- 'path',
- );
- when(
- mockFfiLib.NSSearchPathForDirectoriesInDomains(
- NSSearchPathDirectory.NSCachesDirectory,
- NSSearchPathDomainMask.NSUserDomainMask,
- true,
- ),
- ).thenReturn(_arrayWithString(applicationCachePath));
-
- final String? path = await pathProvider.getApplicationCachePath();
-
- expect(Directory(path!).existsSync(), isTrue);
- },
- variant: platformVariants,
- );
-
- testWidgets('getDownloadsPath', (_) async {
- final mockFfiLib = MockFoundationFFI();
- final pathProvider = PathProviderFoundation(
- ffiLib: mockFfiLib,
- platform: platformVariants.currentValue,
- );
-
- final String downloadsPath = p.join(testRoot.path, 'downloads', 'path');
- when(
- mockFfiLib.NSSearchPathForDirectoriesInDomains(
- NSSearchPathDirectory.NSDownloadsDirectory,
- NSSearchPathDomainMask.NSUserDomainMask,
- true,
- ),
- ).thenReturn(_arrayWithString(downloadsPath));
-
- final String? result = await pathProvider.getDownloadsPath();
+ testWidgets('getApplicationSupportDirectory', (WidgetTester tester) async {
+ final PathProviderPlatform provider = PathProviderPlatform.instance;
+ final String? result = await provider.getApplicationSupportPath();
+ _verifySampleFile(result, 'applicationSupport');
+ });
- expect(result, downloadsPath);
- }, variant: platformVariants);
+ testWidgets('getApplicationCacheDirectory', (WidgetTester tester) async {
+ final PathProviderPlatform provider = PathProviderPlatform.instance;
+ final String? result = await provider.getApplicationCachePath();
+ _verifySampleFile(result, 'applicationCache');
+ });
- testWidgets('getContainerPath', (_) async {
- final String containerPath = p.join(testRoot.path, 'container', 'path');
- final NSURL containerUrl = NSURL.fileURLWithPath(NSString(containerPath));
+ testWidgets('getLibraryDirectory', (WidgetTester tester) async {
+ final PathProviderPlatform provider = PathProviderPlatform.instance;
+ final String? result = await provider.getLibraryPath();
+ _verifySampleFile(result, 'library');
+ });
- final mockFfiLib = MockFoundationFFI();
- final pathProvider = PathProviderFoundation(
- ffiLib: mockFfiLib,
- containerURLForSecurityApplicationGroupIdentifier: (_) => containerUrl,
- platform: FakePlatformProvider(isIOS: true),
- );
+ testWidgets('getDownloadsDirectory', (WidgetTester tester) async {
+ final PathProviderPlatform provider = PathProviderPlatform.instance;
+ final String? result = await provider.getDownloadsPath();
+ // _verifySampleFile causes hangs in driver for some reason, so just
+ // validate that a non-empty path was returned.
+ expect(result, isNotEmpty);
+ });
- const appGroupIdentifier = 'group.example.test';
- final String? result = await pathProvider.getContainerPath(
- appGroupIdentifier: appGroupIdentifier,
+ testWidgets('getContainerDirectory', (WidgetTester tester) async {
+ if (Platform.isIOS) {
+ final provider = PathProviderFoundation();
+ final String? result = await provider.getContainerPath(
+ appGroupIdentifier: 'group.flutter.appGroupTest',
);
-
- expect(result, containerPath);
- });
+ _verifySampleFile(result, 'appGroup');
+ }
});
}
-NSArray _arrayWithString(String s) {
- return NSArray.arrayWithObject(NSString(s));
-}
-
/// Verify a file called [name] in [directoryPath] by recreating it with test
/// contents when necessary.
///
@@ -440,17 +90,3 @@ void _verifySampleFile(String? directoryPath, String name) {
expect(directory.listSync(), isNotEmpty);
file.deleteSync();
}
-
-/// Fake implementation of PathProviderPlatformProvider.
-class FakePlatformProvider implements PathProviderPlatformProvider {
- FakePlatformProvider({this.isIOS = false, this.isMacOS = false})
- : assert(isIOS != isMacOS);
- @override
- bool isIOS;
-
- @override
- bool isMacOS;
-
- @override
- String toString() => isIOS ? 'iOS' : 'macOS';
-}
diff --git a/packages/path_provider/path_provider_foundation/example/integration_test/path_provider_test.mocks.dart b/packages/path_provider/path_provider_foundation/example/integration_test/path_provider_test.mocks.dart
deleted file mode 100644
index 24980d636be..00000000000
--- a/packages/path_provider/path_provider_foundation/example/integration_test/path_provider_test.mocks.dart
+++ /dev/null
@@ -1,111 +0,0 @@
-// Mocks generated by Mockito 5.4.6 from annotations
-// in path_provider_example/integration_test/path_provider_test.dart.
-// Do not manually edit this file.
-
-// ignore_for_file: no_leading_underscores_for_library_prefixes
-import 'package:mockito/mockito.dart' as _i1;
-import 'package:mockito/src/dummies.dart' as _i4;
-import 'package:objective_c/objective_c.dart' as _i2;
-import 'package:path_provider_foundation/src/ffi_bindings.g.dart' as _i3;
-import 'package:path_provider_foundation/src/path_provider_foundation_real.dart'
- as _i5;
-
-// ignore_for_file: type=lint
-// ignore_for_file: avoid_redundant_argument_values
-// ignore_for_file: avoid_setters_without_getters
-// ignore_for_file: comment_references
-// ignore_for_file: deprecated_member_use
-// ignore_for_file: deprecated_member_use_from_same_package
-// ignore_for_file: implementation_imports
-// ignore_for_file: invalid_use_of_visible_for_testing_member
-// ignore_for_file: must_be_immutable
-// ignore_for_file: prefer_const_constructors
-// ignore_for_file: unnecessary_parenthesis
-// ignore_for_file: camel_case_types
-// ignore_for_file: subtype_of_sealed_class
-// ignore_for_file: invalid_use_of_internal_member
-
-class _FakeObjCObject_0 extends _i1.SmartFake implements _i2.ObjCObject {
- _FakeObjCObject_0(Object parent, Invocation parentInvocation)
- : super(parent, parentInvocation);
-}
-
-/// A class which mocks [FoundationFFI].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockFoundationFFI extends _i1.Mock implements _i3.FoundationFFI {
- @override
- _i2.NSArray NSSearchPathForDirectoriesInDomains(
- _i3.NSSearchPathDirectory? directory,
- int? domainMask,
- bool? expandTilde,
- ) =>
- (super.noSuchMethod(
- Invocation.method(#NSSearchPathForDirectoriesInDomains, [
- directory,
- domainMask,
- expandTilde,
- ]),
- returnValue: _FakeObjCObject_0(
- this,
- Invocation.method(#NSSearchPathForDirectoriesInDomains, [
- directory,
- domainMask,
- expandTilde,
- ]),
- ),
- returnValueForMissingStub: _FakeObjCObject_0(
- this,
- Invocation.method(#NSSearchPathForDirectoriesInDomains, [
- directory,
- domainMask,
- expandTilde,
- ]),
- ),
- )
- as _i2.NSArray);
-}
-
-/// A class which mocks [ObjCObject].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockObjCObject extends _i1.Mock implements _i2.ObjCObject {
- @override
- _i2.ObjCObjectRef get ref =>
- (super.noSuchMethod(
- Invocation.getter(#ref),
- returnValue: _i4.dummyValue<_i2.ObjCObjectRef>(
- this,
- Invocation.getter(#ref),
- ),
- returnValueForMissingStub: _i4.dummyValue<_i2.ObjCObjectRef>(
- this,
- Invocation.getter(#ref),
- ),
- )
- as _i2.ObjCObjectRef);
-}
-
-/// A class which mocks [PathProviderPlatformProvider].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockPathProviderPlatformProvider extends _i1.Mock
- implements _i5.PathProviderPlatformProvider {
- @override
- bool get isIOS =>
- (super.noSuchMethod(
- Invocation.getter(#isIOS),
- returnValue: false,
- returnValueForMissingStub: false,
- )
- as bool);
-
- @override
- bool get isMacOS =>
- (super.noSuchMethod(
- Invocation.getter(#isMacOS),
- returnValue: false,
- returnValueForMissingStub: false,
- )
- as bool);
-}
diff --git a/packages/path_provider/path_provider_foundation/example/ios/Runner.xcodeproj/project.pbxproj b/packages/path_provider/path_provider_foundation/example/ios/Runner.xcodeproj/project.pbxproj
index ea6743595e0..16c8997bc44 100644
--- a/packages/path_provider/path_provider_foundation/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/packages/path_provider/path_provider_foundation/example/ios/Runner.xcodeproj/project.pbxproj
@@ -53,7 +53,6 @@
5DB8EF5A2759054360D79B8D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
- 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
86F7986E9DC17432CC8AE464 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; };
91DA83C3D33EB641BAEA3087 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
@@ -102,7 +101,6 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
- 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
@@ -203,7 +201,6 @@
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
- D4AF0CAAE697EF439AFEC08C /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -356,23 +353,6 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
- D4AF0CAAE697EF439AFEC08C /* [CP] Embed Pods Frameworks */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
- );
- name = "[CP] Embed Pods Frameworks";
- outputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
- showEnvVarsInLog = 0;
- };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -487,7 +467,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.pathProviderExample;
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.pathProviderFoundationExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@@ -661,7 +641,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.pathProviderExample;
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.pathProviderFoundationExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -684,7 +664,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.pathProviderExample;
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.pathProviderFoundationExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
diff --git a/packages/path_provider/path_provider_foundation/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/path_provider/path_provider_foundation/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index a02dac9162d..3ea14b59077 100644
--- a/packages/path_provider/path_provider_foundation/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/packages/path_provider/path_provider_foundation/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -44,7 +44,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES">
pigeonChannelCodec = _PigeonCodec();
+
+ final String pigeonVar_messageChannelSuffix;
+
+ Future getDirectoryPath(DirectoryType type) async {
+ final String pigeonVar_channelName =
+ 'dev.flutter.pigeon.path_provider_foundation.PathProviderApi.getDirectoryPath$pigeonVar_messageChannelSuffix';
+ final BasicMessageChannel