Java.IO.FileNotFoundException: (No such file or directory) exception on saving pdf file to phone xamarin forms - android

On a click of a button I need to save pdf file.
Im using xf 4.6.1 and syncfusion component which has event - PdfViewerControl_DocumentSaveInitiated
In codebehind, when program should go to my renderer method Save() which is derivates from ISave class, it throws later on renderer method Save() => Java.IO.FileNotFoundException: 'Download/SavedDocument.pdf (No such file or directory)' exception.
COdebehind:
private void PdfViewerControl_DocumentSaveInitiated(object sender, Syncfusion.SfPdfViewer.XForms.DocumentSaveInitiatedEventArgs args)
{
Device.BeginInvokeOnMainThread(async () =>
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync<StoragePermission>();
if (status != PermissionStatus.Granted)
{
status = await Utils.CheckPermissions(new Plugin.Permissions.StoragePermission());
}
if (status == Plugin.Permissions.Abstractions.PermissionStatus.Granted)
{
string filePath = DependencyService.Get<ISave>().Save(args.SaveStream as MemoryStream);
string message = "The Kiid document has been saved to " + filePath;
DependencyService.Get<IAlertView>().Show(message);
}
});
}
Interface:
public interface ISave
{
string Save(MemoryStream fileStream);
}
AndroidRenderer:
public class SaveAndroid : ISave
{
public string Save(System.IO.MemoryStream stream)
{
string root = null;
string fileName = "SavedDocument.pdf";
if (Android.OS.Environment.IsExternalStorageEmulated)
{
root = Android.OS.Environment.DirectoryDownloads.ToString();
}
Java.IO.File myDir = new Java.IO.File(root + "/Syncfusion");
myDir.Mkdir();
Java.IO.File file = new Java.IO.File(myDir, fileName);
string filePath = file.Path;
if (file.Exists()) file.Delete();
Java.IO.FileOutputStream outs = new Java.IO.FileOutputStream(file);
outs.Write(stream.ToArray());
var ab = file.Path;
outs.Flush();
outs.Close();
return filePath;
}
}
On physical device, it goes to the method Save(), and it breaks on the line Java.IO.FileOutputStream outs = new Java.IO.FileOutputStream(file);
As you can see I added permission check for storage.
What could be?

Related

create an tempDir and save it into an IFile with the external_drive_lib

Currently i am Getting from the IDrive an folder which has a file and i am copying this file into a tempfile which i am reading with the Streamreader, but is there a way to create this IFIle or i chnage the tempfile and save it into the IFile?
public IFolder TryToGetFolder(IDrive drive, string folderPath)
{
if (drive.is_connected())
{
try
{
return drive.try_parse_folder(folderPath);
}
catch
{
return null;
}
}
else
return null;
}
//Tries to get a file in a folder or returns null
public IFile TryToGetFile(IFolder folder, string filename)
{
return folder.files.Where(f => f.name == filename).FirstOrDefault();
}
//Tries to read the text of a file or returns null
public string TryToGetFileText(IFile file)
{
//Uses the tempDir to copy the file to it
string tempDir = _tempDir + "temp-" + DateTime.Now.Ticks;
Directory.CreateDirectory(tempDir);
file.copy_sync(tempDir);
//Read file from tempDir
StreamReader reader = new StreamReader(tempDir + "\\" + file.name);
return reader.ReadToEnd();
}
//Tries to delete a file
public void TryToDeleteFile(IFile file)
{
if(file != null)
{
if (file.exists)
file.delete_sync();
}
}
I tried this but this is using a Process Class, which i havent seen before.
//Tries to Send a file from the WPF to the Android Device
public bool SendFileToAndroid(AndroidDevice device, string filePath, CWCProduct cWCProduct)
{
if (!device.Drive.is_connected())
return false;
try
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "adb",
Arguments = $"push {filePath} {cWCProduct}",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
process.Start();
process.WaitForExit();
return true;
}
catch
{
return false;
}
}

Is there any way to programmatically upload files from Android application to Google Drive? [duplicate]

Myself and many others have been struggling with setting up the Google Drive REST API v3 to work with Android apps. This mainly stems from the fact that the official Google documentation is missing a proper quick start guide for Android and we are left with finding scraps of (outdated and/or confusing) information dotted around - but what is needed is a complete up to date guide aimed at beginners to get us up and running so that they can open and edit files on their Drive, including how to set up credentials, dependencies, and manifests.
So I am asking if anyone would be willing to create such a guide, or can point to such a guide that has already been made that is a) relevant to the latest version of Google Drive API REST v3 detailed here and b) covers ALL above aspects that a beginner would need to be get started?
The guidelines posted by ArtOfWarfare here are absolutely perfect and exactly what I'm looking for - but are unfortunately out of date by several years. Can anyone provide an up-to-date version of this guide? Thank you kindly.
Before answering this question I want you to know that I got the code from here (https://ammar.lanui.online/integrate-google-drive-rest-api-on-android-app-bc4ddbd90820) and the documentation from Google was not much helpful for me. So this solution is from limited resources available to me.
I need the drive to upload and download files from my app. In drive I have to create a folder and I have to upload file from my app to that folder and download a file from the folder to my device. This code was working fine for me.
I believe that you must have completed Google login. If you don’t, go checkout this video (https://youtu.be/t-yZUqthDMM) .
To interact with the Drive API, you need to enable the Drive API service for your app. You can do this in Google Developer Console.
To enable the Drive API, complete these steps:
Go to the Google API Console.
Select a project.
In the sidebar on the left, expand APIs & auth and select APIs.
In the displayed list of available APIs, click the Drive API link and click Enable API.
If you completed it, then go to OAuth Consent screen in console and add the two scopes for drive and save it.
In your project add the dependencies below.
implementation 'com.google.android.gms:play-services-auth:17.0.0'// for google sign in
// for drive integration
implementation 'com.google.android.gms:play-services-auth:16.0.1'
implementation 'com.google.http-client:google-http-client-gson:1.26.0'
implementation('com.google.api-client:google-api-client-android:1.26.0') {
exclude group: 'org.apache.httpcomponents'
}
implementation('com.google.apis:google-api-services-drive:v3-rev136-1.25.0')
{
exclude group: 'org.apache.httpcomponents'
}
And inside android tag, in the same gradle file, add the packaging options.
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/notice.txt'
exclude 'META-INF/ASL2.0'
}
In your Manifest file, add the required permissions
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Here I am storing the downloaded file in external storage. So that’s why I added the permissions for External storage READ and WRITE
After Google sign In, ask permission to access Google drive. The code for it is given below.
private void checkForGooglePermissions() {
if (!GoogleSignIn.hasPermissions(
GoogleSignIn.getLastSignedInAccount(getApplicationContext()),
ACCESS_DRIVE_SCOPE,
SCOPE_EMAIL)) {
GoogleSignIn.requestPermissions(
MainActivity.this,
RC_AUTHORIZE_DRIVE,
GoogleSignIn.getLastSignedInAccount(getApplicationContext()),
ACCESS_DRIVE_SCOPE,
SCOPE_EMAIL);
} else {
Toast.makeText(this, "Permission to access Drive and Email has been granted", Toast.LENGTH_SHORT).show();
driveSetUp();
}
}
The variables ACCESS_DRIVE_SCOPE and SCOPE_EMAIL are,
Scope ACCESS_DRIVE_SCOPE = new Scope(Scopes.DRIVE_FILE);
Scope SCOPE_EMAIL = new Scope(Scopes.EMAIL);
After having permission and Sign In we have our GoogleSignInAccount object. With this object, create an object of GoogleAccountCredential, from which we can generate an object of Drive. The Drive object is what we needed for the communication between Google Drive.
private void driveSetUp() {
GoogleSignInAccount mAccount = GoogleSignIn.getLastSignedInAccount(MainActivity.this);
GoogleAccountCredential credential =
GoogleAccountCredential.usingOAuth2(
getApplicationContext(), Collections.singleton(Scopes.DRIVE_FILE));
credential.setSelectedAccount(mAccount.getAccount());
googleDriveService =
new com.google.api.services.drive.Drive.Builder(
AndroidHttp.newCompatibleTransport(),
new GsonFactory(),
credential)
.setApplicationName("GoogleDriveIntegration 3")
.build();
mDriveServiceHelper = new DriveServiceHelper(googleDriveService);
}
Here you can see I created an object of DriveServiceHelper class and passed the object of Drive(googleDriveSrvice) along with it.
DriveServiceHelper class is given below. I got it from here.( https://github.com/gsuitedevs/android-samples/blob/master/drive/deprecation/app/src/main/java/com/google/android/gms/drive/sample/driveapimigration/DriveServiceHelper.java?source=post_page-----bc4ddbd90820----------------------). You can use that one. I made some changes in that class for myself.
public class DriveServiceHelper {
private final Executor mExecutor = Executors.newSingleThreadExecutor();
private final Drive mDriveService;
private final String TAG = "DRIVE_TAG";
public DriveServiceHelper(Drive driveService) {
mDriveService = driveService;
}
/**
* Creates a text file in the user's My Drive folder and returns its file ID.
*/
public Task<GoogleDriveFileHolder> createFile(String folderId, String filename) {
return Tasks.call(mExecutor, () -> {
GoogleDriveFileHolder googleDriveFileHolder = new GoogleDriveFileHolder();
List<String> root;
if (folderId == null) {
root = Collections.singletonList("root");
} else {
root = Collections.singletonList(folderId);
}
File metadata = new File()
.setParents(root)
.setMimeType("text/plain")
.setName(filename);
File googleFile = mDriveService.files().create(metadata).execute();
if (googleFile == null) {
throw new IOException("Null result when requesting file creation.");
}
googleDriveFileHolder.setId(googleFile.getId());
return googleDriveFileHolder;
});
}
// TO CREATE A FOLDER
public Task<GoogleDriveFileHolder> createFolder(String folderName, #Nullable String folderId) {
return Tasks.call(mExecutor, () -> {
GoogleDriveFileHolder googleDriveFileHolder = new GoogleDriveFileHolder();
List<String> root;
if (folderId == null) {
root = Collections.singletonList("root");
} else {
root = Collections.singletonList(folderId);
}
File metadata = new File()
.setParents(root)
.setMimeType("application/vnd.google-apps.folder")
.setName(folderName);
File googleFile = mDriveService.files().create(metadata).execute();
if (googleFile == null) {
throw new IOException("Null result when requesting file creation.");
}
googleDriveFileHolder.setId(googleFile.getId());
return googleDriveFileHolder;
});
}
public Task<Void> downloadFile(java.io.File targetFile, String fileId) {
return Tasks.call(mExecutor, () -> {
// Retrieve the metadata as a File object.
OutputStream outputStream = new FileOutputStream(targetFile);
mDriveService.files().get(fileId).executeMediaAndDownloadTo(outputStream);
return null;
});
}
public Task<Void> deleteFolderFile(String fileId) {
return Tasks.call(mExecutor, () -> {
// Retrieve the metadata as a File object.
if (fileId != null) {
mDriveService.files().delete(fileId).execute();
}
return null;
});
}
// TO LIST FILES
public List<File> listDriveImageFiles() throws IOException{
FileList result;
String pageToken = null;
do {
result = mDriveService.files().list()
/*.setQ("mimeType='image/png' or mimeType='text/plain'")This si to list both image and text files. Mind the type of image(png or jpeg).setQ("mimeType='image/png' or mimeType='text/plain'") */
.setSpaces("drive")
.setFields("nextPageToken, files(id, name)")
.setPageToken(pageToken)
.execute();
pageToken = result.getNextPageToken();
} while (pageToken != null);
return result.getFiles();
}
// TO UPLOAD A FILE ONTO DRIVE
public Task<GoogleDriveFileHolder> uploadFile(final java.io.File localFile,
final String mimeType, #Nullable final String folderId) {
return Tasks.call(mExecutor, new Callable<GoogleDriveFileHolder>() {
#Override
public GoogleDriveFileHolder call() throws Exception {
// Retrieve the metadata as a File object.
List<String> root;
if (folderId == null) {
root = Collections.singletonList("root");
} else {
root = Collections.singletonList(folderId);
}
File metadata = new File()
.setParents(root)
.setMimeType(mimeType)
.setName(localFile.getName());
FileContent fileContent = new FileContent(mimeType, localFile);
File fileMeta = mDriveService.files().create(metadata,
fileContent).execute();
GoogleDriveFileHolder googleDriveFileHolder = new
GoogleDriveFileHolder();
googleDriveFileHolder.setId(fileMeta.getId());
googleDriveFileHolder.setName(fileMeta.getName());
return googleDriveFileHolder;
}
});
}
}
Remember the fact that whenever you create a file or folder or if you upload a file, the drive will give a unique id for it and you can access it. So it’s not the file name that is unique in here, it’s the id of the file. Hence if you upload or create a file of same name multiple times it will be saved in the folder multiple times. So if you want to replace a file with another file of the same name. First delete the file and save/ upload it.
To create a file, specify the folder id and file name to be created.
The GoogleDriveHolder class is given below.
public class GoogleDriveFileHolder {
private String id;
private String name;
private DateTime modifiedTime;
private long size;
private DateTime createdTime;
private Boolean starred;
public DateTime getCreatedTime() {
return createdTime;
}
public void setCreatedTime(DateTime createdTime) {
this.createdTime = createdTime;
}
public Boolean getStarred() {
return starred;
}
public void setStarred(Boolean starred) {
this.starred = starred;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public DateTime getModifiedTime() {
return modifiedTime;
}
public void setModifiedTime(DateTime modifiedTime) {
this.modifiedTime = modifiedTime;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
}
From your activity you have to call these methods. Like in the codes given below.
To create a folder
public void createFolderInDrive(View view) {
Log.i(TAG, "Creating a Folder...");
mDriveServiceHelper.createFolder("My Foder", null)
.addOnSuccessListener(new OnSuccessListener<GoogleDriveFileHolder>() {
#Override
public void onSuccess(GoogleDriveFileHolder googleDriveFileHolder) {
Gson gson = new Gson();
Log.i(TAG, "onSuccess of Folder creation: " + gson.toJson(googleDriveFileHolder));
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.i(TAG, "onFailure of Folder creation: " + e.getMessage());
}
});
}
To List files
public void listFilesInDrive(View view) {
Log.i(TAG, "Listing Files...");
new MyAsyncTask().execute();
}
To list the files, you can’t do it from your main thread because it will cause a deadlock. You have to do it in doInBackground() method of Asynctask. Here is my class.
public class MyAsyncTask extends AsyncTask<Void, Void, List<File>> {
List<File> fileList;
#Override
protected List<File> doInBackground(Void... voids) {
try {
fileList = mDriveServiceHelper.listDriveImageFiles();
} catch (IOException e) {
Log.i(TAG, "IO Exception while fetching file list");
}
return fileList;
}
#Override
protected void onPostExecute(List<File> files) {
super.onPostExecute(files);
if (files.size() == 0){
Log.i(TAG, "No Files");
}
for (File file : files) {
Log.i(TAG, "\nFound file: File Name :" +
file.getName() + " File Id :" + file.getId());
}
}
}
To Upload a file
To upload a file into Drive folder, specify the folder id , mime type of file to be uploaded and the file itself.
Here I select an Image from gallery and uploaded it into drive.
public void uploadFile(View view) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PICK_IMAGE);
} else {
Intent i = new Intent(
Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, RESULT_LOAD_IMAGE);
}
}
In onActivityResult
else if (requestCode == RESULT_LOAD_IMAGE) {
if (resultCode == RESULT_OK) {
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
uploadImageIntoDrive(BitmapFactory.decodeFile(picturePath));
} else {
Toast.makeText(this, "Did not select any image", Toast.LENGTH_SHORT).show();
}
uploadImageIntoDrive() method,
private void uploadImageIntoDrive(Bitmap bitmap) {
try {
if (bitmap == null) {
Log.i(TAG, "Bitmap is null");
return;
}
java.io.File file = new java.io.File(getApplicationContext().getFilesDir(), "FirstFile");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
byte[] bitmapdata = bos.toByteArray();
//write the bytes in file
FileOutputStream fos = new FileOutputStream(file);
fos.write(bitmapdata);
fos.flush();
fos.close();
mDriveServiceHelper.uploadFile(file, "image/jpeg", "MY_FOLDER_ID")
.addOnSuccessListener(new OnSuccessListener<GoogleDriveFileHolder>() {
#Override
public void onSuccess(GoogleDriveFileHolder googleDriveFileHolder) {
Log.i(TAG, "Successfully Uploaded. File Id :" + googleDriveFileHolder.getId());
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.i(TAG, "Failed to Upload. File Id :" + e.getMessage());
}
});
} catch (Exception e) {
Log.i(TAG, "Exception : " + e.getMessage());
}
}
To Download a file
To download a file, specify the id of the file and the target file into which the downloading file has to be stored.
public void downloadFile(View view) {
java.io.File file = new java.io.File(getExternalFilesDir(null), "DemoFile2.jpg");
mDriveServiceHelper.downloadFile(file, "MY_FILE_ID")
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.i(TAG, "Downloaded the file");
long file_size = file.length() / 1024;
Log.i(TAG, "file Size :" + file_size);
Log.i(TAG, "file Path :" + file.getAbsolutePath());
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.i(TAG, "Failed to Download the file, Exception :" + e.getMessage());
}
});
}
To Delete a file.
public void deleteFile(View view) {
mDriveServiceHelper.deleteFolderFile("MY_FILE_OR_FOLDER_ID")
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.i(TAG, "onSuccess of Deleting File ");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.i(TAG, "onFailure on Deleting File Exception : " + e.getMessage());
}
});
}
I am not an experienced guy. The reason I posted this code is somebody will find it useful and can bring up their own changes to it and post it here. Because there is not much reference for Drive Rest API integration for Android right now.
Thank You.
I need that as well. I managed to build something that works though not optimal from these links :
Google guides for REST API v3
Google Github demo project for migration to REST after deprecation of the other method
Documentation for REST API v3
My main remaining problem now is to find a file/folder picker. The one in the demo project uses SAF which does not allow to retrieve the ID of the file you picked (Oo !!!)
The article that I referred to while trying to figure out how to use the Drive REST API was on this page
I'm pretty new to Android, but here's how I get the list of files' IDs. Hope this helps you
create a method that returns a list of Files (do not mix them up with java.io.Files).
They are instances of com.google.api.services.drive.model.File;
The method below is a part of DriveServiceHelper class from the deprecation tutorial on github. Check the source files to see how mExecutor and mDriveService instances get created
public Task<FileList> queryFiles() {
return Tasks.call(mExecutor, () ->
mDriveService.files().list().setSpaces("drive").execute());
}
then you can iterate the list and get IDs of each file
for (File file : fileList.getFiles()) {
file.getId()
}
Once you get the ID, you can remove or update files
here's an example of a method for removing duplicate files your app will create each time you make an upload to google drive:
private void mQuery(String name) {
if (mDriveServiceHelper != null) {
Log.d(TAG, "Querying for files.");
mDriveServiceHelper.queryFiles()
.addOnSuccessListener(fileList -> {
for (File file : fileList.getFiles()) {
if(file.getName().equals(name))
mDriveServiceHelper.deleteFolderFile(file.getId()).addOnSuccessListener(v-> Log.d(TAG, "removed file "+file.getName())).
addOnFailureListener(v-> Log.d(TAG, "File was not removed: "+file.getName()));
}
})
.addOnFailureListener(exception -> Log.e(TAG, "Unable to query files.", exception));
}
}
and here's the deleteFolderFile method from DriveServiceHelper class
public Task<Void> deleteFolderFile(String fileId) {
return Tasks.call(mExecutor, () -> {
// Retrieve the metadata as a File object.
if (fileId != null) {
mDriveService.files().delete(fileId).execute();
}
return null;
});
}
NB! this is not the best approach if you need to perform a query on a large list of files. It's just a draft to help you get an idea. At least mQuery func can be improved by utilizing a binary search algorithm to look up a particular file in a list.
I created one project in which I have used the "Android Google DRIVE API V3" to create a folder, upload file, delete file, and download file feature in it.
The Complete android app with the code is present at https://github.com/prateekbangre/GoogleDrive_demo
Is Folder present:
public Task<String> isFolderPresent() {
return Tasks.call(mExecutor, () -> {
FileList result = mDriveService.files().list().setQ("mimeType='application/vnd.google-apps.folder' and trashed=false").execute();
for (File file : result.getFiles()) {
if (file.getName().equals(FOLDER_NAME))
return file.getId();
}
return "";
});
}
Create a folder:
public Task<String> createFolder() {
return Tasks.call(mExecutor, () -> {
File metadata = new File()
.setParents(Collections.singletonList("root"))
.setMimeType(FOLDER_MIME_TYPE)
.setName(FOLDER_NAME);
File googleFolder = mDriveService.files().create(metadata).execute();
if (googleFolder == null) {
throw new IOException("Null result when requesting Folder creation.");
}
return googleFolder.getId();
});
}
Get Files list:
public Task<ArrayList<GoogleDriveFileHolder>> getFolderFileList() {
ArrayList<GoogleDriveFileHolder> fileList = new ArrayList<>();
if (folderId.isEmpty()){
Log.e(TAG, "getFolderFileList: folder id not present" );
isFolderPresent().addOnSuccessListener(id -> folderId=id)
.addOnFailureListener(exception -> Log.e(TAG, "Couldn't create file.", exception));
}
return Tasks.call(mExecutor, () -> {
FileList result = mDriveService.files().list()
.setQ("mimeType = '" + SHEET_MIME_TYPE + "' and trashed=false and parents = '" + folderId + "' ")
.setSpaces("drive")
.execute();
for (int i = 0; i < result.getFiles().size(); i++) {
GoogleDriveFileHolder googleDriveFileHolder = new GoogleDriveFileHolder();
googleDriveFileHolder.setId(result.getFiles().get(i).getId());
googleDriveFileHolder.setName(result.getFiles().get(i).getName());
fileList.add(googleDriveFileHolder);
}
Log.e(TAG, "getFolderFileList: folderFiles: "+fileList );
return fileList;
});
}
Upload files to google drive:
public Task<Boolean> uploadFileToGoogleDrive(String path) {
if (folderId.isEmpty()){
Log.e(TAG, "uploadFileToGoogleDrive: folder id not present" );
isFolderPresent().addOnSuccessListener(id -> folderId=id)
.addOnFailureListener(exception -> Log.e(TAG, "Couldn't create file.", exception));
}
return Tasks.call(mExecutor, () -> {
Log.e(TAG, "uploadFileToGoogleDrive: path: "+path );
java.io.File filePath = new java.io.File(path);
File fileMetadata = new File();
fileMetadata.setName(filePath.getName());
fileMetadata.setParents(Collections.singletonList(folderId));
fileMetadata.setMimeType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
FileContent mediaContent = new FileContent("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", filePath);
File file = mDriveService.files().create(fileMetadata, mediaContent)
.setFields("id")
.execute();
System.out.println("File ID: " + file.getId());
return false;
});
}
Download File from google drive:
public Task<Boolean> downloadFile(final java.io.File fileSaveLocation, final String fileId) {
return Tasks.call(mExecutor, new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
// Retrieve the metadata as a File object.
OutputStream outputStream = new FileOutputStream(fileSaveLocation);
mDriveService.files().get(fileId).executeMediaAndDownloadTo(outputStream);
return true;
}
});
}
Delete File:
public Task<Boolean> deleteFolderFile(final String fileId) {
return Tasks.call(mExecutor, new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
// Retrieve the metadata as a File object.
if (fileId != null) {
mDriveService.files().delete(fileId).execute();
return true;
}
return false;
}
});
}
Above is the code same sample.

Can someone provide an up-to-date Android guide for Google Drive REST API v3?

Myself and many others have been struggling with setting up the Google Drive REST API v3 to work with Android apps. This mainly stems from the fact that the official Google documentation is missing a proper quick start guide for Android and we are left with finding scraps of (outdated and/or confusing) information dotted around - but what is needed is a complete up to date guide aimed at beginners to get us up and running so that they can open and edit files on their Drive, including how to set up credentials, dependencies, and manifests.
So I am asking if anyone would be willing to create such a guide, or can point to such a guide that has already been made that is a) relevant to the latest version of Google Drive API REST v3 detailed here and b) covers ALL above aspects that a beginner would need to be get started?
The guidelines posted by ArtOfWarfare here are absolutely perfect and exactly what I'm looking for - but are unfortunately out of date by several years. Can anyone provide an up-to-date version of this guide? Thank you kindly.
Before answering this question I want you to know that I got the code from here (https://ammar.lanui.online/integrate-google-drive-rest-api-on-android-app-bc4ddbd90820) and the documentation from Google was not much helpful for me. So this solution is from limited resources available to me.
I need the drive to upload and download files from my app. In drive I have to create a folder and I have to upload file from my app to that folder and download a file from the folder to my device. This code was working fine for me.
I believe that you must have completed Google login. If you don’t, go checkout this video (https://youtu.be/t-yZUqthDMM) .
To interact with the Drive API, you need to enable the Drive API service for your app. You can do this in Google Developer Console.
To enable the Drive API, complete these steps:
Go to the Google API Console.
Select a project.
In the sidebar on the left, expand APIs & auth and select APIs.
In the displayed list of available APIs, click the Drive API link and click Enable API.
If you completed it, then go to OAuth Consent screen in console and add the two scopes for drive and save it.
In your project add the dependencies below.
implementation 'com.google.android.gms:play-services-auth:17.0.0'// for google sign in
// for drive integration
implementation 'com.google.android.gms:play-services-auth:16.0.1'
implementation 'com.google.http-client:google-http-client-gson:1.26.0'
implementation('com.google.api-client:google-api-client-android:1.26.0') {
exclude group: 'org.apache.httpcomponents'
}
implementation('com.google.apis:google-api-services-drive:v3-rev136-1.25.0')
{
exclude group: 'org.apache.httpcomponents'
}
And inside android tag, in the same gradle file, add the packaging options.
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/notice.txt'
exclude 'META-INF/ASL2.0'
}
In your Manifest file, add the required permissions
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Here I am storing the downloaded file in external storage. So that’s why I added the permissions for External storage READ and WRITE
After Google sign In, ask permission to access Google drive. The code for it is given below.
private void checkForGooglePermissions() {
if (!GoogleSignIn.hasPermissions(
GoogleSignIn.getLastSignedInAccount(getApplicationContext()),
ACCESS_DRIVE_SCOPE,
SCOPE_EMAIL)) {
GoogleSignIn.requestPermissions(
MainActivity.this,
RC_AUTHORIZE_DRIVE,
GoogleSignIn.getLastSignedInAccount(getApplicationContext()),
ACCESS_DRIVE_SCOPE,
SCOPE_EMAIL);
} else {
Toast.makeText(this, "Permission to access Drive and Email has been granted", Toast.LENGTH_SHORT).show();
driveSetUp();
}
}
The variables ACCESS_DRIVE_SCOPE and SCOPE_EMAIL are,
Scope ACCESS_DRIVE_SCOPE = new Scope(Scopes.DRIVE_FILE);
Scope SCOPE_EMAIL = new Scope(Scopes.EMAIL);
After having permission and Sign In we have our GoogleSignInAccount object. With this object, create an object of GoogleAccountCredential, from which we can generate an object of Drive. The Drive object is what we needed for the communication between Google Drive.
private void driveSetUp() {
GoogleSignInAccount mAccount = GoogleSignIn.getLastSignedInAccount(MainActivity.this);
GoogleAccountCredential credential =
GoogleAccountCredential.usingOAuth2(
getApplicationContext(), Collections.singleton(Scopes.DRIVE_FILE));
credential.setSelectedAccount(mAccount.getAccount());
googleDriveService =
new com.google.api.services.drive.Drive.Builder(
AndroidHttp.newCompatibleTransport(),
new GsonFactory(),
credential)
.setApplicationName("GoogleDriveIntegration 3")
.build();
mDriveServiceHelper = new DriveServiceHelper(googleDriveService);
}
Here you can see I created an object of DriveServiceHelper class and passed the object of Drive(googleDriveSrvice) along with it.
DriveServiceHelper class is given below. I got it from here.( https://github.com/gsuitedevs/android-samples/blob/master/drive/deprecation/app/src/main/java/com/google/android/gms/drive/sample/driveapimigration/DriveServiceHelper.java?source=post_page-----bc4ddbd90820----------------------). You can use that one. I made some changes in that class for myself.
public class DriveServiceHelper {
private final Executor mExecutor = Executors.newSingleThreadExecutor();
private final Drive mDriveService;
private final String TAG = "DRIVE_TAG";
public DriveServiceHelper(Drive driveService) {
mDriveService = driveService;
}
/**
* Creates a text file in the user's My Drive folder and returns its file ID.
*/
public Task<GoogleDriveFileHolder> createFile(String folderId, String filename) {
return Tasks.call(mExecutor, () -> {
GoogleDriveFileHolder googleDriveFileHolder = new GoogleDriveFileHolder();
List<String> root;
if (folderId == null) {
root = Collections.singletonList("root");
} else {
root = Collections.singletonList(folderId);
}
File metadata = new File()
.setParents(root)
.setMimeType("text/plain")
.setName(filename);
File googleFile = mDriveService.files().create(metadata).execute();
if (googleFile == null) {
throw new IOException("Null result when requesting file creation.");
}
googleDriveFileHolder.setId(googleFile.getId());
return googleDriveFileHolder;
});
}
// TO CREATE A FOLDER
public Task<GoogleDriveFileHolder> createFolder(String folderName, #Nullable String folderId) {
return Tasks.call(mExecutor, () -> {
GoogleDriveFileHolder googleDriveFileHolder = new GoogleDriveFileHolder();
List<String> root;
if (folderId == null) {
root = Collections.singletonList("root");
} else {
root = Collections.singletonList(folderId);
}
File metadata = new File()
.setParents(root)
.setMimeType("application/vnd.google-apps.folder")
.setName(folderName);
File googleFile = mDriveService.files().create(metadata).execute();
if (googleFile == null) {
throw new IOException("Null result when requesting file creation.");
}
googleDriveFileHolder.setId(googleFile.getId());
return googleDriveFileHolder;
});
}
public Task<Void> downloadFile(java.io.File targetFile, String fileId) {
return Tasks.call(mExecutor, () -> {
// Retrieve the metadata as a File object.
OutputStream outputStream = new FileOutputStream(targetFile);
mDriveService.files().get(fileId).executeMediaAndDownloadTo(outputStream);
return null;
});
}
public Task<Void> deleteFolderFile(String fileId) {
return Tasks.call(mExecutor, () -> {
// Retrieve the metadata as a File object.
if (fileId != null) {
mDriveService.files().delete(fileId).execute();
}
return null;
});
}
// TO LIST FILES
public List<File> listDriveImageFiles() throws IOException{
FileList result;
String pageToken = null;
do {
result = mDriveService.files().list()
/*.setQ("mimeType='image/png' or mimeType='text/plain'")This si to list both image and text files. Mind the type of image(png or jpeg).setQ("mimeType='image/png' or mimeType='text/plain'") */
.setSpaces("drive")
.setFields("nextPageToken, files(id, name)")
.setPageToken(pageToken)
.execute();
pageToken = result.getNextPageToken();
} while (pageToken != null);
return result.getFiles();
}
// TO UPLOAD A FILE ONTO DRIVE
public Task<GoogleDriveFileHolder> uploadFile(final java.io.File localFile,
final String mimeType, #Nullable final String folderId) {
return Tasks.call(mExecutor, new Callable<GoogleDriveFileHolder>() {
#Override
public GoogleDriveFileHolder call() throws Exception {
// Retrieve the metadata as a File object.
List<String> root;
if (folderId == null) {
root = Collections.singletonList("root");
} else {
root = Collections.singletonList(folderId);
}
File metadata = new File()
.setParents(root)
.setMimeType(mimeType)
.setName(localFile.getName());
FileContent fileContent = new FileContent(mimeType, localFile);
File fileMeta = mDriveService.files().create(metadata,
fileContent).execute();
GoogleDriveFileHolder googleDriveFileHolder = new
GoogleDriveFileHolder();
googleDriveFileHolder.setId(fileMeta.getId());
googleDriveFileHolder.setName(fileMeta.getName());
return googleDriveFileHolder;
}
});
}
}
Remember the fact that whenever you create a file or folder or if you upload a file, the drive will give a unique id for it and you can access it. So it’s not the file name that is unique in here, it’s the id of the file. Hence if you upload or create a file of same name multiple times it will be saved in the folder multiple times. So if you want to replace a file with another file of the same name. First delete the file and save/ upload it.
To create a file, specify the folder id and file name to be created.
The GoogleDriveHolder class is given below.
public class GoogleDriveFileHolder {
private String id;
private String name;
private DateTime modifiedTime;
private long size;
private DateTime createdTime;
private Boolean starred;
public DateTime getCreatedTime() {
return createdTime;
}
public void setCreatedTime(DateTime createdTime) {
this.createdTime = createdTime;
}
public Boolean getStarred() {
return starred;
}
public void setStarred(Boolean starred) {
this.starred = starred;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public DateTime getModifiedTime() {
return modifiedTime;
}
public void setModifiedTime(DateTime modifiedTime) {
this.modifiedTime = modifiedTime;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
}
From your activity you have to call these methods. Like in the codes given below.
To create a folder
public void createFolderInDrive(View view) {
Log.i(TAG, "Creating a Folder...");
mDriveServiceHelper.createFolder("My Foder", null)
.addOnSuccessListener(new OnSuccessListener<GoogleDriveFileHolder>() {
#Override
public void onSuccess(GoogleDriveFileHolder googleDriveFileHolder) {
Gson gson = new Gson();
Log.i(TAG, "onSuccess of Folder creation: " + gson.toJson(googleDriveFileHolder));
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.i(TAG, "onFailure of Folder creation: " + e.getMessage());
}
});
}
To List files
public void listFilesInDrive(View view) {
Log.i(TAG, "Listing Files...");
new MyAsyncTask().execute();
}
To list the files, you can’t do it from your main thread because it will cause a deadlock. You have to do it in doInBackground() method of Asynctask. Here is my class.
public class MyAsyncTask extends AsyncTask<Void, Void, List<File>> {
List<File> fileList;
#Override
protected List<File> doInBackground(Void... voids) {
try {
fileList = mDriveServiceHelper.listDriveImageFiles();
} catch (IOException e) {
Log.i(TAG, "IO Exception while fetching file list");
}
return fileList;
}
#Override
protected void onPostExecute(List<File> files) {
super.onPostExecute(files);
if (files.size() == 0){
Log.i(TAG, "No Files");
}
for (File file : files) {
Log.i(TAG, "\nFound file: File Name :" +
file.getName() + " File Id :" + file.getId());
}
}
}
To Upload a file
To upload a file into Drive folder, specify the folder id , mime type of file to be uploaded and the file itself.
Here I select an Image from gallery and uploaded it into drive.
public void uploadFile(View view) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PICK_IMAGE);
} else {
Intent i = new Intent(
Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, RESULT_LOAD_IMAGE);
}
}
In onActivityResult
else if (requestCode == RESULT_LOAD_IMAGE) {
if (resultCode == RESULT_OK) {
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
uploadImageIntoDrive(BitmapFactory.decodeFile(picturePath));
} else {
Toast.makeText(this, "Did not select any image", Toast.LENGTH_SHORT).show();
}
uploadImageIntoDrive() method,
private void uploadImageIntoDrive(Bitmap bitmap) {
try {
if (bitmap == null) {
Log.i(TAG, "Bitmap is null");
return;
}
java.io.File file = new java.io.File(getApplicationContext().getFilesDir(), "FirstFile");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
byte[] bitmapdata = bos.toByteArray();
//write the bytes in file
FileOutputStream fos = new FileOutputStream(file);
fos.write(bitmapdata);
fos.flush();
fos.close();
mDriveServiceHelper.uploadFile(file, "image/jpeg", "MY_FOLDER_ID")
.addOnSuccessListener(new OnSuccessListener<GoogleDriveFileHolder>() {
#Override
public void onSuccess(GoogleDriveFileHolder googleDriveFileHolder) {
Log.i(TAG, "Successfully Uploaded. File Id :" + googleDriveFileHolder.getId());
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.i(TAG, "Failed to Upload. File Id :" + e.getMessage());
}
});
} catch (Exception e) {
Log.i(TAG, "Exception : " + e.getMessage());
}
}
To Download a file
To download a file, specify the id of the file and the target file into which the downloading file has to be stored.
public void downloadFile(View view) {
java.io.File file = new java.io.File(getExternalFilesDir(null), "DemoFile2.jpg");
mDriveServiceHelper.downloadFile(file, "MY_FILE_ID")
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.i(TAG, "Downloaded the file");
long file_size = file.length() / 1024;
Log.i(TAG, "file Size :" + file_size);
Log.i(TAG, "file Path :" + file.getAbsolutePath());
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.i(TAG, "Failed to Download the file, Exception :" + e.getMessage());
}
});
}
To Delete a file.
public void deleteFile(View view) {
mDriveServiceHelper.deleteFolderFile("MY_FILE_OR_FOLDER_ID")
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.i(TAG, "onSuccess of Deleting File ");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.i(TAG, "onFailure on Deleting File Exception : " + e.getMessage());
}
});
}
I am not an experienced guy. The reason I posted this code is somebody will find it useful and can bring up their own changes to it and post it here. Because there is not much reference for Drive Rest API integration for Android right now.
Thank You.
I need that as well. I managed to build something that works though not optimal from these links :
Google guides for REST API v3
Google Github demo project for migration to REST after deprecation of the other method
Documentation for REST API v3
My main remaining problem now is to find a file/folder picker. The one in the demo project uses SAF which does not allow to retrieve the ID of the file you picked (Oo !!!)
The article that I referred to while trying to figure out how to use the Drive REST API was on this page
I'm pretty new to Android, but here's how I get the list of files' IDs. Hope this helps you
create a method that returns a list of Files (do not mix them up with java.io.Files).
They are instances of com.google.api.services.drive.model.File;
The method below is a part of DriveServiceHelper class from the deprecation tutorial on github. Check the source files to see how mExecutor and mDriveService instances get created
public Task<FileList> queryFiles() {
return Tasks.call(mExecutor, () ->
mDriveService.files().list().setSpaces("drive").execute());
}
then you can iterate the list and get IDs of each file
for (File file : fileList.getFiles()) {
file.getId()
}
Once you get the ID, you can remove or update files
here's an example of a method for removing duplicate files your app will create each time you make an upload to google drive:
private void mQuery(String name) {
if (mDriveServiceHelper != null) {
Log.d(TAG, "Querying for files.");
mDriveServiceHelper.queryFiles()
.addOnSuccessListener(fileList -> {
for (File file : fileList.getFiles()) {
if(file.getName().equals(name))
mDriveServiceHelper.deleteFolderFile(file.getId()).addOnSuccessListener(v-> Log.d(TAG, "removed file "+file.getName())).
addOnFailureListener(v-> Log.d(TAG, "File was not removed: "+file.getName()));
}
})
.addOnFailureListener(exception -> Log.e(TAG, "Unable to query files.", exception));
}
}
and here's the deleteFolderFile method from DriveServiceHelper class
public Task<Void> deleteFolderFile(String fileId) {
return Tasks.call(mExecutor, () -> {
// Retrieve the metadata as a File object.
if (fileId != null) {
mDriveService.files().delete(fileId).execute();
}
return null;
});
}
NB! this is not the best approach if you need to perform a query on a large list of files. It's just a draft to help you get an idea. At least mQuery func can be improved by utilizing a binary search algorithm to look up a particular file in a list.
I created one project in which I have used the "Android Google DRIVE API V3" to create a folder, upload file, delete file, and download file feature in it.
The Complete android app with the code is present at https://github.com/prateekbangre/GoogleDrive_demo
Is Folder present:
public Task<String> isFolderPresent() {
return Tasks.call(mExecutor, () -> {
FileList result = mDriveService.files().list().setQ("mimeType='application/vnd.google-apps.folder' and trashed=false").execute();
for (File file : result.getFiles()) {
if (file.getName().equals(FOLDER_NAME))
return file.getId();
}
return "";
});
}
Create a folder:
public Task<String> createFolder() {
return Tasks.call(mExecutor, () -> {
File metadata = new File()
.setParents(Collections.singletonList("root"))
.setMimeType(FOLDER_MIME_TYPE)
.setName(FOLDER_NAME);
File googleFolder = mDriveService.files().create(metadata).execute();
if (googleFolder == null) {
throw new IOException("Null result when requesting Folder creation.");
}
return googleFolder.getId();
});
}
Get Files list:
public Task<ArrayList<GoogleDriveFileHolder>> getFolderFileList() {
ArrayList<GoogleDriveFileHolder> fileList = new ArrayList<>();
if (folderId.isEmpty()){
Log.e(TAG, "getFolderFileList: folder id not present" );
isFolderPresent().addOnSuccessListener(id -> folderId=id)
.addOnFailureListener(exception -> Log.e(TAG, "Couldn't create file.", exception));
}
return Tasks.call(mExecutor, () -> {
FileList result = mDriveService.files().list()
.setQ("mimeType = '" + SHEET_MIME_TYPE + "' and trashed=false and parents = '" + folderId + "' ")
.setSpaces("drive")
.execute();
for (int i = 0; i < result.getFiles().size(); i++) {
GoogleDriveFileHolder googleDriveFileHolder = new GoogleDriveFileHolder();
googleDriveFileHolder.setId(result.getFiles().get(i).getId());
googleDriveFileHolder.setName(result.getFiles().get(i).getName());
fileList.add(googleDriveFileHolder);
}
Log.e(TAG, "getFolderFileList: folderFiles: "+fileList );
return fileList;
});
}
Upload files to google drive:
public Task<Boolean> uploadFileToGoogleDrive(String path) {
if (folderId.isEmpty()){
Log.e(TAG, "uploadFileToGoogleDrive: folder id not present" );
isFolderPresent().addOnSuccessListener(id -> folderId=id)
.addOnFailureListener(exception -> Log.e(TAG, "Couldn't create file.", exception));
}
return Tasks.call(mExecutor, () -> {
Log.e(TAG, "uploadFileToGoogleDrive: path: "+path );
java.io.File filePath = new java.io.File(path);
File fileMetadata = new File();
fileMetadata.setName(filePath.getName());
fileMetadata.setParents(Collections.singletonList(folderId));
fileMetadata.setMimeType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
FileContent mediaContent = new FileContent("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", filePath);
File file = mDriveService.files().create(fileMetadata, mediaContent)
.setFields("id")
.execute();
System.out.println("File ID: " + file.getId());
return false;
});
}
Download File from google drive:
public Task<Boolean> downloadFile(final java.io.File fileSaveLocation, final String fileId) {
return Tasks.call(mExecutor, new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
// Retrieve the metadata as a File object.
OutputStream outputStream = new FileOutputStream(fileSaveLocation);
mDriveService.files().get(fileId).executeMediaAndDownloadTo(outputStream);
return true;
}
});
}
Delete File:
public Task<Boolean> deleteFolderFile(final String fileId) {
return Tasks.call(mExecutor, new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
// Retrieve the metadata as a File object.
if (fileId != null) {
mDriveService.files().delete(fileId).execute();
return true;
}
return false;
}
});
}
Above is the code same sample.

Large file upload fails on node.js Hapi

I have a node.js script which should handle file uploads, also multiple at once. Uploading pictures and voices work just fine. However, video files at around 10 MB or larger do not upload. Sometimes it doesn't work at all and sometimes it gets stuck in the fs.writeFile function. Maybe there is a better way general as I came up with many parts in the code on my own. I need the md5 hash before creating the file on disk because its path will be generated from the hash. Also I get a SocketTimeoutException on the Android side. Code is mainly focused on that part right now, so don't worry about the missing input validation and onProgress.
NodeJS:
server.route({
method: 'POST',
path: '/uploadFile',
config: {
payload: {
output: 'stream',
allow: 'multipart/form-data',
maxBytes: 100*1024*1024 //100 mb
}
}, handler: async function (request, reply)
{
await incoming_uploadFile(request, reply);
}
});
...........
var joi = require('joi');
import { Paths } from "../util/Paths";
import * as fs from 'fs';
let data;
let numOfFiles: number;
export async function incoming_uploadFile(request, reply) {
data = request.payload;
await Application.InitializeSocket(null, "UploadFile");
let userID = await Application.AuthUser(JSON.parse(data['auth']));
numOfFiles = parseInt(data['numOfFiles']);
if (numOfFiles > 0)
upload(0);
}
async function upload(i: number)
{
const file = data['file' + i];
const meta = data['fileMeta' + i];
const metaJson = Application.StringToJson(meta);
const fileType: string = metaJson['fileType'];
const extension: string = metaJson['extension'];
var crypto = require('crypto');
const md5 = crypto.createHash('md5');
var length = parseInt(file.hapi.headers["content-length"]);
let buffer: Buffer = new Buffer(length);
let bufPos : number = 0;
file.on('data', function (b : Uint8Array) {
for (var i = 0; i < b.byteLength; ++i)
buffer.writeUInt8(b[i], bufPos++);
});
file.on('end', function (err) {
var hash = md5.update(buffer.toString("base64")).digest("hex");
const filePath: string = Paths.getFilePath(hash, fileType, extension);
// Creates all dirs that are missing on the path
var shell = require('shelljs');
shell.mkdir('-p', require('path').dirname(filePath));
console.log("writing buffer to file...");
fs.writeFile(filePath, buffer,null);
if ((++i) < numOfFiles)
upload(i);
});
}
Android uploading the file(s):
public static void uploadAttachments(ArrayList<EventAttachment> attachments)
{
OkHttpClient client = new OkHttpClient();
// Add attachments
MultipartBody.Builder builder = new MultipartBody.Builder();
builder.setType(MultipartBody.FORM);
builder.addFormDataPart("numOfFiles",String.valueOf(attachments.size()));
for (int i = 0; i < attachments.size();++i) {
EventAttachment attachment = attachments.get(i);
File file = new File(attachment.getPath());
String extension = MimeTypeMap.getFileExtensionFromUrl(attachment.getPath());
String type = null;
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
} else {
Log.e("x", "Could not get extensions of file " + file.getAbsolutePath() + ". File upload aborted.");
return;
}
ProgressRequestBody p = new ProgressRequestBody(RequestBody.create(MediaType.parse(type), file), new ProgressRequestBody.Listener() {
#Override
public void onProgress(int progress) {
}
});
builder.addFormDataPart("file" + i, file.getName(), p);
HashMap<String, String> hm = new HashMap<>();
hm.put("extension", extension.replace(".", ""));
hm.put("fileType", String.valueOf(attachment.getType()));
builder.addFormDataPart("fileMeta" + i, new JSONObject(hm).toString());
}
JSONObject jObj = new JSONObject();
builder.addFormDataPart("auth", putDefaultHeader(jObj).toString());
MultipartBody mb = builder.build();
okhttp3.Request request = new Request.Builder().url(EndPoint+UPLOAD_FILE).post(mb).build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.e("x", "Error uploading file");
}
#Override
public void onResponse(Call call, Response response) throws IOException {
}
});
}
Thanks for your help.
Added
timeout: false,
parse: true
on the config payload and works for now.

What type of error is this Error: ENOENT: no such file or directory, open

I am getting stuck at this error and not able to resolve this issue.
Error: ENOENT: no such file or directory, open 'C:\Users\sagarkumar\AppData\Loca
l\Temp;C:\Program Files\Java\jdk1.7.0_51\bin\8852-120drlh.jpg'
This is app.js file
var express = require('express');
var connect = require('connect');
var app = express();
var port = process.env.PORT || 8080;
// Configuration
app.use(express.static(__dirname + '/public'));
app.use(connect.cookieParser());
app.use(connect.logger('dev'));
app.use(connect.bodyParser());
app.use(connect.json());
app.use(connect.urlencoded());
// Routes
require('./routes/routes.js')(app);
app.listen(port);
console.log('The App runs on port ' + port);
This is route.js file
var fs = require('fs');
module.exports = function(app) {
app.get('/',function(req,res){
res.end("Node-File-Upload");
});
/*
app.post('/upload', function(req, res) {
console.log(req.files.image.originalFilename);
console.log(req.files.image.path);
fs.readFile(req.files.image.path, function (err, data){
var dirname = "sagar/";
var newPath = dirname + "/uploads/" + req.files.image.originalFilename;
fs.writeFile(newPath, data, function (err) {
if(err){
res.json({'response':"Error"});
}else {
res.json({'response':"Saved"});
}
});
});
*/
app.post('/upload', function(req, res) {
res.json({'response':"Saved"});
}
);
This is android code(client side) making json request(Only requesting part).
There is select button which is choosing image from gallery and upload button making request to nodejs server.
upload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
File f = new File(path);
Future uploading = Ion.with(nodejs.this)
.load("http://192.168.0.101:8080/upload")
.setMultipartFile("image",f)
.asString()
.withResponse()
.setCallback(new FutureCallback<Response<String>>() {
#Override
public void onCompleted(Exception e, Response<String> result) {
try {
JSONObject jobj = new JSONObject(result.getResult());
}
catch (JSONException e1) {
e1.printStackTrace();
}
}
});
}
});
The file C:\Users\sagarkumar\AppData\Loca l\Temp;C:\Program Files\Java\jdk1.7.0_51\bin\8852-120drlh.jpg doesn't exist. It looks like you appended two filenames together.
ENOENT = Error NO ENTity.
You have a problem with the file, maybe your path its wrong or the name of the file, but sure the problem is with your file.

Categories

Resources