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

Commit 470b302

Browse files
[path_provider] Switch iOS to an internal method channel (#4921)
1 parent 4cfcb4c commit 470b302

File tree

5 files changed

+210
-24
lines changed

5 files changed

+210
-24
lines changed

packages/path_provider/path_provider_ios/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.0.8
2+
3+
* Switches to a package-internal implementation of the platform interface.
4+
15
## 2.0.7
26

37
* Fixes link in README.

packages/path_provider/path_provider_ios/ios/Classes/FLTPathProviderPlugin.m

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,19 @@
99
return paths.firstObject;
1010
}
1111

12-
static FlutterError *getFlutterError(NSError *error) {
13-
if (error == nil) return nil;
14-
return [FlutterError errorWithCode:[NSString stringWithFormat:@"Error %ld", (long)error.code]
15-
message:error.domain
16-
details:error.localizedDescription];
17-
}
18-
1912
@implementation FLTPathProviderPlugin
2013

2114
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
2215
FlutterMethodChannel *channel =
23-
[FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/path_provider"
16+
[FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/path_provider_ios"
2417
binaryMessenger:registrar.messenger];
2518
[channel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
2619
if ([@"getTemporaryDirectory" isEqualToString:call.method]) {
2720
result([self getTemporaryDirectory]);
2821
} else if ([@"getApplicationDocumentsDirectory" isEqualToString:call.method]) {
2922
result([self getApplicationDocumentsDirectory]);
3023
} else if ([@"getApplicationSupportDirectory" isEqualToString:call.method]) {
31-
NSString *path = [self getApplicationSupportDirectory];
32-
33-
// Create the path if it doesn't exist
34-
NSError *error;
35-
NSFileManager *fileManager = [NSFileManager defaultManager];
36-
BOOL success = [fileManager createDirectoryAtPath:path
37-
withIntermediateDirectories:YES
38-
attributes:nil
39-
error:&error];
40-
if (!success) {
41-
result(getFlutterError(error));
42-
} else {
43-
result(path);
44-
}
24+
result([self getApplicationSupportDirectory]);
4525
} else if ([@"getLibraryDirectory" isEqualToString:call.method]) {
4626
result([self getLibraryDirectory]);
4727
} else {
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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+
5+
import 'dart:io';
6+
7+
import 'package:flutter/foundation.dart' show visibleForTesting;
8+
import 'package:flutter/services.dart';
9+
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
10+
11+
/// The iOS implementation of [PathProviderPlatform].
12+
class PathProviderIOS 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_ios');
17+
18+
/// Registers this class as the default instance of [PathProviderPlatform]
19+
static void registerWith() {
20+
PathProviderPlatform.instance = PathProviderIOS();
21+
}
22+
23+
@override
24+
Future<String?> getTemporaryPath() async {
25+
return methodChannel.invokeMethod<String>('getTemporaryDirectory');
26+
}
27+
28+
@override
29+
Future<String?> getApplicationSupportPath() async {
30+
final String? path = await methodChannel
31+
.invokeMethod<String>('getApplicationSupportDirectory');
32+
if (path != null) {
33+
// Ensure the directory exists before returning it, for consistency with
34+
// other platforms.
35+
await Directory(path).create(recursive: true);
36+
}
37+
return path;
38+
}
39+
40+
@override
41+
Future<String?> getLibraryPath() async {
42+
return methodChannel.invokeMethod<String>('getLibraryDirectory');
43+
}
44+
45+
@override
46+
Future<String?> getApplicationDocumentsPath() async {
47+
return methodChannel
48+
.invokeMethod<String>('getApplicationDocumentsDirectory');
49+
}
50+
51+
@override
52+
Future<String?> getExternalStoragePath() async {
53+
throw UnsupportedError('getExternalStoragePath is not supported on iOS');
54+
}
55+
56+
@override
57+
Future<List<String>?> getExternalCachePaths() async {
58+
throw UnsupportedError('getExternalCachePaths is not supported on iOS');
59+
}
60+
61+
@override
62+
Future<List<String>?> getExternalStoragePaths({
63+
StorageDirectory? type,
64+
}) async {
65+
throw UnsupportedError('getExternalStoragePaths is not supported on iOS');
66+
}
67+
68+
@override
69+
Future<String?> getDownloadsPath() async {
70+
throw UnsupportedError('getDownloadsPath is not supported on iOS');
71+
}
72+
}

packages/path_provider/path_provider_ios/pubspec.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,19 @@ name: path_provider_ios
22
description: iOS implementation of the path_provider plugin.
33
repository: https://github.com/flutter/plugins/tree/main/packages/path_provider/path_provider_ios
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.7
5+
version: 2.0.8
66

77
environment:
88
sdk: ">=2.14.0 <3.0.0"
9-
flutter: ">=2.5.0"
9+
flutter: ">=2.8.0"
1010

1111
flutter:
1212
plugin:
1313
implements: path_provider
1414
platforms:
1515
ios:
1616
pluginClass: FLTPathProviderPlugin
17+
dartPluginClass: PathProviderIOS
1718

1819
dependencies:
1920
flutter:
@@ -27,5 +28,6 @@ dev_dependencies:
2728
sdk: flutter
2829
integration_test:
2930
sdk: flutter
31+
path: ^1.8.0
3032
plugin_platform_interface: ^2.0.0
3133
test: ^1.16.0
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
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+
5+
import 'dart:io';
6+
7+
import 'package:flutter/services.dart';
8+
import 'package:flutter_test/flutter_test.dart';
9+
import 'package:path/path.dart' as p;
10+
import 'package:path_provider_ios/path_provider_ios.dart';
11+
12+
void main() {
13+
TestWidgetsFlutterBinding.ensureInitialized();
14+
15+
group('PathProviderIOS', () {
16+
late PathProviderIOS pathProvider;
17+
late List<MethodCall> log;
18+
// These unit tests use the actual filesystem, since an injectable
19+
// filesystem would add a runtime dependency to the package, so everything
20+
// is contained to a temporary directory.
21+
late Directory testRoot;
22+
23+
late String temporaryPath;
24+
late String applicationSupportPath;
25+
late String libraryPath;
26+
late String applicationDocumentsPath;
27+
28+
setUp(() async {
29+
pathProvider = PathProviderIOS();
30+
31+
testRoot = Directory.systemTemp.createTempSync();
32+
final String basePath = testRoot.path;
33+
temporaryPath = p.join(basePath, 'temporary', 'path');
34+
applicationSupportPath =
35+
p.join(basePath, 'application', 'support', 'path');
36+
libraryPath = p.join(basePath, 'library', 'path');
37+
applicationDocumentsPath =
38+
p.join(basePath, 'application', 'documents', 'path');
39+
40+
log = <MethodCall>[];
41+
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger
42+
.setMockMethodCallHandler(pathProvider.methodChannel,
43+
(MethodCall methodCall) async {
44+
log.add(methodCall);
45+
switch (methodCall.method) {
46+
case 'getTemporaryDirectory':
47+
return temporaryPath;
48+
case 'getApplicationSupportDirectory':
49+
return applicationSupportPath;
50+
case 'getLibraryDirectory':
51+
return libraryPath;
52+
case 'getApplicationDocumentsDirectory':
53+
return applicationDocumentsPath;
54+
default:
55+
return null;
56+
}
57+
});
58+
});
59+
60+
tearDown(() {
61+
testRoot.deleteSync(recursive: true);
62+
});
63+
64+
test('getTemporaryPath', () async {
65+
final String? path = await pathProvider.getTemporaryPath();
66+
expect(
67+
log,
68+
<Matcher>[isMethodCall('getTemporaryDirectory', arguments: null)],
69+
);
70+
expect(path, temporaryPath);
71+
});
72+
73+
test('getApplicationSupportPath', () async {
74+
final String? path = await pathProvider.getApplicationSupportPath();
75+
expect(
76+
log,
77+
<Matcher>[
78+
isMethodCall('getApplicationSupportDirectory', arguments: null)
79+
],
80+
);
81+
expect(path, applicationSupportPath);
82+
});
83+
84+
test('getApplicationSupportPath creates the directory if necessary',
85+
() async {
86+
final String? path = await pathProvider.getApplicationSupportPath();
87+
expect(Directory(path!).existsSync(), isTrue);
88+
});
89+
90+
test('getLibraryPath', () async {
91+
final String? path = await pathProvider.getLibraryPath();
92+
expect(
93+
log,
94+
<Matcher>[isMethodCall('getLibraryDirectory', arguments: null)],
95+
);
96+
expect(path, libraryPath);
97+
});
98+
99+
test('getApplicationDocumentsPath', () async {
100+
final String? path = await pathProvider.getApplicationDocumentsPath();
101+
expect(
102+
log,
103+
<Matcher>[
104+
isMethodCall('getApplicationDocumentsDirectory', arguments: null)
105+
],
106+
);
107+
expect(path, applicationDocumentsPath);
108+
});
109+
110+
test('getDownloadsPath throws', () async {
111+
expect(pathProvider.getDownloadsPath(), throwsA(isUnsupportedError));
112+
});
113+
114+
test('getExternalCachePaths throws', () async {
115+
expect(pathProvider.getExternalCachePaths(), throwsA(isUnsupportedError));
116+
});
117+
118+
test('getExternalStoragePath throws', () async {
119+
expect(
120+
pathProvider.getExternalStoragePath(), throwsA(isUnsupportedError));
121+
});
122+
123+
test('getExternalStoragePaths throws', () async {
124+
expect(
125+
pathProvider.getExternalStoragePaths(), throwsA(isUnsupportedError));
126+
});
127+
});
128+
}

0 commit comments

Comments
 (0)