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

Commit 2ac7e58

Browse files
committed
[path_provider] Use the application ID in the application support path (#2845)
Use the existing executable named directory if it exists, to allow backwards compatibility to work.
1 parent 29f46b4 commit 2ac7e58

File tree

8 files changed

+181
-61
lines changed

8 files changed

+181
-61
lines changed

packages/path_provider/path_provider_linux/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 2.1.1
2+
3+
* Change getApplicationSupportPath from using executable name to application ID (if provided).
4+
* If the executable name based directory exists, continue to use that so existing applications continue with the same behaviour.
5+
16
## 2.1.0
27

38
* Now `getTemporaryPath` returns the value of the `TMPDIR` environment variable primarily. If `TMPDIR` is not set, `/tmp` is returned.

packages/path_provider/path_provider_linux/lib/path_provider_linux.dart

Lines changed: 1 addition & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,61 +2,4 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:io';
6-
7-
import 'package:flutter/foundation.dart';
8-
import 'package:path/path.dart' as path;
9-
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
10-
import 'package:xdg_directories/xdg_directories.dart' as xdg;
11-
12-
/// The linux implementation of [PathProviderPlatform]
13-
///
14-
/// This class implements the `package:path_provider` functionality for linux
15-
class PathProviderLinux extends PathProviderPlatform {
16-
/// Constructs an instance of [PathProviderLinux]
17-
PathProviderLinux() : _environment = Platform.environment;
18-
19-
/// Constructs an instance of [PathProviderLinux] with the given [environment]
20-
@visibleForTesting
21-
PathProviderLinux.private({
22-
required Map<String, String> environment,
23-
}) : _environment = environment;
24-
25-
final Map<String, String> _environment;
26-
27-
/// Registers this class as the default instance of [PathProviderPlatform]
28-
static void registerWith() {
29-
PathProviderPlatform.instance = PathProviderLinux();
30-
}
31-
32-
@override
33-
Future<String?> getTemporaryPath() {
34-
final String environmentTmpDir = _environment['TMPDIR'] ?? '';
35-
return Future<String?>.value(
36-
environmentTmpDir.isEmpty ? '/tmp' : environmentTmpDir,
37-
);
38-
}
39-
40-
@override
41-
Future<String?> getApplicationSupportPath() async {
42-
final String processName = path.basenameWithoutExtension(
43-
await File('/proc/self/exe').resolveSymbolicLinks());
44-
final Directory directory =
45-
Directory(path.join(xdg.dataHome.path, processName));
46-
// Creating the directory if it doesn't exist, because mobile implementations assume the directory exists
47-
if (!directory.existsSync()) {
48-
await directory.create(recursive: true);
49-
}
50-
return directory.path;
51-
}
52-
53-
@override
54-
Future<String?> getApplicationDocumentsPath() {
55-
return Future<String?>.value(xdg.getUserDirectory('DOCUMENTS')?.path);
56-
}
57-
58-
@override
59-
Future<String?> getDownloadsPath() {
60-
return Future<String?>.value(xdg.getUserDirectory('DOWNLOAD')?.path);
61-
}
62-
}
5+
export 'src/path_provider_linux.dart';
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
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+
// getApplicationId() is implemented using FFI; export a stub for platforms
6+
// that don't support FFI (e.g., web) to avoid having transitive dependencies
7+
// break web compilation.
8+
export 'get_application_id_stub.dart'
9+
if (dart.library.ffi) 'get_application_id_real.dart';
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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:ffi';
6+
import 'package:ffi/ffi.dart';
7+
8+
// GApplication* g_application_get_default();
9+
typedef _GApplicationGetDefaultC = IntPtr Function();
10+
typedef _GApplicationGetDefaultDart = int Function();
11+
12+
// const gchar* g_application_get_application_id(GApplication* application);
13+
typedef _GApplicationGetApplicationIdC = Pointer<Utf8> Function(IntPtr);
14+
typedef _GApplicationGetApplicationIdDart = Pointer<Utf8> Function(int);
15+
16+
/// Gets the application ID for this app.
17+
String? getApplicationId() {
18+
DynamicLibrary gio;
19+
try {
20+
gio = DynamicLibrary.open('libgio-2.0.so');
21+
} on ArgumentError {
22+
return null;
23+
}
24+
final _GApplicationGetDefaultDart gApplicationGetDefault =
25+
gio.lookupFunction<_GApplicationGetDefaultC, _GApplicationGetDefaultDart>(
26+
'g_application_get_default');
27+
final int app = gApplicationGetDefault();
28+
if (app == 0) {
29+
return null;
30+
}
31+
32+
final _GApplicationGetApplicationIdDart gApplicationGetApplicationId =
33+
gio.lookupFunction<_GApplicationGetApplicationIdC,
34+
_GApplicationGetApplicationIdDart>(
35+
'g_application_get_application_id');
36+
final Pointer<Utf8> appId = gApplicationGetApplicationId(app);
37+
if (appId == null) {
38+
return null;
39+
}
40+
41+
return appId.toDartString();
42+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
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+
/// Gets the application ID for this app.
6+
String? getApplicationId() => null;
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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:async';
6+
import 'dart:io';
7+
8+
import 'package:flutter/foundation.dart';
9+
import 'package:path/path.dart' as path;
10+
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
11+
import 'package:xdg_directories/xdg_directories.dart' as xdg;
12+
13+
import 'get_application_id.dart';
14+
15+
/// The linux implementation of [PathProviderPlatform]
16+
///
17+
/// This class implements the `package:path_provider` functionality for Linux.
18+
class PathProviderLinux extends PathProviderPlatform {
19+
/// Constructs an instance of [PathProviderLinux]
20+
PathProviderLinux() : _environment = Platform.environment;
21+
22+
/// Constructs an instance of [PathProviderLinux] with the given [environment]
23+
@visibleForTesting
24+
PathProviderLinux.private(
25+
{Map<String, String> environment = const {},
26+
String? executableName,
27+
String? applicationId})
28+
: _environment = environment,
29+
_executableName = executableName,
30+
_applicationId = applicationId;
31+
32+
final Map<String, String> _environment;
33+
late final String? _executableName;
34+
String? _applicationId;
35+
36+
/// Registers this class as the default instance of [PathProviderPlatform]
37+
static void registerWith() {
38+
PathProviderPlatform.instance = PathProviderLinux();
39+
}
40+
41+
@override
42+
Future<String?> getTemporaryPath() {
43+
final String environmentTmpDir = _environment['TMPDIR'] ?? '';
44+
return Future<String?>.value(
45+
environmentTmpDir.isEmpty ? '/tmp' : environmentTmpDir,
46+
);
47+
}
48+
49+
@override
50+
Future<String?> getApplicationSupportPath() async {
51+
final Directory directory =
52+
Directory(path.join(xdg.dataHome.path, await _getId()));
53+
if (directory.existsSync()) {
54+
return directory.path;
55+
}
56+
57+
// This plugin originally used the executable name as a directory.
58+
// Use that if it exists for backwards compatibility.
59+
final Directory legacyDirectory =
60+
Directory(path.join(xdg.dataHome.path, await _getExecutableName()));
61+
if (legacyDirectory.existsSync()) {
62+
return legacyDirectory.path;
63+
}
64+
65+
// Create the directory, because mobile implementations assume the directory exists.
66+
await directory.create(recursive: true);
67+
return directory.path;
68+
}
69+
70+
@override
71+
Future<String?> getApplicationDocumentsPath() {
72+
return Future<String?>.value(xdg.getUserDirectory('DOCUMENTS')?.path);
73+
}
74+
75+
@override
76+
Future<String?> getDownloadsPath() {
77+
return Future<String?>.value(xdg.getUserDirectory('DOWNLOAD')?.path);
78+
}
79+
80+
// Gets the name of this executable.
81+
Future<String> _getExecutableName() async {
82+
if (_executableName == null) {
83+
_executableName = await path.basenameWithoutExtension(
84+
await File('/proc/self/exe').resolveSymbolicLinks());
85+
}
86+
return _executableName!;
87+
}
88+
89+
// Gets the unique ID for this application.
90+
Future<String> _getId() async {
91+
if (_applicationId == null) {
92+
_applicationId = getApplicationId();
93+
}
94+
95+
if (_applicationId != null) {
96+
return _applicationId!;
97+
}
98+
99+
// Fall back to using the executable name.
100+
return await _getExecutableName();
101+
}
102+
}

packages/path_provider/path_provider_linux/pubspec.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: path_provider_linux
22
description: Linux implementation of the path_provider plugin
33
repository: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_linux
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22
5-
version: 2.1.0
5+
version: 2.1.1
66

77
environment:
88
sdk: ">=2.12.0 <3.0.0"
@@ -17,6 +17,7 @@ flutter:
1717
pluginClass: none
1818

1919
dependencies:
20+
ffi: ^1.1.2
2021
flutter:
2122
sdk: flutter
2223
path: ^1.8.0

packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import 'package:flutter_test/flutter_test.dart';
55
import 'package:path_provider_linux/path_provider_linux.dart';
66
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
7+
import 'package:xdg_directories/xdg_directories.dart' as xdg;
78

89
void main() {
910
TestWidgetsFlutterBinding.ensureInitialized();
@@ -35,8 +36,19 @@ void main() {
3536
});
3637

3738
test('getApplicationSupportPath', () async {
38-
final PathProviderPlatform plugin = PathProviderPlatform.instance;
39-
expect(await plugin.getApplicationSupportPath(), startsWith('/'));
39+
final PathProviderPlatform plugin = PathProviderLinux.private(
40+
executableName: 'test', applicationId: 'com.example.Test');
41+
// Note this will fail if ${xdg.dataHome.path}/test exists on the local filesystem.
42+
expect(await plugin.getApplicationSupportPath(),
43+
'${xdg.dataHome.path}/com.example.Test');
44+
});
45+
46+
test('getApplicationSupportPath uses executable name if no application Id',
47+
() async {
48+
final PathProviderPlatform plugin =
49+
PathProviderLinux.private(executableName: 'test');
50+
expect(
51+
await plugin.getApplicationSupportPath(), '${xdg.dataHome.path}/test');
4052
});
4153

4254
test('getApplicationDocumentsPath', () async {

0 commit comments

Comments
 (0)