Varun.MS
Varun.MS

Reputation: 55

Unable to download file created by my app on Google Drive, But can get the metadata of that file

I followed all the steps mentioned in google drive sdk. I created a sample application on my device(android, running jelly bean) and am able to upload a file on to drive. When trying to download the same file, I am able to get the meta data like fileID, fileTitle, fileDownloadURL etc but not able to download the content. I get 401 Unauthorized error.

My app AUTH SCOPE is AUTH_TOKEN_TYPE = "oauth2:https://www.googleapis.com/auth/drive.file";

I am doing the following to get the OAUTH Token:

AccountManager am = AccountManager.get(this);
        Bundle options = new Bundle();
        am.getAuthToken(
                mAccount,                               
                AUTH_TOKEN_TYPE,                        
                options,                                
                this,                                   
                new OnTokenAcquired(),                  
                new Handler(){
                    @Override
                    public void handleMessage(Message msg) {
                        invadiateToken();                       
                        super.handleMessage(msg);
                    }
                });  

Based on the token this is how I build the Drive object

Drive buildService(final String AuthToken) {
    HttpTransport httpTransport = new NetHttpTransport();
    JacksonFactory jsonFactory = new JacksonFactory();

    Drive.Builder b = new Drive.Builder(httpTransport, jsonFactory, null);
    b.setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {

        @Override
        public void initialize(JsonHttpRequest request) throws IOException {
            DriveRequest driveRequest = (DriveRequest) request;
            driveRequest.setPrettyPrint(true);
            driveRequest.setKey(API_KEY);
            driveRequest.setOauthToken(AuthToken);
        }
    });

    return b.build();
}

I am able to upload the file using the following code:

private void uploadLocalFileToDrive(Drive service) throws IOException{

        // File's metadata.
        String mimeType = "text/plain";
        File body = new File();
        body.setTitle("myText.txt");
        body.setDescription("sample app by varun");
        body.setMimeType("text/plain");

        // File's content.
        java.io.File fileContent = new java.io.File(mInternalFilePath);
        FileContent mediaContent = new FileContent(mimeType, fileContent);

        service.files().insert(body, mediaContent).execute();

    }

While trying to download the same file uploaded by this app, I get a 401 unauthorized error at this line HttpResponse resp = service.getRequestFactory().buildGetRequest(url).execute() from the following code snippet

private void downloadFileFromDrive(Drive service) throws IOException {
        Files.List request;
            request = service.files().list();
            do {
                FileList files = request.execute(); 
                for(File file:files.getItems()){
                    String fieldId = file.getId();
                    String title = file.getTitle();
                    Log.e("MS", "MSV::  Title-->"+title+"  FieldID-->"+fieldId+" DownloadURL-->"+file.getDownloadUrl());
                    if (file.getDownloadUrl() != null && file.getDownloadUrl().length() > 0 ) {
                        GenericUrl url = new GenericUrl(file.getDownloadUrl());
                        HttpResponse resp = service.getRequestFactory().buildGetRequest(url).execute();
                        InputStream isd = resp.getContent();
                        Log.e("MS", "MSV:: FileOutPutStream--->"+getFilesDir().getAbsolutePath()+"/downloaded.txt");

                    } else {
                        Log.e("MS", "MSV:: downloadURL for this file is null");
                    }
                }
                request.setPageToken(files.getNextPageToken());
            } while (request.getPageToken()!=null && request.getPageToken().length()>0);
    }

Can anyone help me out and let me know what I am doing wrong???

Upvotes: 4

Views: 5270

Answers (3)

Archie.bpgc
Archie.bpgc

Reputation: 24012

I don't think we need any Access Token to download a file. I had the same problem, and this worked:

private class DownloadFile extends AsyncTask<Void, Long, Boolean> {

    private com.google.api.services.drive.model.File driveFile;
    private java.io.File file;

    public DownloadFile(File driveFile) {
        this.driveFile = driveFile;
    }

    @Override
    protected Boolean doInBackground(Void... params) {
        if (driveFile.getDownloadUrl() != null
                && driveFile.getDownloadUrl().length() > 0) {
            try {
                HttpResponse resp = mDriveService
                        .getRequestFactory()
                        .buildGetRequest(
                                new GenericUrl(driveFile.getDownloadUrl()))
                        .execute();
                OutputStream os = new FileOutputStream(file);
                CopyStream(resp.getContent(), os);
                os.close();

                return true;
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }
        } else {
            return false;
        }
    }

    @Override
    protected void onPostExecute(Boolean result) {
        //use the file
    }
}

public static void CopyStream(InputStream is, OutputStream os) {
    final int buffer_size = 1024;
    try {
        byte[] bytes = new byte[buffer_size];
        for (;;) {
            int count = is.read(bytes, 0, buffer_size);
            if (count == -1)
                break;
            os.write(bytes, 0, count);
        }
    } catch (Exception ex) {
    }
}

Upvotes: 0

ArtOfWarfare
ArtOfWarfare

Reputation: 21478

I have answered this question, and all related Drive on Android questions, over here:

Android Open and Save files to/from Google Drive SDK

In that answer, I posted code for a method that I used to download files from Google Drive (if the following code by itself isn't clear, have a look at the complete answer that I linked to.)

private java.io.File downloadGFileToJFolder(Drive drive, String token, File gFile, java.io.File jFolder) throws IOException {
    if (gFile.getDownloadUrl() != null && gFile.getDownloadUrl().length() > 0 ) {
        if (jFolder == null) {
            jFolder = Environment.getExternalStorageDirectory();
            jFolder.mkdirs();
        }
        try {

            HttpClient client = new DefaultHttpClient();
            HttpGet get = new HttpGet(gFile.getDownloadUrl());
            get.setHeader("Authorization", "Bearer " + token);
            HttpResponse response = client.execute(get);

            InputStream inputStream = response.getEntity().getContent();
            jFolder.mkdirs();
            java.io.File jFile = new java.io.File(jFolder.getAbsolutePath() + "/" + getGFileName(gFile)); // getGFileName() is my own method... it just grabs originalFilename if it exists or title if it doesn't.
            FileOutputStream fileStream = new FileOutputStream(jFile);
            byte buffer[] = new byte[1024];
            int length;
            while ((length=inputStream.read(buffer))>0) {
                fileStream.write(buffer, 0, length);
            }
            fileStream.close();
            inputStream.close();
            return jFile;
        } catch (IOException e) {        
            // Handle IOExceptions here...
            return null;
        }
    } else {
        // Handle the case where the file on Google Drive has no length here.
        return null;
    }
}

Upvotes: 2

Alain
Alain

Reputation: 6034

This is a known issue that will be resolved with the release of the Google Play Services APIs.

Since your application is authorized for the https://www.googleapis.com/auth/drive.file scope, and the download endpoint doesn't support the ?key= query parameter, there is no way for our server to know which project is issuing the request (to make sure the app has authorization to read this file's content).

In the meantime, the only workaround I can recommend is using the broad scope: https://www.googleapis.com/auth/drive. Please use only that while developing your application and waiting for the Google Play Services to be released.

To learn more about how you will be able to use the new authorization APIs in Android, you might be interested in those 2 Google I/O talks: Building Android Applications that Use Web APIs and Writing Efficient Drive Apps for Android

Upvotes: 6

Related Questions