Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/path_provider/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## 1.1.0

* Added `getApplicationSupportDirectory`.
* Updated documentation for `getApplicationDocumentsDirectory` to suggest
using `getApplicationSupportDirectory` on iOS and
`getExternalStorageDirectory` on Android.
* Updated documentation for `getTemporaryDirectory` to suggest using it
for caches of files that do not need to be backed up.
* Updated integration tests and example to reflect the above changes.

## 1.0.0

* Added integration tests.
Expand Down
22 changes: 22 additions & 0 deletions packages/path_provider/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class MyHomePage extends StatefulWidget {

class _MyHomePageState extends State<MyHomePage> {
Future<Directory> _tempDirectory;
Future<Directory> _appSupportDirectory;
Future<Directory> _appDocumentsDirectory;
Future<Directory> _externalDocumentsDirectory;

Expand Down Expand Up @@ -65,6 +66,12 @@ class _MyHomePageState extends State<MyHomePage> {
});
}

void _requestAppSupportDirectory() {
setState(() {
_appSupportDirectory = getApplicationSupportDirectory();
});
}

void _requestExternalStorageDirectory() {
setState(() {
_externalDocumentsDirectory = getExternalStorageDirectory();
Expand Down Expand Up @@ -111,6 +118,21 @@ class _MyHomePageState extends State<MyHomePage> {
child: FutureBuilder<Directory>(
future: _appDocumentsDirectory, builder: _buildDirectory),
),
Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: RaisedButton(
child: const Text('Get Application Support Directory'),
onPressed: _requestAppSupportDirectory,
),
),
],
),
Expanded(
child: FutureBuilder<Directory>(
future: _appSupportDirectory, builder: _buildDirectory),
),
Column(children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
Expand Down
15 changes: 15 additions & 0 deletions packages/path_provider/example/test_driver/path_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@ void main() {
file.deleteSync();
});

test('getApplicationSupportDirectory', () async {
if (Platform.isIOS) {
final Directory result = await getApplicationSupportDirectory();
final String uuid = Uuid().v1();
final File file = File('${result.path}/$uuid.txt');
file.writeAsStringSync('Hello world!');
expect(file.readAsStringSync(), 'Hello world!');
expect(result.listSync(), isNotEmpty);
file.deleteSync();
} else if (Platform.isAndroid) {
final Future<Directory> result = getApplicationSupportDirectory();
expect(result, throwsA(isInstanceOf<UnsupportedError>()));
}
});

test('getExternalStorageDirectory', () async {
if (Platform.isIOS) {
final Future<Directory> result = getExternalStorageDirectory();
Expand Down
26 changes: 26 additions & 0 deletions packages/path_provider/ios/Classes/PathProviderPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
return paths.firstObject;
}

static FlutterError* getFlutterError(NSError* error) {
if (error == nil) return nil;
return [FlutterError errorWithCode:[NSString stringWithFormat:@"Error %ld", error.code]
message:error.domain
details:error.localizedDescription];
}

@implementation FLTPathProviderPlugin

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
Expand All @@ -20,6 +27,21 @@ + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
result([self getTemporaryDirectory]);
} else if ([@"getApplicationDocumentsDirectory" isEqualToString:call.method]) {
result([self getApplicationDocumentsDirectory]);
} else if ([@"getApplicationSupportDirectory" isEqualToString:call.method]) {
NSString* path = [self getApplicationSupportDirectory];

// Create the path if it doesn't exist
NSError* error;
NSFileManager* fileManager = [NSFileManager defaultManager];
BOOL success = [fileManager createDirectoryAtPath:path
withIntermediateDirectories:YES
attributes:nil
error:&error];
if (!success) {
result(getFlutterError(error));
} else {
result(path);
}
} else {
result(FlutterMethodNotImplemented);
}
Expand All @@ -34,4 +56,8 @@ + (NSString*)getApplicationDocumentsDirectory {
return GetDirectoryOfType(NSDocumentDirectory);
}

+ (NSString*)getApplicationSupportDirectory {
return GetDirectoryOfType(NSApplicationSupportDirectory);
}

@end
57 changes: 37 additions & 20 deletions packages/path_provider/lib/path_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import 'package:flutter/services.dart';
const MethodChannel _channel =
MethodChannel('plugins.flutter.io/path_provider');

/// Path to the temporary directory on the device.
/// Path to the temporary directory on the device that is not backed up and is
/// suitable for storing caches of downloaded files.
///
/// Files in this directory may be cleared at any time. This does *not* return
/// a new temporary directory. Instead, the caller is responsible for creating
Expand All @@ -21,29 +22,47 @@ const MethodChannel _channel =
///
/// On Android, this uses the `getCacheDir` API on the context.
Future<Directory> getTemporaryDirectory() async {
// TODO(amirh): remove this on when the invokeMethod update makes it to stable Flutter.
// https://github.com/flutter/flutter/issues/26431
// ignore: strong_mode_implicit_dynamic_method
final String path = await _channel.invokeMethod('getTemporaryDirectory');
final String path =
await _channel.invokeMethod<String>('getTemporaryDirectory');
if (path == null) {
return null;
}
return Directory(path);
}

/// Path to a directory where the application may place application support
/// files.
///
/// Use this for files you don’t want exposed to the user. Your app should not
/// use this directory for user data files.
///
/// On iOS, this uses the `NSApplicationSupportDirectory` API.
/// If this directory does not exist, it is created automatically.
///
/// On Android, this function throws an [UnsupportedError].
Future<Directory> getApplicationSupportDirectory() async {
if (!Platform.isIOS)
throw UnsupportedError("getApplicationSupportDirectory requires iOS");
final String path =
await _channel.invokeMethod<String>('getApplicationSupportDirectory');
if (path == null) {
return null;
}
return Directory(path);
}

/// Path to a directory where the application may place files that are private
/// to the application and will only be cleared when the application itself
/// is deleted.
/// Path to a directory where the application may place data that is
/// user-generated, or that cannot otherwise be recreated by your application.
///
/// On iOS, this uses the `NSDocumentsDirectory` API.
/// On iOS, this uses the `NSDocumentDirectory` API. Consider using
/// [getApplicationSupportDirectory] instead if the data is not user-generated.
///
/// On Android, this returns the AppData directory.
/// On Android, this uses the `getDataDirectory` API on the context. Consider
/// using getExternalStorageDirectory instead if data is intended to be visible
/// to the user.
Future<Directory> getApplicationDocumentsDirectory() async {
final String path =
// TODO(amirh): remove this on when the invokeMethod update makes it to stable Flutter.
// https://github.com/flutter/flutter/issues/26431
// ignore: strong_mode_implicit_dynamic_method
await _channel.invokeMethod('getApplicationDocumentsDirectory');
await _channel.invokeMethod<String>('getApplicationDocumentsDirectory');
if (path == null) {
return null;
}
Expand All @@ -54,17 +73,15 @@ Future<Directory> getApplicationDocumentsDirectory() async {
/// The current operating system should be determined before issuing this
/// function call, as this functionality is only available on Android.
///
/// On iOS, this function throws an UnsupportedError as it is not possible
/// On iOS, this function throws an [UnsupportedError] as it is not possible
/// to access outside the app's sandbox.
///
/// On Android this returns getExternalStorageDirectory.
/// On Android this uses the `getExternalStorageDirectory` API.
Future<Directory> getExternalStorageDirectory() async {
if (Platform.isIOS)
throw UnsupportedError("Functionality not available on iOS");
// TODO(amirh): remove this on when the invokeMethod update makes it to stable Flutter.
// https://github.com/flutter/flutter/issues/26431
// ignore: strong_mode_implicit_dynamic_method
final String path = await _channel.invokeMethod('getStorageDirectory');
final String path =
await _channel.invokeMethod<String>('getStorageDirectory');
if (path == null) {
return null;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/path_provider/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Flutter plugin for getting commonly used locations on the Android &
iOS file systems, such as the temp and app data directories.
author: Flutter Team <flutter-dev@googlegroups.com>
homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider
version: 1.0.0
version: 1.1.0

flutter:
plugin:
Expand Down