Использование Google Cloud Print API с Android

Я работаю над приложением для Android, которое необходимо распечатать на принтере. Я решил использовать Google Cloud Print, поскольку это казалось простым в настройке. Сначала я следовал инструкциям по интеграции в Android. Это работает, так как в нем будет печататься на мой нужный принтер. Однако этот процесс немного связан с пользователем. В моем случае процесс выглядит следующим образом:

  1. Пользователь выбирает кнопку печати, которая отображается рядом с некоторой информацией.
  2. Диалог показан с предварительным просмотром того, что будет напечатано. На панели действий есть кнопка с надписью "Печать". Это начинает процесс.
  3. Появится новая активность, показывающая список принтеров, которые подключены к этой учетной записи пользователя Google. Пользователь должен выбрать один.
  4. Появится новая страница с описанием задания на печать.
  5. Пользователь должен выбрать "Печать" в правом верхнем углу.
  6. Задание на печать запущено, и принтер распечатывает изображение.

К сожалению, мой клиент не хочет этот процесс. Они хотят, чтобы пользователь щелкнул "Печать" на втором шаге, а затем распечатал изображение (шаги 1, 2 и 6). Таким образом, я не могу использовать Намерение, предоставленное Google, я должен использовать реальный API. Для этого мне нужно получить токен Google Auth, получить нужный принтер и отправить задание на печать таким образом. Я делаю следующее:

  1. Используйте Сервисы Google Play, чтобы получить токен OAuth для учетной записи Gmail.
  2. Получите список принтеров с помощью вызова API /search.
  3. Отправьте задание на печать с помощью вызова API /submit.

Я закончил первые два. У меня просто проблемы с фактической печатью картинки. Вместо печати изображения печатаются байтовые данные изображения (в кодировке Base64). Вот некоторый код относительно того, как я отправляю запрос:

ContentResolver contentResolver = context.getContentResolver();
try {
    InputStream is = contentResolver.openInputStream(uri);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    byte[] buffer = new byte[4096];
    int n = is.read(buffer);
    while (n >= 0) {
            baos.write(buffer, 0, n);
            n = is.read(buffer);
    }
    is.close();
    baos.flush();

    content = Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);
} catch (FileNotFoundException e) {
    Log.d(TAG, "File not found: " + uri.toString(), e);
} catch (IOException e) {
    e.printStackTrace();
}

Этот код извлекает изображение (переменная "uri" является URI этого файла) и превращает его в строку в кодировке Base64. Это тот же метод, который используется в PrintDialogActivity, который предоставляется на странице Google Cloud Print (ссылка указана выше). Вот как я это отправляю:

Насколько я могу судить, так и должно быть. Я получаю ответ {"success":true} при печати. Но, как я уже сказал выше, он печатает фактическую строку данных Base64. Любая помощь будет оценена.

РЕДАКТИРОВАТЬ: Используя то, что Powerje сказал ниже, мне удалось это исправить. Вместо того, чтобы использовать код выше, я использовал следующее:

public void submitPrintJobWithFile(String printerId, String title, String token, String filePath, String contentType){
    File file = new File(filePath);
    // Method that gets the correct headers
    List<Header> headers = getHeaders(contentType, token);
    // Method that gets the correct post parameters
    String url = CLOUDPRINT_URL + PATH_SUBMIT;
    List<NameValuePair> postParams = getParams(title, contentType);
    String params = "access_token=" + token + "&cookies=false" + "&printerid=" + printerId;
    url += params;
    response = sendMultipartData(url, file, postParams, headers);
}

private String sendMultipartData(String url, File file, List<NameValuePair> fields, List<Header> headers){
    HttpPost post = new HttpPost(url);
    MultipartEntity entity = new MultipartEntity();
    for(NameValuePair pair : fields){
        String name = pair.getName();
        String value = pair.getValue();
        try{
            entity.addPart(name, new StringBody(value));
        }catch (UnsupportedEncodingException e){
            Log.d(TAG, "Error turning pair (name=" + name + ", value=" + value + ") into StringBody.");
    }
    entity.addPart("content", new FileBody(file));
    post.setEntity(entity);
    // Finish HttpClient request here...
}

3 ответа

Решение

Похоже, вам нужно использовать многочастное кодирование, пример здесь:

http://blog.tacticalnuclearstrike.com/2010/01/using-multipartentity-in-android-applications/

FTA:

Необходимые файлы: apache-mime4j, httpclient, httpcore и httpmime. Все это проекты с открытым исходным кодом, созданные фондом Apache.

Загрузите 4 файла и добавьте их в свой проект, тогда вы сможете использовать следующий код для размещения строк и файлов на страницах.

HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.tumblr.com/api/write");

try {
    MultipartEntity entity = new MultipartEntity();

    entity.addPart("type", new StringBody("photo"));
    entity.addPart("data", new FileBody(image));
    httppost.setEntity(entity);
    HttpResponse response = httpclient.execute(httppost);
} catch (ClientProtocolException e) {
} catch (IOException e) {
} 

Переменная изображения в этом случае - это файл, который содержит изображение, снятое камерой на телефоне.

Глядя на метод SubmitJob примера кода Python, кажется, что в Base64 необходимо кодировать только типы PDF.

Отвечая на вопрос с небольшим обновлением. По состоянию на октябрь 2013 года в 4.4 и в библиотеке поддержки появились встроенные методы для обработки печати. Смотрите следующую документацию, чтобы узнать, как это сделать правильно:

  • PrintHelper - класс поддержки библиотеки, чтобы помочь с печатью растровых изображений.
  • DevBytes: Android 4.4 Printing API - видео для разработчиков Android с подробным описанием API
  • Печать контента - учебное пособие по Android, посвященное использованию этих API.
Другие вопросы по тегам