Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 86eda69

Browse files
[path_provider] Switch to Pigeon for macOS (#6635)
* [path_provider] Switch to Pigeon for macOS Converts from direct method channel use to the new experimental Swift generator. Also switches from a one-call-per-method approach to a single method with an enum, since it's easy to do that in a maintainable way with Pigeon (unlike manual method channels, where keeping enum indexes in sync across the language boundary is error-prone, and requires manual int/enum conversion). * Format * Analyzer * Update to latest version of Pigeon
1 parent b89e4fc commit 86eda69

File tree

12 files changed

+313
-135
lines changed

12 files changed

+313
-135
lines changed

packages/path_provider/path_provider_macos/CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## NEXT
1+
## 2.0.7
22

3+
* Switches platform channel implementation to Pigeon.
34
* Updates minimum Flutter version to 2.10.
45

56
## 2.0.6

packages/path_provider/path_provider_macos/example/macos/RunnerTests/RunnerTests.swift

+6-36
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,12 @@
44

55
import FlutterMacOS
66
import XCTest
7-
import path_provider_macos
7+
@testable import path_provider_macos
88

99
class RunnerTests: XCTestCase {
1010
func testGetTemporaryDirectory() throws {
1111
let plugin = PathProviderPlugin()
12-
var path: String?
13-
plugin.handle(
14-
FlutterMethodCall(methodName: "getTemporaryDirectory", arguments: nil),
15-
result: { (result: Any?) -> Void in
16-
path = result as? String
17-
18-
})
12+
let path = plugin.getDirectoryPath(type: .temp)
1913
XCTAssertEqual(
2014
path,
2115
NSSearchPathForDirectoriesInDomains(
@@ -27,13 +21,7 @@ class RunnerTests: XCTestCase {
2721

2822
func testGetApplicationDocumentsDirectory() throws {
2923
let plugin = PathProviderPlugin()
30-
var path: String?
31-
plugin.handle(
32-
FlutterMethodCall(methodName: "getApplicationDocumentsDirectory", arguments: nil),
33-
result: { (result: Any?) -> Void in
34-
path = result as? String
35-
36-
})
24+
let path = plugin.getDirectoryPath(type: .applicationDocuments)
3725
XCTAssertEqual(
3826
path,
3927
NSSearchPathForDirectoriesInDomains(
@@ -45,13 +33,7 @@ class RunnerTests: XCTestCase {
4533

4634
func testGetApplicationSupportDirectory() throws {
4735
let plugin = PathProviderPlugin()
48-
var path: String?
49-
plugin.handle(
50-
FlutterMethodCall(methodName: "getApplicationSupportDirectory", arguments: nil),
51-
result: { (result: Any?) -> Void in
52-
path = result as? String
53-
54-
})
36+
let path = plugin.getDirectoryPath(type: .applicationSupport)
5537
// The application support directory path should be the system application support
5638
// path with an added subdirectory based on the app name.
5739
XCTAssert(
@@ -66,13 +48,7 @@ class RunnerTests: XCTestCase {
6648

6749
func testGetLibraryDirectory() throws {
6850
let plugin = PathProviderPlugin()
69-
var path: String?
70-
plugin.handle(
71-
FlutterMethodCall(methodName: "getLibraryDirectory", arguments: nil),
72-
result: { (result: Any?) -> Void in
73-
path = result as? String
74-
75-
})
51+
let path = plugin.getDirectoryPath(type: .library)
7652
XCTAssertEqual(
7753
path,
7854
NSSearchPathForDirectoriesInDomains(
@@ -84,13 +60,7 @@ class RunnerTests: XCTestCase {
8460

8561
func testGetDownloadsDirectory() throws {
8662
let plugin = PathProviderPlugin()
87-
var path: String?
88-
plugin.handle(
89-
FlutterMethodCall(methodName: "getDownloadsDirectory", arguments: nil),
90-
result: { (result: Any?) -> Void in
91-
path = result as? String
92-
93-
})
63+
let path = plugin.getDirectoryPath(type: .downloads)
9464
XCTAssertEqual(
9565
path,
9666
NSSearchPathForDirectoriesInDomains(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
// Autogenerated from Pigeon (v5.0.0), do not edit directly.
5+
// See also: https://pub.dev/packages/pigeon
6+
// 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
7+
import 'dart:async';
8+
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
9+
10+
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
11+
import 'package:flutter/services.dart';
12+
13+
enum DirectoryType {
14+
applicationDocuments,
15+
applicationSupport,
16+
downloads,
17+
library,
18+
temp,
19+
}
20+
21+
class PathProviderApi {
22+
/// Constructor for [PathProviderApi]. The [binaryMessenger] named argument is
23+
/// available for dependency injection. If it is left null, the default
24+
/// BinaryMessenger will be used which routes to the host platform.
25+
PathProviderApi({BinaryMessenger? binaryMessenger})
26+
: _binaryMessenger = binaryMessenger;
27+
final BinaryMessenger? _binaryMessenger;
28+
29+
static const MessageCodec<Object?> codec = StandardMessageCodec();
30+
31+
Future<String?> getDirectoryPath(DirectoryType arg_type) async {
32+
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
33+
'dev.flutter.pigeon.PathProviderApi.getDirectoryPath', codec,
34+
binaryMessenger: _binaryMessenger);
35+
final List<Object?>? replyList =
36+
await channel.send(<Object?>[arg_type.index]) as List<Object?>?;
37+
if (replyList == null) {
38+
throw PlatformException(
39+
code: 'channel-error',
40+
message: 'Unable to establish connection on channel.',
41+
);
42+
} else if (replyList.length > 1) {
43+
throw PlatformException(
44+
code: replyList[0]! as String,
45+
message: replyList[1] as String?,
46+
details: replyList[2],
47+
);
48+
} else {
49+
return (replyList[0] as String?);
50+
}
51+
}
52+
}

packages/path_provider/path_provider_macos/lib/path_provider_macos.dart

+9-13
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,13 @@
44

55
import 'dart:io';
66

7-
import 'package:flutter/foundation.dart' show visibleForTesting;
8-
import 'package:flutter/services.dart';
97
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
108

9+
import 'messages.g.dart';
10+
1111
/// The macOS implementation of [PathProviderPlatform].
1212
class PathProviderMacOS extends PathProviderPlatform {
13-
/// The method channel used to interact with the native platform.
14-
@visibleForTesting
15-
MethodChannel methodChannel =
16-
const MethodChannel('plugins.flutter.io/path_provider_macos');
13+
final PathProviderApi _pathProvider = PathProviderApi();
1714

1815
/// Registers this class as the default instance of [PathProviderPlatform]
1916
static void registerWith() {
@@ -22,13 +19,13 @@ class PathProviderMacOS extends PathProviderPlatform {
2219

2320
@override
2421
Future<String?> getTemporaryPath() {
25-
return methodChannel.invokeMethod<String>('getTemporaryDirectory');
22+
return _pathProvider.getDirectoryPath(DirectoryType.temp);
2623
}
2724

2825
@override
2926
Future<String?> getApplicationSupportPath() async {
30-
final String? path = await methodChannel
31-
.invokeMethod<String>('getApplicationSupportDirectory');
27+
final String? path =
28+
await _pathProvider.getDirectoryPath(DirectoryType.applicationSupport);
3229
if (path != null) {
3330
// Ensure the directory exists before returning it, for consistency with
3431
// other platforms.
@@ -39,13 +36,12 @@ class PathProviderMacOS extends PathProviderPlatform {
3936

4037
@override
4138
Future<String?> getLibraryPath() {
42-
return methodChannel.invokeMethod<String>('getLibraryDirectory');
39+
return _pathProvider.getDirectoryPath(DirectoryType.library);
4340
}
4441

4542
@override
4643
Future<String?> getApplicationDocumentsPath() {
47-
return methodChannel
48-
.invokeMethod<String>('getApplicationDocumentsDirectory');
44+
return _pathProvider.getDirectoryPath(DirectoryType.applicationDocuments);
4945
}
5046

5147
@override
@@ -67,6 +63,6 @@ class PathProviderMacOS extends PathProviderPlatform {
6763

6864
@override
6965
Future<String?> getDownloadsPath() {
70-
return methodChannel.invokeMethod<String>('getDownloadsDirectory');
66+
return _pathProvider.getDirectoryPath(DirectoryType.downloads);
7167
}
7268
}

packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift

+23-21
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,41 @@
55
import FlutterMacOS
66
import Foundation
77

8-
public class PathProviderPlugin: NSObject, FlutterPlugin {
8+
public class PathProviderPlugin: NSObject, FlutterPlugin, PathProviderApi {
99
public static func register(with registrar: FlutterPluginRegistrar) {
10-
let channel = FlutterMethodChannel(
11-
name: "plugins.flutter.io/path_provider_macos",
12-
binaryMessenger: registrar.messenger)
1310
let instance = PathProviderPlugin()
14-
registrar.addMethodCallDelegate(instance, channel: channel)
11+
PathProviderApiSetup.setUp(binaryMessenger: registrar.messenger, api: instance)
1512
}
1613

17-
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
18-
switch call.method {
19-
case "getTemporaryDirectory":
20-
result(getDirectory(ofType: FileManager.SearchPathDirectory.cachesDirectory))
21-
case "getApplicationDocumentsDirectory":
22-
result(getDirectory(ofType: FileManager.SearchPathDirectory.documentDirectory))
23-
case "getApplicationSupportDirectory":
24-
var path = getDirectory(ofType: FileManager.SearchPathDirectory.applicationSupportDirectory)
14+
func getDirectoryPath(type: DirectoryType) -> String? {
15+
var path = getDirectory(ofType: fileManagerDirectoryForType(type))
16+
if type == .applicationSupport {
2517
if let basePath = path {
2618
let basePathURL = URL.init(fileURLWithPath: basePath)
2719
path = basePathURL.appendingPathComponent(Bundle.main.bundleIdentifier!).path
2820
}
29-
result(path)
30-
case "getLibraryDirectory":
31-
result(getDirectory(ofType: FileManager.SearchPathDirectory.libraryDirectory))
32-
case "getDownloadsDirectory":
33-
result(getDirectory(ofType: FileManager.SearchPathDirectory.downloadsDirectory))
34-
default:
35-
result(FlutterMethodNotImplemented)
3621
}
22+
return path
3723
}
3824
}
3925

40-
/// Returns the user-domain director of the given type.
26+
/// Returns the FileManager constant corresponding to the given type.
27+
private func fileManagerDirectoryForType(_ type: DirectoryType) -> FileManager.SearchPathDirectory {
28+
switch type {
29+
case .applicationDocuments:
30+
return FileManager.SearchPathDirectory.documentDirectory
31+
case .applicationSupport:
32+
return FileManager.SearchPathDirectory.applicationSupportDirectory
33+
case .downloads:
34+
return FileManager.SearchPathDirectory.downloadsDirectory
35+
case .library:
36+
return FileManager.SearchPathDirectory.libraryDirectory
37+
case .temp:
38+
return FileManager.SearchPathDirectory.cachesDirectory
39+
}
40+
}
41+
42+
/// Returns the user-domain directory of the given type.
4143
private func getDirectory(ofType directory: FileManager.SearchPathDirectory) -> String? {
4244
let paths = NSSearchPathForDirectoriesInDomains(
4345
directory,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
// Autogenerated from Pigeon (v5.0.0), do not edit directly.
5+
// See also: https://pub.dev/packages/pigeon
6+
7+
import Foundation
8+
#if os(iOS)
9+
import Flutter
10+
#elseif os(macOS)
11+
import FlutterMacOS
12+
#else
13+
#error("Unsupported platform.")
14+
#endif
15+
16+
17+
/// Generated class from Pigeon.
18+
19+
enum DirectoryType: Int {
20+
case applicationDocuments = 0
21+
case applicationSupport = 1
22+
case downloads = 2
23+
case library = 3
24+
case temp = 4
25+
}
26+
/// Generated protocol from Pigeon that represents a handler of messages from Flutter.
27+
protocol PathProviderApi {
28+
func getDirectoryPath(type: DirectoryType) -> String?
29+
}
30+
31+
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
32+
class PathProviderApiSetup {
33+
/// The codec used by PathProviderApi.
34+
/// Sets up an instance of `PathProviderApi` to handle messages through the `binaryMessenger`.
35+
static func setUp(binaryMessenger: FlutterBinaryMessenger, api: PathProviderApi?) {
36+
let getDirectoryPathChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.PathProviderApi.getDirectoryPath", binaryMessenger: binaryMessenger)
37+
if let api = api {
38+
getDirectoryPathChannel.setMessageHandler { message, reply in
39+
let args = message as! [Any?]
40+
let typeArg = DirectoryType(rawValue: args[0] as! Int)!
41+
let result = api.getDirectoryPath(type: typeArg)
42+
reply(wrapResult(result))
43+
}
44+
} else {
45+
getDirectoryPathChannel.setMessageHandler(nil)
46+
}
47+
}
48+
}
49+
50+
private func wrapResult(_ result: Any?) -> [Any?] {
51+
return [result]
52+
}
53+
54+
private func wrapError(_ error: FlutterError) -> [Any?] {
55+
return [
56+
error.code,
57+
error.message,
58+
error.details
59+
]
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Copyright 2013 The Flutter Authors. All rights reserved.
2+
Use of this source code is governed by a BSD-style license that can be
3+
found in the LICENSE file.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
import 'package:pigeon/pigeon.dart';
5+
6+
@ConfigurePigeon(PigeonOptions(
7+
input: 'pigeons/messages.dart',
8+
swiftOut: 'macos/Classes/messages.g.swift',
9+
dartOut: 'lib/messages.g.dart',
10+
dartTestOut: 'test/messages_test.g.dart',
11+
copyrightHeader: 'pigeons/copyright.txt',
12+
))
13+
enum DirectoryType {
14+
applicationDocuments,
15+
applicationSupport,
16+
downloads,
17+
library,
18+
temp,
19+
}
20+
21+
@HostApi(dartHostTestHandler: 'TestPathProviderApi')
22+
abstract class PathProviderApi {
23+
String? getDirectoryPath(DirectoryType type);
24+
}

packages/path_provider/path_provider_macos/pubspec.yaml

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: path_provider_macos
22
description: macOS implementation of the path_provider plugin
33
repository: https://github.com/flutter/plugins/tree/main/packages/path_provider/path_provider_macos
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22
5-
version: 2.0.6
5+
version: 2.0.7
66

77
environment:
88
sdk: ">=2.12.0 <3.0.0"
@@ -22,6 +22,9 @@ dependencies:
2222
path_provider_platform_interface: ^2.0.1
2323

2424
dev_dependencies:
25+
build_runner: ^2.3.2
2526
flutter_test:
2627
sdk: flutter
28+
mockito: ^5.3.2
2729
path: ^1.8.0
30+
pigeon: ^5.0.0

0 commit comments

Comments
 (0)