Intereting Posts
Автоматически форматировать номер телефона в EditText Обработка NDK Bitmap с использованием голубого цвета OpenCv оранжевого цвета? Android GCM SENDER_ID, как его получить? Android загружает маркеры динамически лучшей стратегии Приложение не запускается в визуальном студийном эмуляторе для Android в visual studio 2015 Как сохранить список в Android и получить его обратно, когда это необходимо? Как добавить файл конфигурации в студию Android в окнах? Переключение фрагментов или действий (т.е. макетов) на изменение ориентации Разный SoftInputMode в той же самой деятельности, возможно ли это? Как получить данные из базы данных firebase, которая имеет структуру вложенных массивов и объектов? Устройства Genymotion, не работающие в Eclipse на OS X Yosemite Android Spinner не поддерживает рендеринг, если сгенерирован программно в android 2.0 Как получить номер IMEI в PhoneGap? Maven и android – Немного разные сборки для разных сред Удаление пустого места рядом с логотипом приложения (ActionBar Sherlock)

Возобновляемая загрузка в API Drive Rest V3

Я пытаюсь создать возобновляемый сеанс загрузки, используя API для управления приводом на Android.

В соответствии с документацией необходимо выполнить 3 этапа:

  1. Начало возобновляемой сессии
  2. Сохранить возобновляемый URI сеанса
  3. Загрузите файл

Шаг 1: я использую следующий код для запуска возобновляемого сеанса.

File body = new File(); body.setName(fileName); body.setMimeType(mimeType); body.setCreatedTime(modifiedDate); body.setModifiedTime(modifiedDate); body.setParents(Collections.singletonList(parentId)); HttpHeaders header = new HttpHeaders(); header.setContentLength(0L); header.setContentType("application/json; charset=UTF-8"); header.set("X-Upload-Content-Type","image/jpeg"); HttpResponse response= driveObject .files() .create(body) .setRequestHeaders(header) .set("uploadType","resumable") .buildHttpRequest() .execute(); 

Шаг 2: Как только выполнение завершено, я печатаю заголовок ответа запроса, чтобы увидеть URI местоположения

 System.out.println(response.getHeader().toString()); 

Вывод следующий:

 { cache-control=[no-cache, no-store, max-age=0, must-revalidate], content-encoding=[gzip], content-type=[application/json; charset=UTF-8], date=[Thu, 06 Oct 2016 02:20:18 GMT], expires=[Mon, 01 Jan 1990 00:00:00 GMT], alt-svc=[quic=":443"; ma=2592000; v="36,35,34,33,32"], pragma=[no-cache], server=[GSE], transfer-encoding=[chunked], vary=[Origin, X-Origin], x-android-received-millis=[1475720421761], x-android-response-source=[NETWORK 200], x-android-sent-millis=[1475720420804], x-content-type-options=[nosniff], x-frame-options=[SAMEORIGIN], x-xss-protection=[1; mode=block] } 

Я не нашел URI местоположения в заголовке ответа, чтобы начать загрузку filedata, как указано в документации, и я не нахожу образцы Java для повторной загрузки.

Как получить идентификатор местоположения местоположения, как указано в документации?

Я пробовал в течение большей части недели, и я наконец получил возобновленные загрузки для запуска. Это не работает, как я ожидал, но это сработает.

Не используйте API REST для всех

Я узнал, что API REST Google Диска, насколько мне известно, не способен делать куски загрузок. Это может быть ошибка, или это может быть по дизайну. Я тоже могу быть слишком глупым.

Но я подумал, что я не вижу примеров кода нигде . Все просто говорили о заголовках Http все время. Так вот что мы будем делать ниже. Мы будем использовать только заголовки.

Итак, вот как вы делаете возобновляемые, загруженные загрузки с помощью API REST Google Диска и Android:

0) Инициализация

 String accountName = "account_name"; GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(context, Arrays.asList(SCOPES)).setBackOff(new ExponentialBackOff()).setSelectedAccountName(accountName); 

1) Начало возобновляемой сессии

Следуйте правилам, изложенным Google в этом документе :

 POST /upload/drive/v3/files?uploadType=resumable HTTP/1.1 Host: www.googleapis.com Authorization: Bearer your_auth_token Content-Length: 38 Content-Type: application/json; charset=UTF-8 X-Upload-Content-Type: image/jpeg X-Upload-Content-Length: 2000000 { "name": "My File" } 

Установите все поля заголовка точно так же, как в примере Google. Отправьте его как запрос POST . Используйте свою credential переменную, чтобы получить токен авторизации. Тип mime для X-Upload-Content-Type не так важен, он работает без него ( этот SO-ответ обеспечивает хорошую функцию для извлечения его из пути). Установите X-Upload-Content-Length в общую длину файла. Установите Content-Type в формат JSON, так как наш орган предоставит метаданные для Google в формате JSON.

Теперь создайте тело метаданных. Я ввел имя файла и родителя. Установите Content-Length в длину вашего body в байтах. Затем напишите свое тело в поток request.getOutputStream() .

 URL url = new URL("https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable"); HttpURLConnection request = (HttpURLConnection) url.openConnection(); request.setRequestMethod("POST"); request.setDoInput(true); request.setDoOutput(true); request.setRequestProperty("Authorization", "Bearer " + credential.getToken()); request.setRequestProperty("X-Upload-Content-Type", getMimeType(file.getPath())); request.setRequestProperty("X-Upload-Content-Length", String.format(Locale.ENGLISH, "%d", file.length())); request.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); String body = "{\"name\": \"" + file.getName() + "\", \"parents\": [\"" + parentId + "\"]}"; request.setRequestProperty("Content-Length", String.format(Locale.ENGLISH, "%d", body.getBytes().length)); OutputStream outputStream = request.getOutputStream(); outputStream.write(body.getBytes()); outputStream.close(); request.connect(); 

2) Сохранить возобновляемый URI сеанса

Наконец, connect() и дождитесь ответа. Если код ответа 200 , вы успешно инициировали перезапущенную, возобновляемую загрузку. Теперь сохраните URI заголовка location где-нибудь (база данных, текстовый файл, что угодно). Вам это понадобится позже.

 if (request.getResponseCode() == HttpURLConnection.HTTP_OK) { String sessionUri = request.getHeaderField("location"); } 

3) Загрузите файл

 PUT {session_uri} HTTP/1.1 Host: www.googleapis.com Content-Length: 524288 Content-Type: image/jpeg Content-Range: bytes 0-524287/2000000 bytes 0-524288 

Поместите следующий код в цикл, пока не будет загружен весь файл. После каждого фрагмента вы получите ответ с кодом 308 и заголовком range . Из этого заголовка range вы можете прочитать следующий запуск блока (см. (4)).

Content-Type снова будет типом mime. Content-Length – количество байтов, загружаемых в этот кусок. Content-Range должен иметь форму bytes startByte-EndByte/BytesTotal . Вы помещаете это в запрос PUT .

Затем вы создаете FileInputStream и устанавливаете позицию в стартовый байт (который вы получили из последнего заголовка range ответа) и читаете другой кусок в свой буфер. Затем этот буфер записывается в выходной поток соединения. Наконец, connect() .

 URL url = new URL(sessionUri); HttpURLConnection request = (HttpURLConnection) url.openConnection(); request.setRequestMethod("PUT"); request.setDoOutput(true); request.setConnectTimeout(10000); request.setRequestProperty("Content-Type", getMimeType(file.getPath())); long uploadedBytes = chunkSizeInMb * 1024 * 1024; if (chunkStart + uploadedBytes > file.length()) { uploadedBytes = (int) file.length() - chunkStart; } request.setRequestProperty("Content-Length", String.format(Locale.ENGLISH, "%d", uploadedBytes)); request.setRequestProperty("Content-Range", "bytes " + chunkStart + "-" + (chunkStart + uploadedBytes - 1) + "/" + file.length()); byte[] buffer = new byte[(int) uploadedBytes]; FileInputStream fileInputStream = new FileInputStream(file); fileInputStream.getChannel().position(chunkStart); if (fileInputStream.read(buffer, 0, (int) uploadedBytes) == -1) { /* break, return, exit*/ } fileInputStream.close(); OutputStream outputStream = request.getOutputStream(); outputStream.write(buffer); outputStream.close(); request.connect(); 

4) Обработка ответа

После этого вы получите ответ с кодом 308 (в случае успеха). Этот ответ содержит заголовок range (упомянутый).

 HTTP/1.1 308 Resume Incomplete Content-Length: 0 Range: bytes=0-524287 

Вы разделите это и получите новый байт запуска.

  String range = chunkUploadConnection.getHeaderField("range"); int chunkPosition = Long.parseLong(range.substring(range.lastIndexOf("-") + 1, range.length())) + 1; 

5) Код ответа не 308 ?!

Может случиться так, что вы получите ответ 5xx . Ваше интернет-соединение может потерпеть неудачу, файл может быть удален / переименован во время загрузки и т. Д. И т. Д. Не беспокойтесь. Пока вы сохраняете свой URI сеанса и байт start byte, вы можете возобновить загрузку в любое время.

Для этого отправьте заголовок следующей формы:

 PUT {session_uri} HTTP/1.1 Content-Length: 0 Content-Range: bytes */TotalFileLength URL url = new URL(sessionUri); HttpURLConnection request = (HttpURLConnection) url.openConnection(); request.setRequestMethod("PUT"); request.setDoOutput(true); request.setConnectTimeout(10000); request.setRequestProperty("Content-Length", "0"); request.setRequestProperty("Content-Range", "bytes */" + file.length()); request.connect(); 

Затем вы получите 308 с заголовком range , из которого вы можете прочитать последний загруженный байт (как мы это делали выше). Возьмите это число и снова начните цикл.

Надеюсь, я смогу помочь некоторым из вас. Если у вас есть еще вопросы, просто спросите в комментариях, и я отредактирую ответ.

Если вы смогли получить 200 Http-статус, он предоставит Location как часть заголовка. Но из того, что я видел на вашем System.print , HttpResponse.getHeader нет, это может быть просто опечатка, и вы имеете в виду HttpResponse.getHeaders .

Если это так, я бы предложил сначала определить, есть ли у вас код 200 OK Http и цикл getAllheaders чтобы определить, есть ли заголовок Location .

Надеюсь это поможет!