Представляю вам новую Qt библиотеку для работы с vk api, которая может пригодиться вам при создании любых настольных и мобильных приложений, взаимодействующих с vk. Проект родился из vkontakte плагина для qutIM'а и перерос в отдельную независимую библиотеку, которой теперь может пользоваться каждый.
Краткий обзор
Vreen это обёртка над vk.com api, написанная на C++11/Qt, предназначенная для быстрого и простого создания мобильных и настольных приложений, а также встраивания взаимодействия с vk.com api в уже существующие приложения. Библиотека поддерживает несколько способов авторизации и позволяет при необходимости добавлять свои. Также в vreen существует полноценная привязка к qml, что позволяет создавать приложения, не написав ни единой строчки на C++. Для уменьшения количества обязательных зависимостей все способы авторизации вынесены в отдельные статические библиотеки.
Основные возможности:
- Поддержка любых видов диалогов в том числе и групповых чатов.
- Поддержка просмотра новостных лент, стен.
- Работа с комментариями, в том числе добавления, лайки и репосты.
- Поддержка работы с вложениями.
- Поддержка ростера в том числе отслеживание статуса собеседников.
- Поддержка аудиозаписей.
- Возможность напрямую работать с API из qml в привычном для многих XHTTPRequest стиле.
- Расширяемость.
- Свободная LGPL лицензия, позволяющая использовать библиотеку с проприетарными приложениям.
Основы:
Базовые классы для работы с API:
- Connection — класс, основанный на QNetworkAccessManager'е, выполняющий авторизацию и непосредственно реализующий запросы к API.
- Reply — класс отслеживает выполнение запроса.
- Longpoll — класс, выполняющий опрос сервера на предмет событий.
- Roster — класс, управляющий списком друзей.
- Client — базовый класс, который сшивает всё в единое целое.
Выполнение запросов к API:
Простой запрос:
QVariantMap args;
args.insert("uids", join(ids));
args.insert("fields", fields.join(","));
auto reply = d->client->request("users.get", args);
reply->connect(reply, SIGNAL(resultReady(const QVariant&)),
this, SLOT(_q_friends_received(const QVariant&)));
Сигнал resultReady кидается в случае завершения запроса и содержит в response сконвертированный в QVariant json ответ от сервера или ничего в случае ошибки, код ошибки в этом случае содержится в reply->error()
Помимо этого можно скрыть обработку результата от получателя, добавив в reply функцию-обработчик результата, в этом случае результат будет можно получить при помощи вызова метода reply->result(), результат будет возращен в виде QVariant'а, поэтому его нужно будет еще дополнительно преобразовать при помощи QVariant::fromValue.
QVariantMap args;
//TODO add chat messages support and contact check
args.insert("uid", message.toId());
args.insert("message", message.body());
args.insert("title", message.subject());
return request ("messages.send", args, [](const QVariant &response) -> QVariant { return response.toInt(); });
Для того, чтобы четко обозначить тип возращаемого значения можно применить следующую шаблонную магию:
typedef ReplyBase<int> SendMessageReply;
QVariantMap args;
//TODO add chat messages support and contact check
args.insert("uid", message.toId());
args.insert("message", message.body());
args.insert("title", message.subject());
return request<SendMessageReply> ("messages.send", args, [](const QVariant &response) -> QVariant { return response.toInt(); });
В результате в слоте SendMessageReply::result() будет возращать int вместо QVariant'а.
auto reply = static_cast<Vreen::SendMessageReply*>(sender());
m_unreachedMessagesCount--;
int mid = reply->result();
В целом, все взаимодействие с API получается простым и прозрачным.
Получение и сборка
Vreen использует субмодули и поэтому самым оптимальным способом получения исходников является.
$ git clone git://github.com/gorthauer/vreen.git
$ cd vreen
$ git submodule update --init
Для сборки необходимы cmake 2.8, Qt 4.7.4, и любой компилятор с базовой поддержкой С++11 (gcc 4.4+, clang 3.0+, msvc2010+).
Сама сборка достаточно тривиальна:
$ mkdir build
$ cd build
$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr
$ make
$ make install (sudo)
Если будут возникать вопросы относительно сборки релизной или дебажной версии, то лучше просто обратитесь к документации по cmake. В качестве экспериментального варианта поддерживается сборка при помощи qbs. Существует возможность собрать библиотеку при помощи qmake', но данный способ не является официально поддерживаемым.
Использование в C++ проекте
Подключение
Для подключения к другим проектам в Vreen'е используется pkg-config, поэтому для подключения vreen'а со стандартым методом авторизации через браузер достаточно добавить в pro файл строчки.
CONFIG += link_pkgconfig
PKGCONFIG += vreen
vreenoauth
В случае систем, которые не поддерживают pkgconfig, можно или вручную добавить LIBS и INCLUDEPATH или написать find скрипт для cmake или qbs.
Желающие могут помочь мне написать prf файл для Qt.
Использование
Давайте в качестве примера напишем небольшое консольное приложение, которое будет вытаскивать все номера телефонов у списка друзей.
Для начала просто инициализируем клиента, указав ему способ подключения, идентификатор приложения, а также попросим его самостоятельно создавать окошко с разрешением для доступа из приложения к api.
auto auth = new Vreen::OAuthConnection(3220807, this); //в качестве clientId используйте собственный
auth->setConnectionOption(Vreen::Connection::ShowAuthDialog, true); //заставляет клиент самостоятельно создавать окошко авторизации.
auth->setConnectionOption(Vreen::Connection::KeepAuthData, true); //заставляет хранить токен между сессиями
setConnection(auth);
connect(this, SIGNAL(onlineStateChanged(bool)), SLOT(onOnlineChanged(bool)));
connect(roster(), SIGNAL(syncFinished(bool)), SLOT(onSynced(bool)));
После того, как клиент успешно подключится к api, будет вызван слот onOnlineChanged в котором мы запросим у ростера список друзей. При запросе можно выбирать поля, которые хочется получить. Существует несколько макросов с наиболее распространёнными вариантами полей VK_COMMON_FIELDS, VK_EXTENDED_FIELDS и VK_ALL_FIELDS для всех известных полей.
Описание полей и получаемых свойств можно прочитать здесьu.
В данном случае нас интересует всего три поля и нет необходимости напрягать сервер более тяжелыми запросами.
roster()->sync(QStringList() << QLatin1String("first_name")
<< QLatin1String("last_name")
<< QLatin1String("contacts"));
После успешного завершения синхронизации ростера просто выведем на экран результат:
qDebug() << tr("-- %1 contacts recieved").arg(roster()->buddies().count());
foreach (auto buddy, roster()->buddies()) {
QString homeNumber = buddy->property("_q_home_phone").toString();
QString mobileNumber = buddy->property("_q_mobile_phone").toString();
qDebug() << tr("name: %1, home: %2, mobile: %3").arg(buddy->name())
.arg(homeNumber.isEmpty() ? tr("unknown") : homeNumber)
.arg(mobileNumber.isEmpty() ? tr("unknown") : mobileNumber);
}
Все свойства, которые еще не реализованы штатно для контактов будут иметь префикс _q_, остальные же можно получить через getter'ы или через имена, указанные в Q_PROPERTY.
В качестве второго примера попробуем воспользоваться qml api и получим список друзей.
Импортируем в qml поддержку Vreen'а:
import com.vk.api 1.0
И создадим клиента:
Client {
id: client
connection: conn //используем в качестве подключения и авторизации известный по C++ примеру метод
}
OAuthConnection {
id: conn
Component.onCompleted: { //Не забудем установить для него те же самые свойства, что и в случае с photoview'ером
setConnectionOption(Connection.ShowAuthDialog, true);
setConnectionOption(Connection.KeepAuthData, true);
}
clientId: 3220807
displayType: OAuthConnection.Popup //из всех окошек авторизации это оказалось наиболее удобным
}
Подключаться будем просто через client.connectToHost, в появившемся окошке подтверждения будет возможность вписать логин и пароль, поэтому можно не создавать отдельные поля для ввода, а ограничимся крайне лаконичным приглашением.
Для отображения списка диалогов можно воспользоваться готовой моделью из com.vk.api 1.0:
DialogsModel {
id: dialogsModel
client: client
}
Для получения списка последних диалогов достаточно просто после подключения запросить список:
Connections {
target: client
onOnlineChanged: {
if (client.online) {
client.roster.sync();
dialogsModel.getDialogs(0, //смещение относительно последнего элемента
15, //число элементов
160 //максимальная длина сообщения
);
}
}
}
Доступные для делегата свойства модели можно подсмотреть в коде её реализации:
roles[SubjectRole] = "subject";
roles[BodyRole] = "body";
roles[FromRole] = "from";
roles[ToRole] = "to";
roles[ReadStateRole] = "unread";
roles[DirectionRole] = "incoming";
roles[DateRole] = "date";
roles[IdRole] = "mid";
roles[AttachmentRole] = "attachments";
roles[ChatIdRole] = "chatId";
С помощью использования этих полей можно получить вполне опрятный на вид список диалогов:
Аналогичным образом создадим фотоальбом:
Причем хочется заметить, что в случае создания фотоальбома мы работаем через qml напрямую с vk.api
function getAll(ownerId, count, offset) {
if (!offset)
offset = 0;
if (!count)
count = 200;
var args = {
"owner_id" : ownerId,
"offset" : offset,
"count" : count,
"extended" : 0
}
var reply = client.request("photos.getAll", args)
reply.resultReady.connect(function(response) {
var count = response.shift()
for (var index in response) {
var photo = response[index]
model.append(photo)
}
})
}
Получается очень кратко и лаконично.
Заключение
Текущая версия vreen'а — 0.9.5, то есть фактически это уже почти релиз, а это значит, что API по большей части уже не будет меняться и будет поддерживаться бинарная совместимость между версиями, а значит можно уже смело присоединяться к использованию и тестированию в реальных условиях.
На данный момент поддержка API еще очень неполная, но само написание оберток над ним максимально упрощено, так, что буду рад всем патчам с реализацией различных возможностей.
По остальным вопросам готов ответить в личку или в jabber'е, который можно найти в профиле.
Fork me with github.
Автор: Gorthauer87