Write, view and share app files— Part I

Step by step, the whole story, in Flutter

Danielle H
6 min readOct 11, 2022

As Android progresses, you can’t just save regular txt or csv documents in Downloads or Documents directory with jumping through a lot of permission and app hoops. So the most elegant solution is to save all the files in your app folder (no permissions needed!) and create a page in your app for your users to view the files and share them. Elegant, yes, but how to do it in Flutter? That’s what we’re here for :)

We’re going to build our example app, in two stages.

Part I (this article): Save files to your app directory and view them.

Part II (here): Select and deselect files and share them via email (with flutter_email_sender) or via anything else using share_plus plugin.

View the code in Gitlab.

Let’s get started.

Create Flutter app

In Visual Studio Code, press F1 to open the command palette and choose Flutter create . Choose Application and then your project location and project name.

Change Main.dart

Our main page will have two options: create file and view files.

In main.dart remove all the MyHomePage class and change the MyApp class as follows:

  1. Change MyHomePage() to HomePage()
  2. Add an elevatedButtonTheme to your themeData to theme our buttons.

The new main.dart class will look like this:

It will mark HomePage in red, as we haven’t created it yet. We’ll do that now.

Create home page

Create a new file called home_page.dart. Our home page will be a a column with two button, Create files and View files. We’ll leave their onPressed functions empty for now. And we’ll give them some icons, just for fun (yes, I consider this fun. I’m a programmer 😉).

Because we can, we’ll make it Stateless (always make your widgets stateless if you can).

Great!

Create Files page

In order to view and send files, we need first to create them. We’ll do this using a simple form where user inputs some text and a filename (without the extension) and we’ll create a file in the app directory with these parameters.

Let’s start with the form and a create button:

In the code above:

  1. Stateless Widget, again. The state is managed by the form, there is no need for a stateful widget. The form needs a global key, and two Strings: one for the filename, and one for the file contents. In addition there is a final Regexp for validating if the filename is alphanumeric.
  2. The AppBar contains one action button, a text button Create that creates the file.
  3. The Create button doesn’t yet create the file, we will do this soon. For now it just checks if the form is valid.
  4. The main content is a Form widget. It has two text fields arranged in a column.
  5. The first field has the file content. There is some text already in it so we don’t have to type out the contents if we don’t want to (in this example we are more interested in the files’ name and location rather than their content). We specify maxLines so that the field will be more than one line, set autofocus on it and the next action on enter so that the focus will go automatically to the next form. The validator is simple — we don’t want empty text.
  6. The second field is the file name. Here the validator has two parts — we don’t want empty text, and in addition we want the filename to be alphanumeric. You could of course add underscores etc. as you wish.

In order to test our form, we need to navigate to it from the home page, so lets add the following to our HomePage, on the line where it says //TODO CreatePage:

Now run your app to make sure everything works. Should print out “Looking good” when pressing on the Create button.

Saving the file

As I said above, in order to save to internal app memory you don’t need permissions, so there is nothing to update in manifests or permission requests that you need to handle. You just locate the internal app directory and save, and that's it!

To locate the internal app directory, I used the path_provider package. Install the package in your preferred way (using terminal or your editor. I use the Pubspec Assist extension of VSCode). Please note that you will need to stop the app and rebuild it, and not just hot restart.

In CreatePage.dart, add the following function:

Here we get the internal app directory using the getApplicationDocumentsDirectory() function. Then we create our filename using the directory and the given filename, using the platform pathSeparator. We save our text using writeAsString and return the file. In this app we aren’t using the returned File, but you can use it in order to e.g. show a message to your users that the file named File.pathwas saved successfully.

Now we need to call the saveFile function from the Create onPressed function, where it says TODO save file:

And now we can save files to our internal app folder.

View Page

I just claimed that you saved a file, and you (hopefully!) didn’t get any errors. But how can you see the files you saved?

For this we will create a ViewPage screen, that lists the files in the internal app directory.

While we can use a stateless widget and a FutureBuilder, we will use a stateful widget because we will need it to be stateful later, when we are choosing files to share.

In the code above:

  1. In initState we start an asynchronous function to get the file list by calling the getFiles() function.
  2. When getFiles() gets the list, _files is updated using setState, updating our UI.
  3. The build function uses a ListView.builder to build tiles with borders from each element in _files.
  4. In each ListTile we show the filename of the file.
  5. In order to show only the file name in the UI instead of the entire path, we create a utility function getFileName() that retrieves the filename from the file path.

We need to navigate to the new page, so in HomePage add the following, on the line where it says //TODO ViewPage:

Run the app, view the files you created before, and create some more files and watch them appear.

This looks great, but… what if you don’t want to show all the files in your app directory? Maybe you have some app data you don’t want your users to see, or crash logs, etc.

One option is to create your own folder in your app directory and show all the contents from this folder. Another option is to have all user files have the same base name, e.g. unicorn and show only files that start with unicorn. Here I’ll demonstrate the second option. And let’s sort the files by date as well 😄.

Let’s change the getFiles function to the following:

And now the user sees only the files we wish them to see.

We did it!

In the next article, we will select files and share them, in two different ways.

See you there!

--

--

Danielle H
Danielle H

Written by Danielle H

Physicist turned programmer, exploring many languages to build projects from neurobiology tools to abstract videos.

No responses yet