IOS: How to Download Google Docs files using ios g

2019-01-23 20:02发布

问题:

I integrated google drivs sdk with my ios app. At present am using the following code to download the files from my google drive a/c based on download url link. But when i try to download the google docs files (which has mime type application/vnd.google-apps.document) there is no download url link from google drive library. In that case how can i download the google docs data?. Can i use alternateLink instead of download url link?. Any help must be appreciated.

My Code:

- (void)loadFileContent {

GTMHTTPFetcher *fetcher =
[self.driveService.fetcherService fetcherWithURLString:[[self.driveFiles objectAtIndex:selectedFileIdx] downloadUrl]];

[fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
    if (error == nil) {
        NSLog(@"\nfile %@ downloaded successfully from google drive", [[self.driveFiles objectAtIndex:selectedFileIdx] originalFilename]);

        //saving the downloaded data into temporary location

    } else {
        NSLog(@"An error occurred: %@", error);            

    }
}];

}

回答1:

Here the steps to download the file from google drive. It will work for both file and also google docs.

Step 1:

Fetch the file list and store it into an array or dict with related file download link url:

- (void)loadDriveFiles {
fileFetchStatusFailure = NO;

//for more info about fetching the files check this link
//https://developers.google.com/drive/v2/reference/children/list    
GTLQueryDrive *query2 = [GTLQueryDrive queryForChildrenListWithFolderId:[parentIdList lastObject]];
query2.maxResults = 1000;

// queryTicket can be used to track the status of the request.
[self.driveService executeQuery:query2
              completionHandler:^(GTLServiceTicket *ticket,
                                  GTLDriveChildList *children, NSError *error) {
                  GTLBatchQuery *batchQuery = [GTLBatchQuery batchQuery];                      
                  //incase there is no files under this folder then we can avoid the fetching process
                  if (!children.items.count) {                          
                      [self.driveFiles removeAllObjects];
                      [fileNames removeAllObjects];                          
                      [self performSelectorOnMainThread:@selector(reloadTableDataFromMainThread) withObject:nil waitUntilDone:NO];                          
                      return ;
                  }

                  if (error == nil) {
                      int totalChildren = children.items.count;
                      count = 0;

                      [self.driveFiles removeAllObjects];
                      [fileNames removeAllObjects];                                                    //http://stackoverflow.com/questions/14603432/listing-all-files-from-specified-folders-in-google-drive-through-ios-google-driv/14610713#14610713
                      for (GTLDriveChildReference *child in children) {
                          GTLQuery *query = [GTLQueryDrive queryForFilesGetWithFileId:child.identifier];                              
                          query.completionBlock = ^(GTLServiceTicket *ticket, GTLDriveFile *file, NSError *error) {

                              //increment count inside this call is very important. Becasue the execute query call is asynchronous
                              count ++;
                              NSLog(@"Google Drive: retrieving children info: %d", count);                                  
                              if (error == nil) {
                                  if (file != nil) { //checking the file resource is available or not
                                      //only add the file info if that file was not in trash
                                      if (file.labels.trashed.intValue != 1 )
                                          [self addFileMetaDataInfo:file numberOfChilderns:totalChildren];
                                  }

                                  //the process passed all the files then we need to sort the retrieved files
                                  if (count == totalChildren) {
                                      NSLog(@"Google Drive: processed all children, now stopping HUDView - 1");
                                      [self performSelectorOnMainThread:@selector(reloadTableDataFromMainThread) withObject:nil waitUntilDone:NO];
                                  }
                              } else {
                                  //the file resource was not found
                                  NSLog(@"Google Drive: error occurred while retrieving file info: %@", error);

                                  if (count == totalChildren) {
                                      NSLog(@"Google Drive: processed all children, now stopping HUDView - 2");
                                      [self performSelectorOnMainThread:@selector(reloadTableDataFromMainThread)
                                                             withObject:nil waitUntilDone:NO];
                                  }                                      
                              }                                  
                          };                              
                          //add the query into batch query. Since we no need to iterate the google server for each child.
                          [batchQuery addQuery:query];
                      }                          
                      //finally execute the batch query. Since the file retrieve process is much faster because it will get all file metadata info at once
                      [self.driveService executeQuery:batchQuery
                                    completionHandler:^(GTLServiceTicket *ticket,
                                                        GTLDriveFile *file,
                                                        NSError *error) {
                                    }];

                      NSLog(@"\nGoogle Drive: file count in the folder: %d", children.items.count);
                  } else {
                      NSLog(@"Google Drive: error occurred while retrieving children list from parent folder: %@", error);
                  }
              }];

}

step-2: add the file metadata info

    -(void)addFileMetaDataInfo:(GTLDriveFile*)file numberOfChilderns:(int)totalChildren
{
    NSString *fileName = @"";
    NSString *downloadURL = @"";

    BOOL isFolder = NO;

    if (file.originalFilename.length)
        fileName = file.originalFilename;
    else
        fileName = file.title;

    if ([file.mimeType isEqualToString:@"application/vnd.google-apps.folder"]) {
        isFolder = YES;
    } else {
        //the file download url not exists for native google docs. Sicne we can set the import file mime type
        //here we set the mime as pdf. Since we can download the file content in the form of pdf
        if (!file.downloadUrl) {
            GTLDriveFileExportLinks *fileExportLinks;

            NSString    *exportFormat = @"application/pdf";

            fileExportLinks = [file exportLinks];
            downloadURL = [fileExportLinks JSONValueForKey:exportFormat];
        } else {
            downloadURL = file.downloadUrl;
        }
    }

    if (![fileNames containsObject:fileName]) {
        [fileNames addObject:fileName];

        NSArray *fileInfoArray = [NSArray arrayWithObjects:file.identifier, file.mimeType, downloadURL,
                                  [NSNumber numberWithBool:isFolder], nil];
        NSDictionary *dict = [NSDictionary dictionaryWithObject:fileInfoArray forKey:fileName];

        [self.driveFiles addObject:dict];
    }
}

step-3: download the file based on file select on the table row

    NSString *downloadUrl = [[[[self.driveFiles objectAtIndex:selectedFileIdx] allValues] objectAtIndex:0]
                   objectAtIndex:download_url_link];
NSLog(@"\n\ngoogle drive file download url link = %@", downloadUrl);    
GTMHTTPFetcher *fetcher =
[self.driveService.fetcherService fetcherWithURLString:downloadUrl];    
//async call to download the file data
[fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
    if (error == nil) {
        NSLog(@"\nfile %@ downloaded successfully from google drive", self.selectedFileName);

        //saving the downloaded data into temporary location
        [data writeToFile:<path> atomically:YES];               
    } else {
        NSLog(@"An error occurred: %@", error);
    }
}];


回答2:

Documents in Google Docs native formats can't be downloaded as other files, but only exported to different supported formats using the exportLinks URLs.

For more details and the list of supported formats check the Google Drive SDK documentation:

https://developers.google.com/drive/manage-downloads#downloading_google_documents



回答3:

I had similar problem before. Specifically, I did not find downloadurl for the native documents created in Google Document. They are null. Only those created through DrEdit (solutions exemplified in Drive SDK) are associated with downloadUrl.

The solution is actually embedded in the attribute: JSON in GTLDriveFileExportLinks instance, which returns NSMutableDictionary*. You can choose to view the content of JSON object via access JSONString attribute. The JSON mutatable dictionary can be obtained through querying exportLinks in GTLDriveFile instance. The example is as below:

GTLDriveFile *file = files.items[0]; // assume file is assigned to a valid instance.
NSMutableDictionary *jsonDict = file.exportLinks.JSON; 
NSLog(@"URL:%@.", [jsonDict objectForKey:@"text/plain"]);