混合应用中的Google云端硬盘文件上传

时间:2016-05-05 16:10:51

标签: android ios google-drive-api

我们有一个混合应用程序,其中大部分代码都是通过Javascript处理的(包括通过Google登录登录和一些上传到Google云端硬盘)。在iOS上,我们有其他Google云端硬盘上传代码,但我无法弄清楚如何在Android中完成相同的操作。我试图避免让用户登录到网络部分然后再次登录Android。

用于上传的iOS代码是......

let mutableURLRequest           = NSMutableURLRequest(URL: NSURL(string: "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart")!)
mutableURLRequest.HTTPMethod    = "POST"
let boundaryConstant            = generateBoundaryString()
let contentType                 = "multipart/related; boundary="+boundaryConstant

// Set the headers
mutableURLRequest.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
mutableURLRequest.addValue("Keep-Alive", forHTTPHeaderField: "Connection")
mutableURLRequest.addValue(contentType, forHTTPHeaderField: "Content-Type")
mutableURLRequest.addValue("\(requestData.length)", forHTTPHeaderField: "Content-Length")

// create upload data to send
let uploadData = NSMutableData()
uploadData.appendData("\r\n--\(boundaryConstant)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)

let date        = NSDate()
let calendar    = NSCalendar.currentCalendar()
let components  = calendar.components([.Day, .Month, .Year], fromDate: date)
let fileName    = "\(components.year)-\(components.month)-\(components.day).\(ext)"

// Add parameters
let params = [
    "name":             fileName,
    "mimeType":         mimeType,
    "parents":          ["\(slnFldrId)"],
    "convert":          true
]

// Add the file meta data (JSON format)
uploadData.appendData("Content-Type: application/json; charset=UTF-8\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData("\(getJsonString(params))\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData("\r\n--\(boundaryConstant)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)

// Add the file
uploadData.appendData("Content-Type: \(mimeType)\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
uploadData.appendData(requestData)
uploadData.appendData("\r\n--\(boundaryConstant)--\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)

mutableURLRequest.HTTPBody = uploadData

let configuration   = NSURLSessionConfiguration.defaultSessionConfiguration()
let session         = NSURLSession(configuration: configuration, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
let task            = session.uploadTaskWithStreamedRequest(mutableURLRequest)
task.resume()

...所以它只是使用REST端点并且运行良好。对于Android,我尝试使用HttpClient和HttpPost并设置标题等,但我总是得到400错误(错误请求)。

String ext      = fileName.substring(fileName.lastIndexOf(".") + 1);
String mimeType = mimeTypeFromTypeId(typeId);
String boundary = getBoundary();
String tail     = "\r\n-"+ boundary +"--\r\n";

HttpParams httpParams   = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 30000);
HttpConnectionParams.setSoTimeout(httpParams, 30000);
HttpClient httpClient   = new DefaultHttpClient(httpParams);
HttpPost httpPost       = new HttpPost("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
httpPost.addHeader("Authorization", "Bearer "+ Common.accessToken);
httpPost.addHeader("Content-Length", ""+ file.length());

String json = "{\"name\":\"Android upload."+ ext +"\",\"mimeType\":\""+ mimeType +"\",\"parents\":[\""+ Common.slnFldrId +"\"],\"convert\":true}";

MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
entityBuilder.setBoundary(boundary);
entityBuilder.setCharset(MIME.UTF8_CHARSET);
entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
entityBuilder.addTextBody("", json, ContentType.APPLICATION_JSON);
entityBuilder.addBinaryBody("", file, ContentType.create(mimeType), "Android upload."+ ext);

httpPost.setEntity(entityBuilder.build());

httpPost.setHeader(HTTP.CONTENT_TYPE, "multipart-related; boundary="+ boundary);
try
{
    return httpClient.execute(httpPost);
}
catch(ConnectTimeoutException e)
{
    throw e;
}

...我认为标头导致了错误的请求错误。即使我将Content-Type标头设置为multipart / related,它总是转换为multipart / form-data(我认为是MultipartEntityBuilder)。

据我所知,Google客户端库都需要授权程序(因为我无法通过网络登录将我已经拥有的accessToken设置到其中),这就是我的原因。我没有使用它们。

非常感谢任何帮助或建议。

1 个答案:

答案 0 :(得分:0)

我找到的解决方案基于http://www.codejava.net/java-se/networking/upload-files-by-sending-multipart-request-programmatically

上的文章

以下代码包含一些更改,以使其与Google Drive API一起正常运行。

URL url                         = null;
HttpURLConnection connection    = null;
try
{
    // Set up some constants and "global" variables
    String BOUNDARY             = getBoundary();
    String LINE_FEED            = "\r\n";
    String UTF8                 = "UTF-8";

    String fileName = file.getName();
    String ext      = fileName.substring(fileName.lastIndexOf(".") + 1);
    String mimeType = mimeTypeFromTypeId(typeId);

    // Use the calendar to give the file a name
    Calendar cal    = Calendar.getInstance();
    int cYear       = cal.get(Calendar.YEAR);//calender year starts from 1900 so you must add 1900 to the value recevie.i.e., 1990+112 = 2012
    int cMonth      = cal.get(Calendar.MONTH);//this is april so you will receive  3 instead of 4.
    int cDay        = cal.get(Calendar.DAY_OF_MONTH);
    int cHour       = cal.get(Calendar.HOUR_OF_DAY);
    int cMin        = cal.get(Calendar.MINUTE);
    int cSec        = cal.get(Calendar.SECOND);
    String name     = cYear +"-"+ cMonth +"-"+ cDay +"-"+ cHour +"-"+ cMin +"-"+ cSec +"."+ ext;

    // JSON meta-data part
    String json         = "{\"name\":\""+ name +"\",\"mimeType\":\""+ mimeType +"\",\"parents\":[\""+ Common.slnFldrId +"\"],\"convert\":true}";
    String META_PART1   = "--"+ BOUNDARY + LINE_FEED
            + "Content-Type: application/json; charset="+ UTF8 + LINE_FEED + LINE_FEED
            + json + LINE_FEED + LINE_FEED;

    // File meta-data part
    String META_PART2   = "--"+ BOUNDARY + LINE_FEED
            + "Content-Type: "+ mimeType + LINE_FEED + LINE_FEED;

    // Tail
    String TAIL         = LINE_FEED +"--"+ BOUNDARY +"--";

    long contentLength  = META_PART1.length() + META_PART2.length() + file.length() + TAIL.length();

    // Set up the HttpUrlConnection
    url         = new URL("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
    connection  = (HttpURLConnection) url.openConnection();
    connection.setReadTimeout(10000);
    connection.setConnectTimeout(15000);
    connection.setDoInput(true);
    connection.setDoOutput(true);
    connection.setInstanceFollowRedirects(false);
    connection.setRequestProperty("Authorization", "Bearer "+ Common.accessToken);
    connection.setRequestProperty("Content-Type", "multipart/related; boundary="+ BOUNDARY);
    connection.setRequestProperty("Content-Length", ""+ contentLength);
    connection.connect();

    // Get the connection's output stream
    OutputStream outputStream    = connection.getOutputStream();

    // Write the META_PART1 (JSON) and flush
    outputStream.write(META_PART1.getBytes(UTF8));
    outputStream.flush();

    // Write the META_PART2 (file's contentType) and flush
    outputStream.write(META_PART2.getBytes(UTF8));
    outputStream.flush();

    // Write the FILE
    int totalRead   = 0;
    int bytesRead   = -1;
    byte[] buffer   = new byte[4096];
    FileInputStream inputStream = new FileInputStream(file);
    while ((bytesRead = inputStream.read(buffer)) != -1)
    {
        outputStream.write(buffer, 0, bytesRead);
        outputStream.flush();
        totalRead      += bytesRead;
        float progress  = totalRead / (float)contentLength;
        delegate.onUploadProgress(progress);
    }
    // Flush the last of the file data and close the inputStream
    outputStream.flush();
    inputStream.close();

    // Flush the TAIL and close the outputStream
    outputStream.write(TAIL.getBytes(UTF8));
    outputStream.flush();
    outputStream.close();

    // Get the server response
    int responseCode = connection.getResponseCode();
    if(responseCode == HTTP_SUCCESS)
    {
        BufferedReader reader   = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        String line             = "";
        StringBuilder builder   = new StringBuilder();
        while ((line = reader.readLine()) != null)
        {
            builder.append(line);
        }
        // Send the completed message to the delegate
        delegate.onUploadComplete(builder.toString(), typeId);
    }
    else
    {
        // Send the error message to the delegate
        delegate.onUploadError(file);
    }
}catch(IOException e)
{
    // Send the error message to the delegate
    delegate.onUploadError(file);
}finally
{
    if(connection != null)
    {
        connection.disconnect();
    }
}