Closed arielt closed 2 years ago
Hello @arielt
One of the strongest points of MSIX is total isolation by virtualize the file system.
After the app is installed, windows creates a virtual folder and files tree (copy of the real folders and files), and the installed app can work (read/write) only with this virtual tree.
After the app is uninstalled, the all virtual tree is deleted.
I created a small app to illustrate those points, its create new folder 'MyFolder', and create random files in it.
The app code:
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
String myFolderPath = '${Platform.environment['AppData']}\\MyFolder';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool isMyFolderExists = false;
List<String> files = [];
_MyHomePageState() {
checkMyFolder();
}
Future<void> createMyFolder() async {
await Directory(myFolderPath).create();
await checkMyFolder();
}
Future<void> deleteMyFolder() async {
await Directory(myFolderPath).delete(recursive: true);
await checkMyFolder();
}
Future<void> createRandomFileInMyFolder() async {
final String fileName = '${Random().nextInt(100)}';
final File file = File('$myFolderPath\\$fileName.txt');
await file.create();
await checkMyFolder();
}
Future<void> checkMyFolder() async {
bool myFolderExists = await Directory(myFolderPath).exists();
List<String> myFolderFileNames = [];
if (myFolderExists) {
var myFolderEntities = await Directory(myFolderPath).list().toList();
myFolderFileNames = myFolderEntities.map((e) => e.path).toList();
}
setState(() {
isMyFolderExists = myFolderExists;
files = myFolderFileNames;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: createMyFolder,
child: const Text(
'Create My Folder',
),
),
Container(width: 10),
isMyFolderExists
? ElevatedButton(
onPressed: deleteMyFolder,
child: const Text(
'Delete My Folder',
),
)
: const Text(''),
Container(width: 10),
isMyFolderExists
? ElevatedButton(
onPressed: createRandomFileInMyFolder,
child: const Text(
'create random file in my folder',
),
)
: const Text(''),
],
),
Text(
isMyFolderExists
? 'is my folder exists in: $myFolderPath'
: 'my folder not exists in: $myFolderPath',
style: TextStyle(
color: isMyFolderExists ? Colors.green : Colors.red,
),
),
Column(
children: files.map((e) => Text(e)).toList(),
),
],
),
),
);
}
}
@YehudaKremer thank you for the quick reply.
I was referring to the Documents folder because that's what Flutter documentation mentions: https://docs.flutter.dev/cookbook/persistence/reading-writing-files -getApplicationDocumentsDirectory()
In your example, you are using Windows' %APPDATA% which would be mapped to something like C:\Users\xxx\AppData\Roaming in Debug or C:\Users\xxx\AppData\Local\Packages\Company.Suite.App\LocalCache\Roaming in Release.
Theoretically, those folders are subject to synchronization between computers.
Do you know if using something like %LOCALAPPDATA% is fine from MSIX perspective, so it would be cleaned up properly?
You welcome @arielt
On my pc, the "AppData" map to the same path in both debug and release 👍:
String myFolderPath = '${Platform.environment['AppData']}\\MyFolder';
i checked the "LOCALAPPDATA" environment variable, its the same in debug and release, and its cleanup after uninstalling just like "APPDATA" 👍 :
String myFolderPath = '${Platform.environment['LOCALAPPDATA']}\\MyFolder';
About the "path_provider" package:
getApplicationDocumentsDirectory
working with the "Documents" folder (the real one, not a virtual) so no cleanup here after uninstalling 👎,
even with getApplicationSupportDirectory
;
for some reason there is NO CLEANUP after uninstalling👎
Thanks @YehudaKremer %LOCALAPPDATA% seems to work for me, deleted properly on uninstall.
The location is still different in debug and release modes: C:\Users\xxx\AppData\Local vs. C:\Users\xxx\AppData\Local\Packages\Company.Suite.App\LocalCache\LocalCache\Local in Release. Not a problem for me though.
:speech_balloon: Description
Application may create housekeeping files in folders like Documents. It can be useful to have a configuration (path) that will be cleared up by Windows when uninstalling an application.
:question: Platform
Windows