How to upload images in Flutter using Appwrite

Femi-ige Muyiwa - Nov 30 '22 - - Dev Community

Avatar background images and user profiles are examples of application features that developers use image uploads to scale. The project may sometimes be more significant in scope, such as a collection of photos accessible to the public or a developer's desire to learn about reactive systems.

This tutorial explains how to use Appwrite functions in reactive systems by creating an image upload and retrieval application. We will demonstrate how to select a picture from local storage, upload it to an Appwrite console, retrieve the list of all the images from the server, and update the UI.

Here is the link to the GitHub repository containing all the code.

Prerequisites

To follow along with this tutorial, the following requirements apply:

Setting up the Appwrite project

To set up a project, we’ll type in the host or IP address of our device in the browser to open an appwrite console. Then, click on create project and give it a project name and ID (ID can be autogenerated).

createproject1
createproject2

In the home section of the Appwrite console, we will select create platform, and in the popup, select Flutter. Within the Flutter section, choose Android and input the application name and package name (we can find them in our app-level build.gradle file by heading to android>app folder).

createplatform1
createplatform2
createplatform3

Next, we want to set up a storage bucket. Head to the storage section and click on add bucket. Then, we’ll set the bucket-level permission's read and write access to allow all users (role:all).

create bucket
set bucket permission

Finally, we want to create a database. To do so, we’ll navigate to the database section and click on add database. Then, create a collection and set the collection-level permission's read and write access to allow all users (role:all). We will also create a required string attribute to store the URL of each image added to the storage.

create database 1
create database 2
set database permission

Cloning the Flutter UI template and connecting to Appwrite

In this section, we will need to clone the repository specified in the prerequisites. To do that, click on the link to the repository, and within the repository, click on code and download it as a .zip file. To use the other methods, check out the GitHub docs on how to clone a repository.

clone repo 1
clone repo 2

Next, to utilize our Appwrite storage and database, we need to connect our Flutter project to the console. Doing this varies among devices. Thus, we will show the process of connecting to Android and iOS devices.

i*OS*
First, we will need to obtain the bundle ID, which we can do by going to the project.pbxproj file (ios > Runner.xcodeproj > project.pbxproj) and searching for our PRODUCT_BUNDLE_IDENTIFIER.

Now, we will head to the Runner.xcworkspace folder in the applications iOS folder in the project directory on Xcode. Now, we want to select the runner target, and to do this; we will choose the Runner project in the Xcode project navigator and then find the Runner target. Next, select General and IOS 11.0 in the deployment info section as the target.

Android
To do this, copy the XML script below and paste it below the activity tag in the Androidmanifest.xml file ( to find this file, head to android > app > src > main).

Note: change [PROJECT-ID] to the id you used when creating the Appwrite project

Getting started

The cloned repository contains an authprovider folder, the homepage.dart file, and the main.dart file in the lib folder. When we run it, we should have a UI that looks like the image below:

repo UI demo

As we can see above, there are two buttons (select file and retrieve) and a display area that shows the images uploaded to the database in a grid format. Currently, the template lacks functionality; thus, we will work on that in the coming sections.

Before we begin, we will need to add the following dependencies to the pubspec.yaml file:

  • provider: ^6.0.3
  • file_picker: ^4.5.1
  • appwrite: ^6.0.0 pubspec.yaml file

Next, within the lib folder, we will create two different folders; constants and models. In the constant folder, we will create a file called app_constants.dart and will add the code below to the file:

To get the IP address for a physical emulator, we will connect our device running the Appwrite instance and physical emulator to the same wifi device and type the command below in the terminal:

ipconfig
Enter fullscreen mode Exit fullscreen mode

The command above will bring out the IPs of the devices connected to our PC.

Creating the image upload feature
We will need to create a model class to convert the response received when we send a file to the Appwrite storage bucket. We do this because, unlike the web SDK, Appwrite does not return a link when getting a file preview. Thus, we will have to create a URL manually for every file added to the storage bucket, and we will need two data (bucketId and fileid).

Now, within the model folder, we will create a file called fileurl.dart and add the code below to it:

The code above creates a class called UploadedFiles with some required properties followed by some constructors. It then creates a fromJson and toJson method for serialization.

To create our application's core logic, we will update the code in the imageprovider.dart file in the template. Using the provider package, we can affect the state of our UI. Before we can do that, we need to update the imageprovider.dart file with the code below:

In the code above, we have a ChangeNotifier class. Within it, we called the Appwrite client, account, storage API, a PlatformFile (from the file_picker package), and also the model class we created earlier. Next, we called a getter for the model class and created a function called _initialize(). Within the _initialize() function, we set the _selectedfile and _uploadedFiles to null (initializers), initialize the Appwrite's API, and call the _getaccount function, which conditionally creates an anonymous user session.

Next, we will use the file_picker package within the filepicker function to select image files from our device storage. The function calls the Filepicker method and checks whether it returns null. If false, it will return the result.files.first.

As specified in the code above, we will need to create a function called _uploadfile(). After picking the file, we’ll use the Appwrite storage API to get the image selected by the path and upload it to the file bucket within our Appwrite storage. We will then check if the id is present, and if true, we will map the value of the uploaded image file to the model class; if false, we do nothing.

Creating the image retrieval feature
Now that we can upload images to the server, we want to be able to get the image from the Appwrite server. As mentioned earlier, we created a model class to manually create a URL. Before we delve into that aspect, we will need to create a model class to map the data sent to the database.

Now, we will call the Appwrite database API and the model class we created above, followed by a getter for the model class. Next, we will initialize the database API and call the createdocument() function in the filepicker function (add it before notifylisteners). The createdocument() will handle uploading the URL we created to the database.

The createdocument() function contains a manually created URL generated from an interpolation of other data stores (variables, constants, model classes), and here is how it looks:

var url='${Appconstants.endpoint}/storage/buckets/${uploadedFiles!.bucketId}/files/${uploadedFiles!.id}/preview?project=${Appconstants.projectid}';
Enter fullscreen mode Exit fullscreen mode

After, we will call the createDocument method from the Appwrite database function and set the data key and value pair to the attribute name created in the collection and our manually created URL, respectively.

Finally, we will create a future asynchronous function that will list the documents in our collection and map them to the model class List<DocModel>.

Consuming the service
We want to use some of the functions from our ChangeNotifier class within our UI. On the homepage.dart file of the UI template, we wrapped the body property in a Consumer class (from the provider library). Thus, we can call functions and getters from the ChangeNotifier class to the UI. Thus, we will set the value of the NetworImage as below:

image: NetworkImage(
   state.docmodel![index].url!)
    ),
Enter fullscreen mode Exit fullscreen mode

Finally, here is how our application looks:

result

Conclusion

In this tutorial, we created an Appwrite service to store uploaded image files, built custom URLs for each uploaded image using the File list object, created a database collection for the URL, and retrieved the URL to map it to the user interface. Here are some related resources you might find useful”

Thanks for reading, and happy coding!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .