[path_provider] Use the application ID in the application support path (#2845) (#3077)
Use the existing executable named directory if it exists, to allow backwards
compatibility to work.
diff --git a/packages/path_provider/path_provider_linux/CHANGELOG.md b/packages/path_provider/path_provider_linux/CHANGELOG.md
index 209fddb..f227570 100644
--- a/packages/path_provider/path_provider_linux/CHANGELOG.md
+++ b/packages/path_provider/path_provider_linux/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 2.1.3
+
+* Change getApplicationSupportPath from using executable name to application ID (if provided).
+ * If the executable name based directory exists, continue to use that so existing applications continue with the same behaviour.
+
## 2.1.2
* Fixes link in README.
diff --git a/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart b/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart
index ab18db6..e32af1b 100644
--- a/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart
+++ b/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart
@@ -2,61 +2,4 @@
// 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/foundation.dart';
-import 'package:path/path.dart' as path;
-import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
-import 'package:xdg_directories/xdg_directories.dart' as xdg;
-
-/// The linux implementation of [PathProviderPlatform]
-///
-/// This class implements the `package:path_provider` functionality for linux
-class PathProviderLinux extends PathProviderPlatform {
- /// Constructs an instance of [PathProviderLinux]
- PathProviderLinux() : _environment = Platform.environment;
-
- /// Constructs an instance of [PathProviderLinux] with the given [environment]
- @visibleForTesting
- PathProviderLinux.private({
- required Map<String, String> environment,
- }) : _environment = environment;
-
- final Map<String, String> _environment;
-
- /// Registers this class as the default instance of [PathProviderPlatform]
- static void registerWith() {
- PathProviderPlatform.instance = PathProviderLinux();
- }
-
- @override
- Future<String?> getTemporaryPath() {
- final String environmentTmpDir = _environment['TMPDIR'] ?? '';
- return Future<String?>.value(
- environmentTmpDir.isEmpty ? '/tmp' : environmentTmpDir,
- );
- }
-
- @override
- Future<String?> getApplicationSupportPath() async {
- final String processName = path.basenameWithoutExtension(
- await File('/proc/self/exe').resolveSymbolicLinks());
- final Directory directory =
- Directory(path.join(xdg.dataHome.path, processName));
- // Creating the directory if it doesn't exist, because mobile implementations assume the directory exists
- if (!directory.existsSync()) {
- await directory.create(recursive: true);
- }
- return directory.path;
- }
-
- @override
- Future<String?> getApplicationDocumentsPath() {
- return Future<String?>.value(xdg.getUserDirectory('DOCUMENTS')?.path);
- }
-
- @override
- Future<String?> getDownloadsPath() {
- return Future<String?>.value(xdg.getUserDirectory('DOWNLOAD')?.path);
- }
-}
+export 'src/path_provider_linux.dart';
diff --git a/packages/path_provider/path_provider_linux/lib/src/get_application_id.dart b/packages/path_provider/path_provider_linux/lib/src/get_application_id.dart
new file mode 100644
index 0000000..e169c02
--- /dev/null
+++ b/packages/path_provider/path_provider_linux/lib/src/get_application_id.dart
@@ -0,0 +1,9 @@
+// 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.
+
+// getApplicationId() is implemented using FFI; export a stub for platforms
+// that don't support FFI (e.g., web) to avoid having transitive dependencies
+// break web compilation.
+export 'get_application_id_stub.dart'
+ if (dart.library.ffi) 'get_application_id_real.dart';
diff --git a/packages/path_provider/path_provider_linux/lib/src/get_application_id_real.dart b/packages/path_provider/path_provider_linux/lib/src/get_application_id_real.dart
new file mode 100644
index 0000000..f6d25bb
--- /dev/null
+++ b/packages/path_provider/path_provider_linux/lib/src/get_application_id_real.dart
@@ -0,0 +1,42 @@
+// 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 'dart:ffi';
+import 'package:ffi/ffi.dart';
+
+// GApplication* g_application_get_default();
+typedef _GApplicationGetDefaultC = IntPtr Function();
+typedef _GApplicationGetDefaultDart = int Function();
+
+// const gchar* g_application_get_application_id(GApplication* application);
+typedef _GApplicationGetApplicationIdC = Pointer<Utf8> Function(IntPtr);
+typedef _GApplicationGetApplicationIdDart = Pointer<Utf8> Function(int);
+
+/// Gets the application ID for this app.
+String? getApplicationId() {
+ DynamicLibrary gio;
+ try {
+ gio = DynamicLibrary.open('libgio-2.0.so');
+ } on ArgumentError {
+ return null;
+ }
+ final _GApplicationGetDefaultDart gApplicationGetDefault =
+ gio.lookupFunction<_GApplicationGetDefaultC, _GApplicationGetDefaultDart>(
+ 'g_application_get_default');
+ final int app = gApplicationGetDefault();
+ if (app == 0) {
+ return null;
+ }
+
+ final _GApplicationGetApplicationIdDart gApplicationGetApplicationId =
+ gio.lookupFunction<_GApplicationGetApplicationIdC,
+ _GApplicationGetApplicationIdDart>(
+ 'g_application_get_application_id');
+ final Pointer<Utf8> appId = gApplicationGetApplicationId(app);
+ if (appId == null) {
+ return null;
+ }
+
+ return appId.toDartString();
+}
diff --git a/packages/path_provider/path_provider_linux/lib/src/get_application_id_stub.dart b/packages/path_provider/path_provider_linux/lib/src/get_application_id_stub.dart
new file mode 100644
index 0000000..9099976
--- /dev/null
+++ b/packages/path_provider/path_provider_linux/lib/src/get_application_id_stub.dart
@@ -0,0 +1,6 @@
+// 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.
+
+/// Gets the application ID for this app.
+String? getApplicationId() => null;
diff --git a/packages/path_provider/path_provider_linux/lib/src/path_provider_linux.dart b/packages/path_provider/path_provider_linux/lib/src/path_provider_linux.dart
new file mode 100644
index 0000000..1544dce
--- /dev/null
+++ b/packages/path_provider/path_provider_linux/lib/src/path_provider_linux.dart
@@ -0,0 +1,92 @@
+// 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 'dart:io';
+
+import 'package:flutter/foundation.dart';
+import 'package:path/path.dart' as path;
+import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
+import 'package:xdg_directories/xdg_directories.dart' as xdg;
+
+import 'get_application_id.dart';
+
+/// The linux implementation of [PathProviderPlatform]
+///
+/// This class implements the `package:path_provider` functionality for Linux.
+class PathProviderLinux extends PathProviderPlatform {
+ /// Constructs an instance of [PathProviderLinux]
+ PathProviderLinux() : _environment = Platform.environment;
+
+ /// Constructs an instance of [PathProviderLinux] with the given [environment]
+ @visibleForTesting
+ PathProviderLinux.private(
+ {Map<String, String> environment = const <String, String>{},
+ String? executableName,
+ String? applicationId})
+ : _environment = environment,
+ _executableName = executableName,
+ _applicationId = applicationId;
+
+ final Map<String, String> _environment;
+ String? _executableName;
+ String? _applicationId;
+
+ /// Registers this class as the default instance of [PathProviderPlatform]
+ static void registerWith() {
+ PathProviderPlatform.instance = PathProviderLinux();
+ }
+
+ @override
+ Future<String?> getTemporaryPath() {
+ final String environmentTmpDir = _environment['TMPDIR'] ?? '';
+ return Future<String?>.value(
+ environmentTmpDir.isEmpty ? '/tmp' : environmentTmpDir,
+ );
+ }
+
+ @override
+ Future<String?> getApplicationSupportPath() async {
+ final Directory directory =
+ Directory(path.join(xdg.dataHome.path, await _getId()));
+ if (directory.existsSync()) {
+ return directory.path;
+ }
+
+ // This plugin originally used the executable name as a directory.
+ // Use that if it exists for backwards compatibility.
+ final Directory legacyDirectory =
+ Directory(path.join(xdg.dataHome.path, await _getExecutableName()));
+ if (legacyDirectory.existsSync()) {
+ return legacyDirectory.path;
+ }
+
+ // Create the directory, because mobile implementations assume the directory exists.
+ await directory.create(recursive: true);
+ return directory.path;
+ }
+
+ @override
+ Future<String?> getApplicationDocumentsPath() {
+ return Future<String?>.value(xdg.getUserDirectory('DOCUMENTS')?.path);
+ }
+
+ @override
+ Future<String?> getDownloadsPath() {
+ return Future<String?>.value(xdg.getUserDirectory('DOWNLOAD')?.path);
+ }
+
+ // Gets the name of this executable.
+ Future<String> _getExecutableName() async {
+ _executableName ??= path.basenameWithoutExtension(
+ await File('/proc/self/exe').resolveSymbolicLinks());
+ return _executableName!;
+ }
+
+ // Gets the unique ID for this application.
+ Future<String> _getId() async {
+ _applicationId ??= getApplicationId();
+ // If no application ID then fall back to using the executable name.
+ return _applicationId ?? await _getExecutableName();
+ }
+}
diff --git a/packages/path_provider/path_provider_linux/pubspec.yaml b/packages/path_provider/path_provider_linux/pubspec.yaml
index 67638cd..25d1af9 100644
--- a/packages/path_provider/path_provider_linux/pubspec.yaml
+++ b/packages/path_provider/path_provider_linux/pubspec.yaml
@@ -2,7 +2,7 @@
description: Linux implementation of the path_provider plugin
repository: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_linux
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22
-version: 2.1.2
+version: 2.1.3
environment:
sdk: ">=2.12.0 <3.0.0"
@@ -16,6 +16,7 @@
dartPluginClass: PathProviderLinux
dependencies:
+ ffi: ^1.1.2
flutter:
sdk: flutter
path: ^1.8.0
diff --git a/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart b/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart
index 6dd3500..1f567c0 100644
--- a/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart
+++ b/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart
@@ -4,6 +4,7 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:path_provider_linux/path_provider_linux.dart';
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
+import 'package:xdg_directories/xdg_directories.dart' as xdg;
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
@@ -35,8 +36,20 @@
});
test('getApplicationSupportPath', () async {
- final PathProviderPlatform plugin = PathProviderPlatform.instance;
- expect(await plugin.getApplicationSupportPath(), startsWith('/'));
+ final PathProviderPlatform plugin = PathProviderLinux.private(
+ executableName: 'path_provider_linux_test_binary',
+ applicationId: 'com.example.Test');
+ // Note this will fail if ${xdg.dataHome.path}/path_provider_linux_test_binary exists on the local filesystem.
+ expect(await plugin.getApplicationSupportPath(),
+ '${xdg.dataHome.path}/com.example.Test');
+ });
+
+ test('getApplicationSupportPath uses executable name if no application Id',
+ () async {
+ final PathProviderPlatform plugin = PathProviderLinux.private(
+ executableName: 'path_provider_linux_test_binary');
+ expect(await plugin.getApplicationSupportPath(),
+ '${xdg.dataHome.path}/path_provider_linux_test_binary');
});
test('getApplicationDocumentsPath', () async {