Created
August 14, 2022 08:22
-
-
Save abdullahalamodi/a7c7208e52f73414afb49c837f04275d to your computer and use it in GitHub Desktop.
upload, download and show files from google drive
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:developer'; | |
import 'dart:io'; | |
import 'package:google_sign_in/google_sign_in.dart'; | |
import 'package:googleapis/drive/v3.dart' as g_drive; | |
import 'package:http/http.dart' as http; | |
import 'package:path_provider/path_provider.dart'; | |
class GoogleAuthClient extends http.BaseClient { | |
final Map<String, String> _headers; | |
final _client = http.Client(); | |
GoogleAuthClient(this._headers); | |
@override | |
Future<http.StreamedResponse> send(http.BaseRequest request) { | |
request.headers.addAll(_headers); | |
return _client.send(request); | |
} | |
} | |
extension FileNameEx on File { | |
String get nameWithEx => path.substring(path.lastIndexOf('/') + 1); | |
} | |
class GoogleDriveServices { | |
g_drive.DriveApi? driveApi; | |
final GoogleSignIn _googleSignIn = GoogleSignIn.standard( | |
scopes: [g_drive.DriveApi.driveScope], | |
); | |
Future<g_drive.DriveApi?> _getDriveApi( | |
GoogleSignInAccount? googleUser, | |
) async { | |
if (driveApi == null) { | |
final headers = await googleUser?.authHeaders; | |
if (headers == null) { | |
return null; | |
} | |
final client = GoogleAuthClient(headers); | |
driveApi = g_drive.DriveApi(client); | |
} | |
return driveApi; | |
} | |
Future<GoogleSignInAccount?> signIn({bool silently = false}) => | |
silently ? _googleSignIn.signInSilently() : _googleSignIn.signIn(); | |
Future<bool> isSignedIn() => _googleSignIn.isSignedIn(); | |
Future<void> signOut() => _googleSignIn.disconnect(); | |
// upload file to google drive | |
Future<void> uploadFile( | |
File file, | |
GoogleSignInAccount? googleUser, | |
) async { | |
final driveApi = await _getDriveApi(googleUser); | |
if (driveApi == null) return; | |
final appFolderId = await _getMyAppFolderId(driveApi); | |
if (appFolderId == null) { | |
log('backup: folderId == null, need sign in'); | |
return; | |
} | |
// Create a folder | |
var folderInfo = g_drive.File(); | |
folderInfo.name = DateTime.now().millisecondsSinceEpoch.toString(); | |
folderInfo.mimeType = _mimeType; | |
folderInfo.parents = [appFolderId]; | |
final backupfolder = await driveApi.files.create(folderInfo); | |
try { | |
final datInfo = | |
g_drive.File(name: file.nameWithEx, parents: [backupfolder.id!]); | |
final datRresponse = await driveApi.files.create( | |
datInfo, | |
uploadMedia: g_drive.Media( | |
file.openRead(), | |
file.lengthSync(), | |
), | |
); | |
log(datRresponse.toJson().toString()); | |
} catch (e) { | |
//if not completed the backup (uplade the file) delete the folder | |
// so that no corrupted files remain | |
driveApi.files.delete(backupfolder.id!); | |
rethrow; | |
} | |
// when backup (uplade the file) successfuly delete others if exist | |
final fileList = await driveApi.files.list( | |
q: "'$appFolderId' in parents", | |
$fields: "files(id, name)", | |
); | |
final backupsList = fileList.files ?? []; | |
for (var item in backupsList) { | |
if (item.id != backupfolder.id!) { | |
await driveApi.files.delete(item.id!); | |
} | |
} | |
} | |
Future<g_drive.File?> _getFileByFolderId( | |
g_drive.DriveApi driveApi, | |
String folderId, | |
) async { | |
try { | |
final found = await driveApi.files.list( | |
q: "'$folderId' in parents", | |
$fields: "files(id, name)", | |
); | |
final files = found.files; | |
return files?.first; | |
} catch (e) { | |
log(e.toString()); | |
return null; | |
} | |
} | |
Future<List<int>> futureFromStream(Stream<List<int>> stream) async { | |
List<int> sum = []; | |
await for (final value in stream) { | |
sum += value; | |
} | |
return sum; | |
} | |
// download file form google drive by folder id. | |
// I have one file in my folder so I get that file by query | |
// that folder this is what is suitable for my case | |
// 💡 you can search and query files as you want | |
// by follow this link https://developers.google.com/drive/api/guides/search-files | |
Future<File?> downloadFileByFolderId({ | |
required final String folderId, | |
required final GoogleSignInAccount? googleUser, | |
final String fileNameWithEx = 'downloaded_file.txt', | |
}) async { | |
final driveApi = await _getDriveApi(googleUser); | |
if (driveApi == null) return null; | |
// query folder to get file | |
final driveFile = await _getFileByFolderId(driveApi, folderId); | |
if (driveFile == null) return null; | |
final directory = await getApplicationDocumentsDirectory(); | |
// | |
final fileMedia = (await driveApi.files.get(driveFile.id!, | |
downloadOptions: g_drive.DownloadOptions.fullMedia)) as g_drive.Media; | |
// the palce you safe the file. 💡 you can pass it as parameter instead of file name with ex | |
File? newFile = File('${directory.path}/$fileNameWithEx'); | |
List<int> dataStore = []; | |
dataStore = await futureFromStream(fileMedia.stream); | |
await newFile.writeAsBytes(dataStore); | |
// TODO for debug !! | |
log("lckFile: File saved at ${newFile.path}"); | |
log("lckFile: File name: ${newFile.nameWithEx}"); | |
return newFile; | |
} | |
// get all files in a spicific folder. ( ❗ the file "id and name" not the file media) | |
// you can desplay them as list | |
Future<List<g_drive.File>?> getFiles({ | |
required final GoogleSignInAccount? googleUser, | |
}) async { | |
final driveApi = await _getDriveApi(googleUser); | |
if (driveApi == null) return null; | |
final appFolderId = await _getMyAppFolderId(driveApi); | |
final found = await driveApi.files.list( | |
q: "'$appFolderId' in parents", | |
$fields: "files(id, name)", | |
); | |
final files = found.files ?? []; | |
return files.isEmpty ? null : files; | |
} | |
// we assume that you will create folder | |
// for your app on google drive to store your data on | |
Future<String?> _getMyAppFolderId( | |
g_drive.DriveApi driveApi, | |
) async { | |
try { | |
// search for folder by name | |
final found = await driveApi.files.list( | |
q: "mimeType = '$_mimeType' and name = '$_folderName'", | |
$fields: "files(id, name)", | |
); | |
final files = found.files; | |
if (files == null) return null; | |
// Create a folder for first time | |
if (files.isEmpty) { | |
var folder = g_drive.File(); | |
folder.name = _folderName; | |
folder.mimeType = _mimeType; | |
final folderCreation = await driveApi.files.create(folder); | |
log("Folder ID: ${folderCreation.id}"); | |
return folderCreation.id; | |
} else { | |
return files.first.id; | |
} | |
} catch (e) { | |
log(e.toString()); | |
return null; | |
} | |
} | |
static const _mimeType = "application/vnd.google-apps.folder"; | |
static const _folderName = "myAppFolder"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment