I am trying to retrieve files stored is firebase storage to my app and later download them but I'm getting the error: W/NetworkRequest( 5407): No App Check token for request.
Below is my code snippet:
final firebase_storage.Reference ref = firebase_storage
.FirebaseStorage.instance
.ref('product/${data['file_name']}');
final Directory appDocDir = await getApplicationDocumentsDirectory();
final String appDocPath = appDocDir.path;
final File tempFile = File(appDocPath + '/' + '${data['file_name']}');
try {
await ref.writeToFile(tempFile);
await tempFile.create();
await OpenFile.open(tempFile.path);
} on firebase_core.FirebaseException {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Error, file tidak bisa diunduh',
style: Theme.of(context).textTheme.bodyText1,
),
),
);
}
Related
Below is a snippet of code from a function that uploads a generated QR code (using the qr_flutter package) to firebase storage; then gets the firebase storage url to save in a custom model that is uploaded to firebase firestore (not shown).
This works fine, however I want to upload a file that consists of the QR code bounded by title text above and address text below. (Essentially a Column with children [title, qrFile, address]).
My question is: How do I combine Text and my qrFile into a single image file that I can upload to firebase storage?
String qrString = 'qr_data_here';
final qrValidationResult = QrValidator.validate(
data: qrString,
version: QrVersions.auto,
errorCorrectionLevel: QrErrorCorrectLevel.L,
);
if (qrValidationResult.status == QrValidationStatus.valid) {
final qrCode = qrValidationResult.qrCode;
const String title = 'title_name_here';
final String address = 'address_here';
final painter = QrPainter.withQr(
qr: qrCode!,
color: const Color(0xFF000000),
gapless: true,
embeddedImageStyle: null,
embeddedImage: null,
);
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
final ts = DateTime.now().millisecondsSinceEpoch.toString();
String path = '$tempPath/$ts.png';
// ui is from import 'dart:ui' as ui;
final picData =
await painter.toImageData(2048, format: ui.ImageByteFormat.png);
// writeToFile is seen in code snippet below
await writeToFile(
picData!,
path,
);
} else {
genericErrorDialog(context);
}
// qrStorage is a reference to a folder in firebase storage
await qrStorage.child('name_here').putFile(qrFile);
var url =
await qrStorage.child('name_here').getDownloadURL();
late File qrFile;
Future<void> writeToFile(ByteData data, String path) async {
final buffer = data.buffer;
qrFile = await File(path).writeAsBytes(
buffer.asUint8List(data.offsetInBytes, data.lengthInBytes));
}
One solution is to use the screenshot package (https://pub.dev/packages/screenshot). This package has a function to save a widget as an image (without displaying it on screen) as shown below.
ScreenshotController screenshotController = ScreenshotController();
await screenshotController
.captureFromWidget(CustomWidget())
.then((capturedImage) async {
await do_something_with_capturedImage_here();
});
As it relates to my question specifically; Below is the code to generate a qr code, place it in a widget (needs some more formatting) with text, and then save the widget as an image file and upload to firebase.
String qrString = 'qr_data_here';
final qrValidationResult = QrValidator.validate(
data: qrString,
version: QrVersions.auto,
errorCorrectionLevel: QrErrorCorrectLevel.L,
);
if (qrValidationResult.status == QrValidationStatus.valid) {
final qrCode = qrValidationResult.qrCode;
const String title = 'title_name_here';
final String address = 'address_here';
final painter = QrPainter.withQr(
qr: qrCode!,
color: const Color(0xFF000000),
gapless: true,
embeddedImageStyle: null,
embeddedImage: null,
);
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
final ts = DateTime.now().millisecondsSinceEpoch.toString();
String path = '$tempPath/$ts.png';
// ui is from import 'dart:ui' as ui;
final picData =
await painter.toImageData(2048, format: ui.ImageByteFormat.png);
// writeToFile is seen in code snippet below
await writeToFile(
picData!,
path,
);
await screenshotController
.captureFromWidget(Column(
children: [
Text(title),
Image.file(qrFile),
Text(address),
],
))
.then((capturedImage) async {
await widgetToImageFile(capturedImage);
});
} else {
genericErrorDialog(context);
}
// qrStorage is a reference to a folder in firebase storage
await qrStorage.child('name_here').putFile(fullQrFile);
var url =
await qrStorage.child('name_here').getDownloadURL();
ScreenshotController screenshotController = ScreenshotController();
late File qrFile;
late File fullQrFile;
Future<void> writeToFile(ByteData data, String path) async {
final buffer = data.buffer;
qrFile = await File(path).writeAsBytes(
buffer.asUint8List(data.offsetInBytes, data.lengthInBytes));
}
Future<void> widgetToImageFile(
Uint8List capturedImage,
) async {
Directory newTempDir = await getTemporaryDirectory();
String newTempPath = newTempDir.path;
final newTs = DateTime.now().millisecondsSinceEpoch.toString();
String path = '$newTempPath/$newTs.png';
fullQrFile = await File(path).writeAsBytes(capturedImage);
}
I want to save an image inside a folder with a name that matches with the users email when signing up.
The flow of the file in Firebase Storage is like this
usersProfilePic -> test#gmail.com(users email) -> image_picker.jpg(the pic)
This is my code
uploadImage() async {
//upload the image to storage
var imageFile = FirebaseStorage.instance
.ref()
.child("usersProfilePic")
.child("the email of the user")
.child(basename(_image!.path));
UploadTask task = imageFile.putFile(_image!);
TaskSnapshot snapshot = await task;
//for download
url = await snapshot.ref.getDownloadURL();
print(url);
}
//add user to firebase
addUserToFirebase() async {
await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password)
.then((value) {
print(value.user!.uid);
ScaffoldMessenger.of(this.context).showSnackBar(
const SnackBar(
backgroundColor: kSoftLimeGreen,
content: Text(
"Registered Successfully. Please Login..",
style: TextStyle(fontSize: 20.0),
),
),
);
Navigator.pushReplacement(
this.context,
MaterialPageRoute(
builder: (context) => const LoginPage(),
),
);
});
await FirebaseFirestore.instance.collection('user').doc().set({
'name': name,
'phoneNumber': phoneNumber,
'email': email,
'password': password,
'confirmPassword': confirmPassword,
'imageProfileUrl': url,
});
}
All of the code is working as intended, I only need on how to save the image inside a folder with the users email as the name of the folder.
If you have any solution, please share with me. Thank you
Something like this should work:
if (FirebaseAuth.instance.currentUser != null) {
var email = FirebaseAuth.instance.currentUser.email
var imageFile = FirebaseStorage.instance
.ref()
.child("usersProfilePic")
.child(email)
.child(basename(_image!.path));
...
https://pub.dev/packages/share
Dependency:
share: ^0.6.5+2
Local file directory
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Share function
Future<void> _onShare(BuildContext context) async {
final RenderBox box = context.findRenderObject();
final path = await _localPath;
await Share.shareFiles(
['$path/assets/images/${widget.imgUrl}.png'],
text: text,
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size);
}
Button - on press
FlatButton(child: Text('Share'), onPressed: () => _onShare(context)),
I'm using this package to share image from application. I have no issue sharing text but when I add the function to share image, I keep getting errors for missing image.
Am I doing it correctly?
Managed to figure out the problem.
Seems like I need to save image before I can reference the image.
final ByteData bytes = await rootBundle
.load('assets/images/${widget.imgUrl}.png');
final Uint8List list = bytes.buffer.asUint8List();
final directory = (await getExternalStorageDirectory()).path;
File imgFile = File('$directory/screenshot.png');
imgFile.writeAsBytesSync(list);
Share.shareFiles(['$directory/screenshot.png'],
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size);
I'm making functionality to be able to upload images to firebase storages through the Flutter Web. I need a list a files, where each file is 'File' type, but i get a type 'File$'.
import 'dart:io' as io;
SpeedDial(
animatedIconTheme: IconThemeData(size: 22.0),
child: Icon(Icons.add),
closeManually: false,
children: [
SpeedDialChild(
child: Icon(Icons.photo_library),
label: translate('agreement.image_uploader.select_images_button', context: context),
onTap: () => _callAddImagesFromWeb(context)),
],
)
_callAddImagesFromWeb(BuildContext context) async {
print('Called _callAddImagesFromWeb: upload images from web app');
html.InputElement uploadInput = html.FileUploadInputElement();
uploadInput.multiple = true;
uploadInput.click();
uploadInput.onChange.listen((changeEvent) {
print("User added images, length: " + uploadInput.files.length.toString());
allProcessAmount = uploadInput.files.length;
doneProcessAmount = 0;
uploadFile(uploadInput.files);
});
}
Method uploadFile get a list of Files and i need to storage each file to Firebase storage, but when i take one element from list, i get an error that ** Error: Expected a value of type 'File', but got one of type 'File$' **
Future uploadFile(List list) async {
// EXCEPTION IS HERE
io.File image = list.first;
var fileName = new DateTime.now().millisecondsSinceEpoch.toString();
StorageReference storageReference = FirebaseStorage.instance
.ref()
.child('agreements/' + widget.agreement.id + '/' + fileName);
StorageUploadTask uploadTask = storageReference.putFile(image);
await uploadTask.onComplete;
print('File Uploaded');
storageReference.getDownloadURL().then((fileURL) {
print(fileURL);
});
}
I'm using sqflite for my flutter project and now, I want to backup and then restore it. I searched for this issue but can't find a result. Is there any way to do it?
You can use this solution, it performs the backup of your bank with encryption or not, it's up to you, in addition to migrating from one version of the bank to another when, for example, the user is updating the application and the bank is a old version. I hope I helped, sorry for the writing because I don't speak English.
Dependencies
dependencies:
encrypt: ^4.1.0
path: ^1.7.0
sqflite: ^1.3.1
Class
import 'dart:async';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'dart:convert' as convert;
import 'package:encrypt/encrypt.dart' as encrypt ;
class DatabaseRepository {
Database _db;
static const SECRET_KEY = "2021_PRIVATE_KEY_ENCRYPT_2021";
static const DATABASE_VERSION = 1;
List<String> tables =[
];
Future<Database> get db async
{
if(_db != null)
{
return _db;
}
else
{
_db = await initDb(DATABASE_VERSION);
return _db;
}
}
Future<String> _databasePath() async
{
String databasesPath = await getDatabasesPath();
return join(databasesPath, "database.db");
}
Future<Database> initDb(int version) async
{
String path = await _databasePath();
return await openDatabase(path, version:version, onCreate: onCreate,onUpgrade: onUpgrade);
}
Future deleteDB() async
{
String path = await _databasePath();
await deleteDatabase(path);
}
FutureOr onCreate(Database db, int newerVersion) => this._onCreates[newerVersion](db);
Map<int,Function> _onCreates = {
1:(Database db) async {
print("DATABASE CREATE v1");
},
2:(Database db) async{
print("DATABASE CREATE v2");
},
3:(Database db) async{
print("DATABASE CREATE v3");
},
};
FutureOr<void> onUpgrade(Database db , int oldVersion, int newVersion ) async
{
for (var migration = oldVersion; migration < newVersion; migration++)
{
this._onUpgrades["from_version_${migration}_to_version_${migration+1}"](db);
}
}
Map<String,Function> _onUpgrades = {
'from_version_1_to_version_2':(Database db) async {
print('from_version_1_to_version_2');
},
'from_version_2_to_version_3':(Database db) async {
print('from_version_2_to_version_3');
},
};
Future clearAllTables() async
{
try
{
var dbs = await this.db;
for (String table in [
])
{
await dbs.delete(table);
await dbs.rawQuery("DELETE FROM sqlite_sequence where name='$table'");
}
print('------ CLEAR ALL TABLE');
}
catch(e){}
}
Future<String>generateBackup({bool isEncrypted = false}) async {
print('GENERATE BACKUP');
var dbs = await this.db;
List data =[];
List<Map<String,dynamic>> listMaps=[];
for (var i = 0; i < tables.length; i++)
{
listMaps = await dbs.query(tables[i]);
data.add(listMaps);
}
List backups=[tables,data];
String json = convert.jsonEncode(backups);
if(isEncrypted)
{
var key = encrypt.Key.fromUtf8(SECRET_KEY);
var iv = encrypt.IV.fromLength(16);
var encrypter = encrypt.Encrypter(encrypt.AES(key));
var encrypted = encrypter.encrypt(json, iv: iv);
return encrypted.base64;
}
else
{
return json;
}
}
Future<void>restoreBackup(String backup,{ bool isEncrypted = false}) async {
var dbs = await this.db;
Batch batch = dbs.batch();
var key = encrypt.Key.fromUtf8(SECRET_KEY);
var iv = encrypt.IV.fromLength(16);
var encrypter = encrypt.Encrypter(encrypt.AES(key));
List json = convert.jsonDecode(isEncrypted ? encrypter.decrypt64(backup,iv:iv):backup);
for (var i = 0; i < json[0].length; i++)
{
for (var k = 0; k < json[1][i].length; k++)
{
batch.insert(json[0][i],json[1][i][k]);
}
}
await batch.commit(continueOnError:false,noResult:true);
print('RESTORE BACKUP');
}
}
Use:
final DatabaseRepository databaseRepository = new DatabaseRepository();
String backup = await databaseRepository.generateBackup(isEncrypted: true);
await databaseRepository.clearAllTables();
await databaseRepository.restoreBackup(backup,isEncrypted: true);
For complete details, go to link
ElevatedButton(
onPressed: () async {
final dbFolder = await getDatabasesPath();
File source1 = File('$dbFolder/doggie_database.db');
Directory copyTo =
Directory("storage/emulated/0/Sqlite Backup");
if ((await copyTo.exists())) {
// print("Path exist");
var status = await Permission.storage.status;
if (!status.isGranted) {
await Permission.storage.request();
}
} else {
print("not exist");
if (await Permission.storage.request().isGranted) {
// Either the permission was already granted before or the user just granted it.
await copyTo.create();
} else {
print('Please give permission');
}
}
String newPath = "${copyTo.path}/doggie_database.db";
await source1.copy(newPath);
setState(() {
message = 'Successfully Copied DB';
});
},
child: const Text('Copy DB'),
),
ElevatedButton(
onPressed: () async {
var databasesPath = await getDatabasesPath();
var dbPath = join(databasesPath, 'doggie_database.db');
FilePickerResult? result =
await FilePicker.platform.pickFiles();
if (result != null) {
File source = File(result.files.single.path!);
await source.copy(dbPath);
setState(() {
message = 'Successfully Restored DB';
});
} else {
// User canceled the picker
}
},
child: const Text('Restore DB'),
),
dependencies:
sqflite: ^2.0.0+3
path_provider: ^2.0.11
permission_handler: ^10.0.0
Export ( back up)
To export SQFLite database , I came across some errors , some of the error are
FileSystemException: Cannot open file, path
error: permission denied, errno = 13
etc........
I want to export my Database into Download folder that is ,
this is my Database path /data/user/0/com.example.reminder_app/databases/notes.db , it's a application directory path so my aim is to export notes.db file into this path
/storage/emulated/0/Download/
Expanding dBToCopy functions , this function will give path of Database
Future<File> dBToCopy() async {
final db = await instance.database;
final dbPath = await getDatabasesPath();
var afile = File(dbPath);
return afile;
}
full code bellow
dbExportToDownloadFolder() async {
File result = await NotesDatabase.instance.dBToCopy();
print("lllllllllllllllllll ${result.absolute.path}");
Directory documentsDirectory =
Directory("storage/emulated/0/Download/");
String newPath = join(documentsDirectory.absolute.path + 'abcde.db');
File b =
File("/data/user/0/com.example.reminder_app/databases/notes.db");
if ( await Permission.storage.request().isGranted &&
await Permission.accessMediaLocation.request().isGranted &&
await Permission.manageExternalStorage.request().isGranted )
{
File a = await b.copy(newPath);
} else {
print("No Permission Granted");
}
}
Note
File result = await NotesDatabase.instance.dBToCopy();
print("lllllllllllllllllll ${result.absolute.path}");
OutPut print
lllllllllllllllllll /data/user/0/com.example.reminder_app/databases
this result file not contain the notes.db file , only contain this path
/data/user/0/com.example.reminder_app/databases
To get the DatabaseFile
File b = File("/data/user/0/com.example.reminder_app/databases/notes.db");
or
File b = File("${result.path}"+"/notes.db");
so using the file b we can copy the file to Download folder file that is abcde.db
To do that create a file in Download , that is abcde.db
Directory documentsDirectory = Directory("storage/emulated/0/Download/");
String newPath = join(documentsDirectory.absolute.path + 'abcde.db');
and using the copy method , to copy one file to another file
File a = await b.copy(newPath);
Note
If you are getting permission denied errors and OS errors please add all permission in manifest , and using permission_handler allow all permissions
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>
after the copying , A new file created in Download folder that is abcde.db
Improt (restore)
To improt abcde.db file from Download to databases folder file that is notes.db
importDataBaseFile () async {
String recoveryPath =
"/data/user/0/com.example.noteapp/databases/notedb.db";
Directory backupPath = Directory("storage/emulated/0/Download/");
String newPath = join("${backupPath.absolute.path}" + 'abcde.db');
File backupFile = File(newPath);
backupFile.copy(recoveryPath);
NotesDatabase.instance.readAllNotes();
},
Expanding function readAllNotes ()
Future<List<Note>> readAllNotes() async {
final db = await instance.database;
final orderBy = '${NoteFields.time} ASC';
final result = await db.query(tableNotes, orderBy: orderBy);
return result.map((json) => Note.fromJson(json)).toList();
}
so importing operation is performs reversing the export operation .
use a FilePicker to pick Database file instead
Improt from file picker ( restore from file picker )
dependencies:
sqflite: ^2.0.0+3
path_provider: ^2.0.11
permission_handler: ^10.0.0
file_picker: ^5.0.1
full code :
importDataBaseFile () async {
bool? clear = await FilePicker.platform.clearTemporaryFiles();
print(clear);
FilePickerResult? result =
await FilePicker.platform.pickFiles();
String recoveryPath =
"/data/user/0/com.example.reminder_app/databases/notes.db";
String newPath = "${result!.files.single.path}";
File backupFile = File(newPath);
backupFile.copy(recoveryPath);
refreshNotes();
}
Note
this is the demo example so , you can add encryptions and choose different path to store the back up , it according to you
You can use this Guide to make your restore.
https://github.com/tekartik/sqflite/blob/master/sqflite/doc/opening_asset_db.md
With this, you can download from somewhere your .db and change with the phone version.
To backup, you can change some lines in exemple above.