Java библиотека, созданная для работы с Telegram Bot API
- Полная поддержка всех методов BOT API 6.9
- Поддержка Telegram паспорта и дешифровки (Decryption API);
- Поддержка платежей;
- Игровая платформа.
Gradle:
implementation 'com.github.pengrad:java-telegram-bot-api:6.9.1'
Maven:
<dependency>
<groupId>com.github.pengrad</groupId>
<artifactId>java-telegram-bot-api</artifactId>
<version>6.9.1</version>
</dependency>
Также JAR со всеми зависимостями можно найти в релизах.
// Создание бота путем передачи токена, полученного от @BotFather
TelegramBot bot = new TelegramBot("BOT_TOKEN");
// Подписка на обновления
bot.setUpdatesListener(updates -> {
// Обработка обновлений
// return id of last processed update or confirm them all
return UpdatesListener.CONFIRMED_UPDATES_ALL;
// Создание Обработчика ошибок
}, e -> {
if (e.response() != null) {
// Ошибка из Телеграма
e.response().errorCode();
e.response().description();
} else {
// Как видно проблема сети
e.printStackTrace();
}
});
// Отправка сообщений
long chatId = update.message().chat().id();
SendResponse response = bot.execute(new SendMessage(chatId, "Hello!"));
- Создание бота
- Создание ответов
- Получение обновлений
- Доступные типы
- Доступные методы
- Обновление сообщений
- Стикеры
- Inline-режим
- Платежи
- Telegram паспорт
- Игры
TelegramBot bot = new TelegramBot("BOT_TOKEN");
Сетевые операции основаны на библиотеке OkHttp.
Вы можете создать бота с нестандартным OkHttpClient для использования собственных таймаутов и перехватчиков.
TelegramBot bot = new TelegramBot.Builder("BOT_TOKEN").okHttpClient(client).build();
Синхронно
BaseResponse response = bot.execute(request);
Асинхронно
bot.execute(request, new Callback() {
@Override
public void onResponse(BaseRequest request, BaseResponse response) {
}
@Override
public void onFailure(BaseRequest request, IOException e) {
}
});
String response = request.toWebhookResponse();
Для получения обновлений вы можете:
- вызвать метод getUpdates;
- распарсить входящий запрос по Webhook;
- установить слушателя для получения обновлений.
Класс Update просто копирует ответ, полученный от Telegram.
class Update {
Integer updateId();
Message message();
Message editedMessage();
InlineQuery inlineQuery();
ChosenInlineResult chosenInlineResult();
CallbackQuery callbackQuery();
}
Создание запроса
GetUpdates getUpdates = new GetUpdates().limit(100).offset(0).timeout(0);
Метод getUpdates возвращает 100 самых ранних необработанных обновлений. Для пометки обновления, как обработанного, используйте параметр смещения при вызове getUpdates следующим образом:
offset = updateId последнего обработанного обновления + 1
Все обновления, updateId которых меньше, чем смещение, будут помечены на сервере как обработанные и больше не будут возвращаться.
Исполнение
// Синхронно
GetUpdatesResponse updatesResponse = bot.execute(getUpdates);
List<Update> updates = updatesResponse.updates();
...
Message message = update.message()
// Асинхронно
bot.execute(getUpdates, new Callback<GetUpdates, GetUpdatesResponse>() {
@Override
public void onResponse(GetUpdates request, GetUpdatesResponse response) {
List<Update> updates = response.updates();
}
@Override
public void onFailure(GetUpdates request, IOException e) {
}
});
Создание запроса
SetWebhook request = new SetWebhook()
.url("url")
.certificate(new byte[]{}) // byte[]
.certificate(new File("path")); // или File
Исполнение
// Синхронно
BaseResponse response = bot.execute(request);
boolean ok = response.isOk();
// Асинхронно
bot.execute(request, new Callback<SetWebhook, BaseResponse>() {
@Override
public void onResponse(SetWebhook request, BaseResponse response) {
}
@Override
public void onFailure(SetWebhook request, IOException e) {
}
});
Используя веб хук Вы можете распарсить запрос в Update
Update update = BotUtils.parseUpdate(stringRequest); // из String
Update update = BotUtils.parseUpdate(reader); // или из java.io.Reader
Message message = update.message();
Вы можете установить слушателя для получения входящих обновлений, как при использовании вебхука.
При этом getUpdates будет выполняться в цикле.
bot.setUpdatesListener(new UpdatesListener() {
@Override
public int process(List<Update> updates) {
// обработка обновлений
return UpdatesListener.CONFIRMED_UPDATES_ALL;
}
// Создание Обработчика ошибок
}, new ExceptionHandler() {
@override
public void onException(TelegramException e)
{
if (e.response() != null) {
// Ошибка из Телеграма
e.response().errorCode();
e.response().description();
} else {
// Как видно проблема сети
e .printStackTrace();
}
}
});
Слушатель должен возвращать id последнего обработанного (подтвержденного) обновления.
- Для подтверждения обработки всех обновлений используйте
UpdatesListener.CONFIRMED_UPDATES_ALL
, этого будет достаточно в большинстве случаев; - Для того чтобы не подтверждать обработку обновлений, используйте
UpdatesListener.CONFIRMED_UPDATES_NONE
, эти обновления будут передоставлены; - Чтобы установить определенное обновление, как последнее обработанное, возвращайте его updateId.
Для прекращения получения обновлений
bot.removeGetUpdatesListener();
Все типы такие же, как и оригинальные. Поля типов - методы в нижнем CamelCase.
Типы, используемые в ответах (Update, Message, User, Document...), расположены в пакете com.pengrad.telegrambot.model
.
Типы, используемые в запросах (Keyboard, InlineQueryResult, ParseMode, InputMessageContent...), расположены в пакете com.pengrad.telegrambot.model.request
.
При создании пользовательского типа для использования в запросах обязательные параметры должны быть переданы в конструкторе, необязательные параметры могут быть добавлены в цепочках.
ForceReply, ReplyKeyboardRemove
Keyboard forceReply = new ForceReply(isSelective); // or just new ForceReply();
Keyboard replyKeyboardRemove = new ReplyKeyboardRemove(); // new ReplyKeyboardRemove(isSelective)
ReplyKeyboardMarkup
Keyboard replyKeyboardMarkup = new ReplyKeyboardMarkup(
new String[]{"first row button1", "first row button2"},
new String[]{"second row button1", "second row button2"})
.oneTimeKeyboard(true) // optional
.resizeKeyboard(true) // optional
.selective(true); // optional
KeyboardButton
Keyboard keyboard = new ReplyKeyboardMarkup(
new KeyboardButton[]{
new KeyboardButton("text"),
new KeyboardButton("contact").requestContact(true),
new KeyboardButton("location").requestLocation(true)
}
);
InlineKeyboardMarkup
InlineKeyboardMarkup inlineKeyboard = new InlineKeyboardMarkup(
new InlineKeyboardButton[]{
new InlineKeyboardButton("url").url("www.google.com"),
new InlineKeyboardButton("callback_data").callbackData("callback_data"),
new InlineKeyboardButton("Switch!").switchInlineQuery("switch_inline_query")
});
ChatAction action = ChatAction.typing;
ChatAction action = ChatAction.upload_photo;
ChatAction action = ChatAction.find_location;
Все методы для запросов имеют такие же имена, как и оригинальные. Обязательные параметры должны быть переданы в конструкторе. Необязательные параметры могут быть добавлены в цепочках.
Все запросы на отправку (SendMessage, SendPhoto, SendLocation...) возвращают объект класса SendResponse, который содержит Message.
SendMessage request = new SendMessage(chatId, "text")
.parseMode(ParseMode.HTML)
.disableWebPagePreview(true)
.disableNotification(true)
.replyToMessageId(1)
.replyMarkup(new ForceReply());
// синхронно
SendResponse sendResponse = bot.execute(request);
boolean ok = sendResponse.isOk();
Message message = sendResponse.message();
// асинхронно
bot.execute(request, new Callback<SendMessage, SendResponse>() {
@Override
public void onResponse(SendMessage request, SendResponse response) {
}
@Override
public void onFailure(SendMessage request, IOException e) {
}
});
ParseMode parseMode = ParseMode.Markdown;
ParseMode parseMode = ParseMode.HTML;
GetFile request = new GetFile("fileId")
GetFileResponse getFileResponse = bot.execute(request);
File file = getFileResponse.file(); // com.pengrad.telegrambot.model.File
file.fileId();
file.filePath(); // относительный путь
file.fileSize();
Для получения ссылки на скачивание вида: https://api.telegram.org/file/bot<token>/<file_path>
String fullPath = bot.getFullFilePath(file); // com.pengrad.telegrambot.model.File
Все запросы возвращают BaseResponse, если не упомянуты здесь
class BaseResponse {
boolean isOk();
int errorCode();
String description();
}
Запрос GetMe возвращает GetMeResponse
class GetMeResponse {
User user();
}
Получение администраторов чата
class GetChatAdministratorsResponse {
List<ChatMember> administrators();
}
Получение количества участников в чате
class GetChatMembersCountResponse {
int count();
}
Получение участника чата
class GetChatMemberResponse {
ChatMember chatMember();
}
Получение чата
class GetChatResponse {
Chat chat();
}
Получить фото из профиля пользователя
class GetUserProfilePhotosResponse {
UserProfilePhotos photos();
}
Остановить опрос
class PollResponse {
Poll poll();
}
Обычное сообщение
EditMessageText editMessageText = new EditMessageText(chatId, messageId, "new test")
.parseMode(ParseMode.HTML)
.disableWebPagePreview(true)
.replyMarkup(new ReplyKeyboardRemove());
BaseResponse response = bot.execute(editMessageText);
Inline сообщение
EditMessageText editInlineMessageText = new EditMessageText(inlineMessageId, "new text");
BaseResponse response = bot.execute(editInlineMessageText);
Удалить сообщение
DeleteMessage deleteMessage = new DeleteMessage(chatId, messageId);
BaseResponse response = bot.execute(deleteMessage);
Отправить стикер
// Файл, массив byte[], строковое (String) fileId существующего стикера или строковый (String) URL
SendSticker sendSticker = new SendSticker(chatId, imageFile);
SendResponse response = bot.execute(sendSticker);
Получить набор стикеров
GetStickerSet getStickerSet = new GetStickerSet(stickerSet);
GetStickerSetResponse response = bot.execute(getStickerSet);
StickerSet stickerSet = response.stickerSet();
Загрузить файл со стикером
// Файл, массив byte[], строковый (String URL)
UploadStickerFile uploadStickerFile = new UploadStickerFile(chatId, stickerFile);
GetFileResponse response = bot.execute(uploadStickerFile);
Получение обновлений
GetUpdatesResponse updatesResponse = bot.execute(new GetUpdates());
List<Update> updates = updatesResponse.updates();
...
InlineQuery inlineQuery = update.inlineQuery();
ChosenInlineResult chosenInlineResult = update.chosenInlineResult();
CallbackQuery callbackQuery = update.callbackQuery();
При использовании веб хука Вы можете распарсить запрос в InlineQuery
Update update = BotUtils.parseUpdate(stringRequest); // из строки (String)
Update update = BotUtils.parseUpdate(reader); // из java.io.Reader
InlineQuery inlineQuery = update.inlineQuery();
InlineQueryResult r1 = new InlineQueryResultPhoto("id", "photoUrl", "thumbUrl");
InlineQueryResult r2 = new InlineQueryResultArticle("id", "title", "message text").thumbUrl("url");
InlineQueryResult r3 = new InlineQueryResultGif("id", "gifUrl", "thumbUrl");
InlineQueryResult r4 = new InlineQueryResultMpeg4Gif("id", "mpeg4Url", "thumbUrl");
InlineQueryResult r5 = new InlineQueryResultVideo(
"id", "videoUrl", InlineQueryResultVideo.MIME_VIDEO_MP4, "message", "thumbUrl", "video title")
.inputMessageContent(new InputLocationMessageContent(21.03f, 105.83f));
BaseResponse response = bot.execute(new AnswerInlineQuery(inlineQuery.id(), r1, r2, r3, r4, r5));
// или полностью
bot.execute(
new AnswerInlineQuery(inlineQuery.id(), new InlineQueryResult[]{r1, r2, r3, r4, r5})
.cacheTime(cacheTime)
.isPersonal(isPersonal)
.nextOffset("offset")
.switchPmParameter("pmParam")
.switchPmText("pmText")
);
Выставить счет
SendInvoice sendInvoice = new SendInvoice(chatId, "title", "desc", "my_payload",
"providerToken", "my_start_param", "USD", new LabeledPrice("label", 200))
.needPhoneNumber(true)
.needShippingAddress(true)
.isFlexible(true)
.replyMarkup(new InlineKeyboardMarkup(new InlineKeyboardButton[]{
new InlineKeyboardButton("just pay").pay(),
new InlineKeyboardButton("google it").url("www.google.com")
}));
SendResponse response = bot.execute(sendInvoice);
Ответить на запрос о доставке
LabeledPrice[] prices = new LabeledPrice[]{
new LabeledPrice("delivery", 100),
new LabeledPrice("tips", 50)
};
AnswerShippingQuery answerShippingQuery = new AnswerShippingQuery(shippingQueryId,
new ShippingOption("1", "VNPT", prices),
new ShippingOption("2", "FREE", new LabeledPrice("free delivery", 0))
);
BaseResponse response = bot.execute(answerShippingQuery);
// оповестить об ошибке
AnswerShippingQuery answerShippingError = new AnswerShippingQuery(id, "Can't deliver here!");
BaseResponse response = bot.execute(answerShippingError);
Ответить на предварительный запрос
AnswerPreCheckoutQuery answerCheckout = new AnswerPreCheckoutQuery(preCheckoutQueryId);
BaseResponse response = bot.execute(answerPreCheckoutQuery);
// оповестить об ошибке
AnswerPreCheckoutQuery answerCheckout = new AnswerPreCheckoutQuery(id, "Sorry, item not available");
BaseResponse response = bot.execute(answerPreCheckoutQuery);
Когда пользователь подтверждает Ваш запрос путем нажатия на кнопку авторизации (Authorize), API отправляет Update с полем passport_data боту, в котором содержатся зашифрованные данные Telegram Passport. Мануал по Telegram Passport
Вы можете получить зашифрованные данные паспорта из обновления (через слушателя обновлений или веб хук)
PassportData passportData = update.message().passportData();
PassportData содержит массив из EncryptedPassportElement
и EncryptedCredentials
.
Вам необходимо дешифровать Credentials
с использованием приватного ключа (публичного ключа, загруженного к @BotFather
)
String privateKey = "...";
EncryptedCredentials encryptedCredentials = passportData.credentials();
Credentials credentials = encryptedCredentials.decrypt(privateKey);
Эти Credentials
могут быть использованы для дешифровки зашифрованных данных в EncryptedPassportElement
.
EncryptedPassportElement[] encryptedPassportElements = passportData.data();
for (EncryptedPassportElement element : encryptedPassportElements) {
DecryptedData decryptedData = element.decryptData(credentials);
// DecryptedData может быть преобразована в определенный тип с использованием проверки instanceOf
if (decryptedData instanceof PersonalDetails) {
PersonalDetails personalDetails = (PersonalDetails) decryptedData;
}
// Или путем проверки типа элемента паспорта
if (element.type() == EncryptedPassportElement.Type.address) {
ResidentialAddress address = (ResidentialAddress) decryptedData;
}
}
EncryptedPassportElement
также содержит массив из PassportFile
(файлы, загруженные в Telegram Passport).
Для дешифровки их необходимо скачать один за другим.
Данная библиотека поддерживает загрузку и дешифровку, возвращая расшифрованный массив байт (byte[]).
EncryptedPassportElement element = ...
// Группировка всех файлов
List<PassportFile> files = new ArrayList<PassportFile>();
files.add(element.frontSide());
files.add(element.reverseSide());
files.add(element.selfie());
if (element.files() != null) {
files.addAll(Arrays.asList(element.files()));
}
if (element.translation() != null) {
files.addAll(Arrays.asList(element.translation()));
}
// Расшифровка
for (PassportFile file : files) {
if (file == null) continue;
byte[] data = element.decryptFile(file, credentials, bot); // GetFile request and decrypt content
// сохранение в файл при необходимости
new FileOutputStream("files/" + element.type()).write(data);
}
SetPassportDataErrors setPassportDataErrors = new SetPassportDataErrors(chatId,
new PassportElementErrorDataField("personal_details", "first_name", "dataHash",
"Please enter a valid First name"),
new PassportElementErrorSelfie("driver_license", "fileHash",
"Can't see your face on photo")
);
bot.execute(setPassportDataErrors);
Отправка игры
SendResponse response = bot.execute(new SendGame(chatId, "my_super_game"));
Установка счета в игре
BaseResponse response = bot.execute(new SetGameScore(userId, score, chatId, messageId));
Получение списка лучших результатов
GetGameHighScoresResponse response = bot.execute(new GetGameHighScores(userId, chatId, messageId));
GameHighScore[] scores = response.result();