Handling File Upload, Compression, and Encryption using AES Algorithm in Flutter Applications

File compression is the process of reducing the logical size of a file to save disk space. It also involves network optimization of files for easier transfer over the internet.

On the other hand, file encryption is a way of encoding files, including the sensitive data they contain, to send them securely. This prevents unauthorized access and tampering.

Goal

This tutorial will guide the reader on how to create a simple Flutter mobile application that will be able to:

  • Accept files such as images, videos, or documents from the phone’s local storage.
  • Compress the files without losing their quality.
  • Encrypt the files using the AES encryption algorithm before uploading the file to Firebase storage.

Prerequisites

  • A solid understanding of the Dart programming language.
  • Knowledge of working with Flutter widgets.
  • An IDE that supports Flutter such as Visual Studio Code. This tutorial uses Android Studio with the Flutter plugin installed.

We will be using Flutter version 2.10.4 in this tutorial. If you do not have Flutter SDK installed, visit Flutter Docs for the installation process.

Project overview

Open Android Studio and create a new Flutter application with the name flutter-app-demo.
After the project has been initialized, we will create our project structure.

The project will have four routes. We will go to the lib folder of our project and create a new folder called screens and here, we will add our routes.

The routes are as follows:

  • Home screen – This will be our startup page when the application loads. It will go by the name, home.screen.dart.
  • Image screen – This page will be called image.screen.dart. It will allow the user to pick and upload an image.
  • Video screen – This page will be called video.screen.dart. It will allow the user to pick a video and upload it to Firebase storage.
  • Document screen – This will be called document.screen.dart. It will allow the user to pick a document and manipulate it.

Next, we will create another folder under the lib folder called services. This folder will contain the APIs that we will use for the functionality of our application.

We will create the following APIs:

  • A Firebase API – It will contain the code that will enable us to upload files to Firebase storage.

  • File picker API – This API will enable us to pick files from the local storage.

  • File compression API – This APi will enable us to compress images and videos picked from the gallery.

  • File encryption API – This API will enable us to encrypt a file.

Setting up Firebase

To set up Firebase go to the Firebase Console and follow the step-by-step process to create your Firebase project.

After successfully creating your Firebase Android app. Navigate to the menu in the dashboard and select Storage and then Get Started as shown below:

Getting started with Firebase Storage

Next, select to start in test mode and specify the location of your Firebase server and then click done.

After the process is complete, navigate to the Rules tab and then change the rules, as shown below:

Firebase Storage Rules

Note that this rule is not recommended when in production mode because it makes your data insecure.

Adding dependencies

Go to the pubspec.yaml file and add the following dependencies:

dependencies:

encrypt:

^

5.0

.

1

video_compress:

^

3.1

.

0

firebase_storage:

^

10.2

.

9

firebase_core:

^

1.13

.

1

flutter_native_image:

^

0.0

.

6

+

1

gallery_saver:

^

2.3

.

2

file_picker:

^

4.5

.

1

file_saver:

^

0.1

.

0

  • firebase_storage and firebase_core help us to access our Firebase storage where we will store our files.
  • flutter_native_image helps us to compress images that we pick from the local storage.
  • video_compress enables us to compress videos.
  • gallery_saver provides an easier way to save images or videos to the gallery.
  • file_saver provides us an easier way to save document files to the local storage.
  • file_picker enables us to pick from the local storage.
  • encrypt allows us to encrypt and decrypt files using the AES algorithm.

Creating APIs

We will create four APIs which we will use to build the functionality of our application.

These APIs are as follows:

1. File Picker API

In this API we create methods for the functions that the program will perform, i.e., picking images and videos from the local storage. These functions are as follows:

a. Picking an image

This function is shown below:

class

FilePickerApi

{

//Picking an image from local storage

static

Future

<

File

?>

pickImage()

async

{

final

pickedFile

=

await

FilePicker.platform.pickFiles(

allowMultiple:

false

,

type: FileType.image,

// Only images will be picked in the file picker

);

if

(pickedFile

==

null

) {

return

null

;

}

else

{

final

pickedImage

=

pickedFile.files.first;

return

File(pickedImage.path

!

);

}

}

}

b. Picking a video

This will be done using the following code:

// Picking a video from the local storage

static

Future

<

File

?>

pickVideo()

async

{

final

pickedFile

=

await

FilePicker.platform.pickFiles(

allowMultiple:

false

,

type: FileType.video,

//Only videos will be picked in the file picker

);

if

(pickedFile

==

null

) {

return

null

;

}

else

{

final

pickedVideo

=

pickedFile.files.first;

return

File(pickedVideo.path

!

);

}

}

This is the function for picking a video from the local storage.

c. Picking a document

It is as shown below:

// Picking a document from local storage

Future

<

File

?>

pickDocument()

async

{

final

pickedFile

=

await

FilePicker.platform.pickFiles(

allowMultiple:

false

,

type: FileType.custom,

allowedExtensions: [

"pdf"

]);

//Only PDF document files will be picked in the file picker

if

(pickedFile

==

null

) {

return

null

;

}

else

{

final

pickedDocument

=

pickedFile.files.first;

return

File(pickedDocument.path

!

);

}

}

The function above will enable us to pick documents from the gallery. We will only be able to select .pdf document files from the local storage.

This is because we have set PDF files as the only allowed document format but more could be added.

2. File compression API

a. Compressing an image

It is as shown below:

class

FileCompressionApi

{

//Compressing the picked image

static

Future

<

File

?>

compressImage(File file)

async

{

try

{

final

compressedFile

=

await

FlutterNativeImage.compressImage(file.path,

quality:

100

, percentage:

10

);

return

File(compressedFile.path);

}

catch

(e) {

return

null

;

//If any error occurs during compression, the process is stopped.

}

}

}

From the function above, the picked image is passed as an argument. We have used the flutter-native-image package to compress the image and return a new compressed file.

b. Compressing a video

It is as shown below:

//Compressing the picked video

static

Future

<

MediaInfo

?>

compressVideo(File file)

async

{

try

{

await

VideoCompress.setLogLevel(

0

);

return

VideoCompress.compressVideo(file.path,

quality: VideoQuality.LowQuality,

includeAudio:

true

,

deleteOrigin:

true

);

}

catch

(e) {

VideoCompress.cancelCompression();

//If any error occurs during compression, the process is stopped.

}

return

null

;

}

From the above function, we pass the picked video as an argument. We will then use the video_compress package to compress the image.

The final output is a file with media information. We will use the media information to get the actual file which is our compressed video.

3. Firebase API

The function of the Firebase API is to enable the user to upload files to the Firebase storage.

We have created a class called firebase.api.dart. Here is the code for the Firebase file uploading:

class

FirebaseApi

{

static

UploadTask

?

uploadFile(

String

destination, File file) {

try

{

final

storageRef

=

FirebaseStorage.instance.ref(destination);

//Here the destination of the file is passed.

return

storageRef.putFile(file);

// The file to be uploaded is passed.

} on FirebaseException

catch

(e) {

return

null

;

// If any errors occur uploading is cancelled.

}

}

}

Here, we will pass the file we want to upload, and the path where will store the file in the Firebase storage bucket.

4. File Encryption API

import

'dart:typed_data'

;

import

'package:encrypt/encrypt.dart'

;

class

FileEcryptionApi

{

static

Future

<

Uint8List

?>

encryptFile(data)

async

{

final

key

=

Key.fromSecureRandom(

16

);

final

iv

=

IV.fromLength(

16

);

final

encrypter

=

Encrypter(AES(key, mode: AESMode.cbc));

final

encryptedFile

=

encrypter.encryptBytes(data, iv: iv);

return

encryptedFile.bytes;

}

}

Here, we set the encryption algorithm to AES, and we have created a key variable. It contains an encryption key that is randomly generated containing 16 characters.

iv represents an Initialization Vector key which is used to initialize the encryption process.

Finally, we have passed the data which we want to encrypt which is the list of bytes that we want to encrypt.

User Interface

Home Screen

This page will be the main screen of our application. It is the root page that we will use to navigate to other pages in the application.

This is the code for our home screen:

import

'package:flutter/material.dart'

;

import

'package:flutter_app_demo/screens/document.screen.dart'

;

import

'package:flutter_app_demo/screens/image.screen.dart'

;

import

'package:flutter_app_demo/screens/video.screen.dart'

;

class

HomeScreen

extends

StatefulWidget {

const

HomeScreen({Key

?

key})

:

super

(key: key);

@

override

State

<

HomeScreen

>

createState()

=>

_HomeScreenState();

}

class

_HomeScreenState

extends

State

<

HomeScreen

>

{

@

override

Widget build(BuildContext context) {

return

Scaffold(

appBar: AppBar(

title:

const

Text(

"Flutter App Demo"

),

centerTitle:

true

,

),

body: Center(

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: [

ElevatedButton.icon(

onPressed: () {

Navigator.push(

context,

MaterialPageRoute(

builder: (context)

=>

const

VideoScreen()));

},

icon:

const

Icon(Icons.video_file),

label:

const

Text(

"Select Video"

)),

const

SizedBox(height:

16

),

ElevatedButton.icon(

onPressed: () {

Navigator.push(

context,

MaterialPageRoute(

builder: (context)

=>

const

ImageScreen()));

},

icon:

const

Icon(Icons.image_rounded),

label:

const

Text(

"Select Image"

)),

const

SizedBox(height:

16

),

ElevatedButton.icon(

onPressed: () {

Navigator.push(

context,

MaterialPageRoute(

builder: (context)

=>

const

DocumentScreen()));

},

icon:

const

Icon(Icons.insert_drive_file_rounded),

label:

const

Text(

"Select Document"

))

],

),

),

);

}

}

Image Screen

This is the page where we will be able to select an image, compress it, save it to the gallery or upload it to firebase.

This is the code for our Image screen:

import

'dart:io'

;

import

'package:flutter/material.dart'

;

import

'package:flutter_app_demo/services/file.compression.api.dart'

;

import

'package:flutter_app_demo/services/file.picker.api.dart'

;

import

'package:gallery_saver/gallery_saver.dart'

;

import

'../services/firebase.api.dart'

;

class

ImageScreen

extends

StatefulWidget {

const

ImageScreen({Key

?

key})

:

super

(key: key);

@

override

State

<

ImageScreen

>

createState()

=>

_ImageScreenState();

}

class

_ImageScreenState

extends

State

<

ImageScreen

>

{

File

?

image;

File

?

compressedImage;

bool

isUploading

=

false

;

bool

isCompressing

=

false

;

@

override

Widget build(BuildContext context) {

final

fileName

=

image

!=

null

?

(image

!

.path.split(

'/'

).last)

:

"No Image Selected"

;

final

fileSize

=

image

!=

null

?

(image

!

.lengthSync().roundToDouble()

/

1048576

).toStringAsFixed(

2

)

:

""

;

final

compressedFileSize

=

compressedImage

!=

null

?

(compressedImage

!

.lengthSync().roundToDouble()

/

1048576

)

.toStringAsFixed(

2

)

:

""

;

return

Scaffold(

appBar: AppBar(

title:

const

Text(

"Select Image"

),

centerTitle:

true

,

),

body: Center(

child: Padding(

padding:

const

EdgeInsets.all(

30

),

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: [

Text(

fileName,

style:

const

TextStyle(

fontSize:

18

,

fontWeight: FontWeight.w600,

),

textAlign: TextAlign.center,

),

const

SizedBox(

height:

8

,

),

Text(

image

!=

null

?

"File Size:

$

fileSize

MB"

:

""

,

style:

const

TextStyle(

fontSize:

16

,

fontWeight: FontWeight.w600,

),

textAlign: TextAlign.center,

),

const

SizedBox(

height:

8

,

),

Text(

compressedImage

!=

null

?

"Compressed File Size:

$

compressedFileSize

MB"

:

""

,

style:

const

TextStyle(

fontSize:

16

,

fontWeight: FontWeight.w600,

),

textAlign: TextAlign.center,

),

const

SizedBox(

height:

10

,

),

if

(image

==

null

)

ElevatedButton.icon(

onPressed: ()

async

{

final

result

=

await

FilePickerApi.pickImage();

if

(result

==

null

) {

return

;

}

final

filePath

=

result.path;

setState(() {

image

=

File(filePath);

});

},

icon:

const

Icon(Icons.image),

label:

const

Text(

"Pick Image"

))

else

(compressedImage

==

null

)

?

ElevatedButton(

onPressed: ()

async

{

setState(() {

isCompressing

=

true

;

});

final

result

=

await

FileCompressionApi.compressImage(

image

!

);

if

(result

==

null

) {

return

;

}

final

filePath

=

result.path;

setState(() {

compressedImage

=

File(filePath);

isCompressing

=

false

;

});

},

child: isCompressing

?

const

Text(

"Compressing..."

)

:

const

Text(

"Compress Image"

))

:

Column(

children: [

ElevatedButton.icon(

onPressed: ()

async

{

String

url

=

compressedImage

!

.path;

GallerySaver.saveImage(url,

albumName:

"Flutter App Demo"

)

.whenComplete(()

=>

ScaffoldMessenger.of(context)

.showSnackBar(

const

SnackBar(

content: Text(

"Saved to Gallery!"

))));

},

icon:

const

Icon(Icons.download_rounded),

label:

const

Text(

"Save to Gallery"

)),

const

SizedBox(

height:

8

,

),

ElevatedButton.icon(

onPressed: ()

async

{

setState(() {

isUploading

=

true

;

});

await

uploadImage().whenComplete(() {

setState(() {

isUploading

=

false

;

});

ScaffoldMessenger.of(context)

.showSnackBar(

const

SnackBar(

content: Text(

"Uploaded Successfully!"

)));

});

},

icon:

const

Icon(Icons.cloud_upload_rounded),

label: isUploading

?

const

Text(

"Uploading..."

)

:

const

Text(

"Upload to Firebase"

)),

],

),

],

)),

));

}

Future uploadImage()

async

{

if

(compressedImage

==

null

)

return

;

var

filePath

=

compressedImage

!

.path;

var

fileName

=

(filePath.split(

'/'

).last);

final

destination

=

"files/images/

$

fileName

"

;

await

FirebaseApi.uploadFile(destination, compressedImage

!

);

}

}

We derive the name of the file that we pick and store it in the variable fileName, as shown below:

final

fileName

=

image

!=

null

?

(image

!

.path.split(

'/'

).last)

:

"No Image Selected"

;

We will get the size of the picked file and that of the compressed image file like this:

final

fileSize

=

image

!=

null

?

(image

!

.lengthSync().roundToDouble()

/

1048576

).toStringAsFixed(

2

)

:

""

;

final

compressedFileSize

=

compressedImage

!=

null

?

(compressedImage

!

.lengthSync().roundToDouble()

/

1048576

)

.toStringAsFixed(

2

)

:

""

;

Uploading an image to Firebase

We have created a function uploadImage() which will enable us to upload the image to Firebase storage with the help of the Firebase API that we created, as demonstrated below:

Future uploadImage()

async

{

if

(compressedImage

==

null

)

return

;

var

filePath

=

compressedImage

!

.path;

var

fileName

=

(filePath.split(

'/'

).last);

final

destination

=

"files/images/

$

fileName

"

;

await

FirebaseApi.uploadFile(destination, compressedImage

!

);

}

We first retrieve the name of the compressed image from its path. We then set the destination, which is a required argument by the Firebase API function, uploadFile().

The destination is the path in the Firebase storage bucket where the file will be stored. In our case, we will store images, videos, and documents in different folders.

Finally, we will call the function, uploadFile() from the Firebase API and pass the required arguments, i.e., the destination of the file and the file itself as shown in the code above.

We have created a function to save the compressed image to the local storage. We have used the gallery_saver package to achieve that, as shown below:

String

url

=

compressedImage

!

.path;

GallerySaver.saveImage(url, albumName:

"Flutter App Demo"

)

A new album is created by the name provided and the image is saved there.

Video Screen

The video screen is almost similar to the image screen. We have only added a few extra functions that we will use for manipulating our video files such as video compressing.

This is the code for the video screen:

import

'dart:io'

;

import

'package:flutter/material.dart'

;

import

'package:gallery_saver/gallery_saver.dart'

;

import

'package:video_compress/video_compress.dart'

;

import

'../services/file.compression.api.dart'

;

import

'../services/file.picker.api.dart'

;

import

'../services/firebase.api.dart'

;

class

VideoScreen

extends

StatefulWidget {

const

VideoScreen({Key

?

key})

:

super

(key: key);

@

override

State

<

VideoScreen

>

createState()

=>

_VideoScreenState();

}

class

_VideoScreenState

extends

State

<

VideoScreen

>

{

File

?

videoFile;

MediaInfo

?

compressedVideoInfo;

bool

isUploading

=

false

;

bool

isCompressing

=

false

;

@

override

Widget build(BuildContext context) {

final

fileName

=

videoFile

!=

null

?

(videoFile

!

.path.split(

'/'

).last)

:

"No Video Selected"

;

final

fileSize

=

videoFile

!=

null

?

(videoFile

!

.lengthSync().roundToDouble()

/

1048576

).toStringAsFixed(

2

)

:

""

;

return

Scaffold(

appBar: AppBar(

title:

const

Text(

"Select Video"

),

centerTitle:

true

,

),

body: Center(

child: Padding(

padding:

const

EdgeInsets.all(

30

),

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: [

Text(

fileName,

style:

const

TextStyle(

fontSize:

18

,

fontWeight: FontWeight.w600,

),

textAlign: TextAlign.center,

),

const

SizedBox(

height:

8

,

),

Text(

videoFile

!=

null

?

"File Size:

$

fileSize

MB"

:

""

,

style:

const

TextStyle(

fontSize:

16

,

fontWeight: FontWeight.w600,

),

textAlign: TextAlign.center,

),

const

SizedBox(

height:

10

,

),

if

(videoFile

==

null

)

ElevatedButton.icon(

onPressed: ()

async

{

final

result

=

await

FilePickerApi.pickVideo();

if

(result

==

null

) {

return

;

}

final

filePath

=

result.path;

setState(() {

videoFile

=

File(filePath);

});

},

icon:

const

Icon(Icons.video_file),

label:

const

Text(

"Pick Video"

))

else

(compressedVideoInfo

==

null

)

?

ElevatedButton(

onPressed: ()

async

{

setState(() {

isCompressing

=

true

;

});

final

result

=

await

FileCompressionApi.compressVideo(

videoFile

!

);

if

(result

==

null

) {

return

;

}

setState(() {

compressedVideoInfo

=

result;

videoFile

=

File(result.file

!

.path);

isCompressing

=

false

;

});

},

child: isCompressing

?

const

Text(

"Compressing..."

)

:

const

Text(

"Compress Video"

))

:

Column(

children: [

ElevatedButton.icon(

onPressed: ()

async

{

String

url

=

compressedVideoInfo

!

.file

!

.path;

GallerySaver.saveVideo(url,

albumName:

"Flutter App Demo"

)

.whenComplete(()

=>

ScaffoldMessenger.of(context)

.showSnackBar(

const

SnackBar(

content: Text(

"Saved to Gallery!"

))));

},

icon:

const

Icon(Icons.download_rounded),

label:

const

Text(

"Save to Gallery"

)),

const

SizedBox(

height:

8

,

),

ElevatedButton.icon(

onPressed: ()

async

{

setState(() {

isUploading

=

true

;

});

await

uploadVideo().whenComplete(() {

setState(() {

isUploading

=

false

;

});

ScaffoldMessenger.of(context)

.showSnackBar(

const

SnackBar(

content: Text(

"Uploaded Successfully!"

)));

});

},

icon:

const

Icon(Icons.cloud_upload_rounded),

label: isUploading

?

const

Text(

"Uploading..."

)

:

const

Text(

"Upload to Firebase"

)),

],

),

],

)),

));

}

Future uploadVideo()

async

{

if

(compressedVideoInfo

==

null

)

return

;

var

filePath

=

compressedVideoInfo

!

.file

!

.path;

var

fileName

=

(filePath.split(

'/'

).last);

final

destination

=

"files/videos/

$

fileName

"

;

await

FirebaseApi.uploadFile(destination, compressedVideoInfo

!

.file

!

);

}

}

When we compress a video a MediaInfo file containing the media information is returned. It contains the path to the file, the file size, title, author, duration e.t.c.

For our case, we will only use the file path. From here the picked video will be replaced with the new compressed video:

setState(() {

isCompressing

=

true

;

});

final

result

=

await

FileCompressionApi.compressVideo(videoFile

!

);

if

(result

==

null

) {

return

;

}

setState(() {

compressedVideoInfo

=

result;

videoFile

=

File(result.file

!

.path);

isCompressing

=

false

;

});

We store the media information which is returned when the compression is successful in the MediaInfo variable that we created earlier:

MediaInfo

?

compressedVideoInfo;

From the media information, we derive the file path of the compressed video. The new video file will be the compressed video:

videoFile

=

File(result.file

!

.path);

Document Screen

We maintained a consistent user interface for all the screens. In the document screen, we will be able to pick a document from the phone storage, encrypt the document and then upload it to Firebase storage.

This is demonstrated below:

import

'dart:io'

;

import

'package:file_saver/file_saver.dart'

;

import

'package:flutter/material.dart'

;

import

'package:flutter_app_demo/services/file.encryption.api.dart'

;

import

'package:flutter_app_demo/services/file.picker.api.dart'

;

import

'package:flutter_app_demo/services/firebase.api.dart'

;

class

DocumentScreen

extends

StatefulWidget {

const

DocumentScreen({Key

?

key})

:

super

(key: key);

@

override

State

<

DocumentScreen

>

createState()

=>

_DocumentScreenState();

}

class

_DocumentScreenState

extends

State

<

DocumentScreen

>

{

File

?

doc;

bool

isUploading

=

false

;

bool

isEncrypting

=

false

;

@

override

Widget build(BuildContext context) {

final

fileName

=

doc

!=

null

?

(doc

!

.path.split(

'/'

).last)

:

"No Document Selected"

;

//Getting the name of the selected document

return

Scaffold(

appBar: AppBar(

title:

const

Text(

"Select Document"

),

centerTitle:

true

,

),

body: Center(

child: Padding(

padding:

const

EdgeInsets.all(

30

),

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: [

Text(

fileName,

style:

const

TextStyle(

fontSize:

18

,

fontWeight: FontWeight.w600,

),

textAlign: TextAlign.center,

),

const

SizedBox(

height:

10

,

),

(doc

==

null

)

?

ElevatedButton.icon(

onPressed: ()

async

{

final

result

=

await

FilePickerApi.pickDocument();

if

(result

==

null

) {

return

;

}

final

filePath

=

result.path;

setState(() {

doc

=

File(filePath);

});

},

icon:

const

Icon(Icons.attach_file),

label:

const

Text(

"Select Document"

))

:

Column(

children: [

ElevatedButton(

onPressed: ()

async

{

setState(() {

isEncrypting

=

true

;

});

final

result

=

await

FileEcryptionApi.encryptFile(

doc

!

.readAsBytesSync());

//Changing the file into a list of bytes

await

FileSaver.instance

//Saving the encrypted document to local storage

.saveAs(fileName, result

!

,

"aes"

,

MimeType.OTHER)

.whenComplete(() {

setState(() {

isEncrypting

=

false

;

});

ScaffoldMessenger.of(context).showSnackBar(

const

SnackBar(

content: Text(

"Successfully encrypted!"

)));

});

},

child: isEncrypting

?

const

Text(

"Encrypting..."

)

:

const

Text(

"Encrypt Document"

)),

const

SizedBox(

height:

10

,

),

ElevatedButton.icon(

onPressed: ()

async

{

setState(() {

isUploading

=

true

;

});

await

uploadDocument().whenComplete(() {

setState(() {

isUploading

=

false

;

});

ScaffoldMessenger.of(context).showSnackBar(

const

SnackBar(

content: Text(

"Uploaded Successfully!"

)));

});

},

icon:

const

Icon(Icons.cloud_upload_rounded),

label: isUploading

?

const

Text(

"Uploading..."

)

:

const

Text(

"Upload to Firebase"

)),

],

),

],

)),

));

}

Future uploadDocument()

async

{

// Function to upload the picked document to Firebase

if

(doc

==

null

)

return

;

var

filePath

=

doc

!

.path;

var

fileName

=

(filePath.split(

'/'

).last);

final

destination

=

"files/documents/

$

fileName

"

;

await

FirebaseApi.uploadFile(destination, doc

!

);

}

}

Document File encryption

When encrypting the file, we first get the file we want to encrypt. For our case, we will use the document that we pick from the local storage.

The file is read and changed into a list of bytes which is the required format to be able to encrypt the file.

Once we have successfully changed the file into a list of bytes, the file is encrypted using the AES algorithm. This is done by calling the File Encryption API that we created earlier.

final

result

=

await

FileEcryptionApi.encryptFile(doc

!

.readAsBytesSync());

//Changing the file into a list of bytes

Once the encryption is complete, the encrypted file is saved to the local storage by passing the list of bytes, the file name, and the file extension as shown below:

await

FileSaver.instance.saveAs(fileName, result

!

,

"aes"

, MimeType.OTHER);

//Saving the encrypted file to the local storage

main.dart

The main.dart is the root of the application from where all other widgets form the widget tree.

For our main function we will initialize our Firebase app as follows:

import

'package:firebase_core/firebase_core.dart'

;

// Make sure this package is imported.

void

main()

async

{

WidgetsFlutterBinding.ensureInitialized();

await

Firebase.initializeApp();

runApp(

const

MyApp());

}

Next, we will set the home page to be the home screen that we created earlier:

class

MyApp

extends

StatelessWidget {

const

MyApp({Key

?

key})

:

super

(key: key);

// This widget is the root of your application.

@

override

Widget build(BuildContext context) {

return

MaterialApp(

title:

'Flutter App Demo'

,

theme: ThemeData(

primarySwatch: Colors.indigo,

),

home:

const

HomeScreen(),

// Here we set the first page that will appear when we start the application

);

}

}

Conclusion

In this article, we have gone through how to pick different types of files from the local storage and manipulate them.

We were able to pick videos and images from the gallery and compress them to achieve a smaller image and video size. This is a way of optimizing data usage when uploading such files to cloud storage.

We have also gone through the process of encrypting documents and uploading videos, images, and document files to Firebase storage. I do hope this article is useful.

Happy coding!

Peer Review Contributions by: Wanja Mike