Использование Google Cloud Print API с Android
Я работаю над приложением для Android, которое необходимо распечатать на принтере. Я решил использовать Google Cloud Print, поскольку это казалось простым в настройке. Сначала я следовал инструкциям по интеграции в Android. Это работает, так как в нем будет печататься на мой нужный принтер. Однако этот процесс немного связан с пользователем. В моем случае процесс выглядит следующим образом:
- Пользователь выбирает кнопку печати, которая отображается рядом с некоторой информацией.
- Диалог показан с предварительным просмотром того, что будет напечатано. На панели действий есть кнопка с надписью "Печать". Это начинает процесс.
- Появится новая активность, показывающая список принтеров, которые подключены к этой учетной записи пользователя Google. Пользователь должен выбрать один.
- Появится новая страница с описанием задания на печать.
- Пользователь должен выбрать "Печать" в правом верхнем углу.
- Задание на печать запущено, и принтер распечатывает изображение.
К сожалению, мой клиент не хочет этот процесс. Они хотят, чтобы пользователь щелкнул "Печать" на втором шаге, а затем распечатал изображение (шаги 1, 2 и 6). Таким образом, я не могу использовать Намерение, предоставленное Google, я должен использовать реальный API. Для этого мне нужно получить токен Google Auth, получить нужный принтер и отправить задание на печать таким образом. Я делаю следующее:
- Используйте Сервисы Google Play, чтобы получить токен OAuth для учетной записи Gmail.
- Получите список принтеров с помощью вызова API /search.
- Отправьте задание на печать с помощью вызова 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 (ссылка указана выше). Вот как я это отправляю:
- URL: http://www.google.com/cloudprint/submit?access_token=[AUTH_TOKEN_GOES_HERE]&cookies=false&printerid=[PRINTER_ID_HERE]
- Метод HTTP: POST
- Параметры POST: [printerId=PRINTER_ID_HERE, title=TestPrint, contentType=image/jpeg,abilities={"abilities":[{}]}, content=[Строка закодированных данных Base64 находится здесь]]
Насколько я могу судить, так и должно быть. Я получаю ответ {"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.