Vreen — простая и удобная библиотека для работы с vk.api

от автора


Представляю вам новую Qt библиотеку для работы с vk api, которая может пригодиться вам при создании любых настольных и мобильных приложений, взаимодействующих с vk. Проект родился из vkontakte плагина для qutIM’а и перерос в отдельную независимую библиотеку, которой теперь может пользоваться каждый.

Краткий обзор

Vreen это обёртка над vk.com api, написанная на C++11/Qt, предназначенная для быстрого и простого создания мобильных и настольных приложений, а также встраивания взаимодействия с vk.com api в уже существующие приложения. Библиотека поддерживает несколько способов авторизации и позволяет при необходимости добавлять свои. Также в vreen существует полноценная привязка к qml, что позволяет создавать приложения, не написав ни единой строчки на C++. Для уменьшения количества обязательных зависимостей все способы авторизации вынесены в отдельные статические библиотеки.

Основные возможности:

  1. Поддержка любых видов диалогов в том числе и групповых чатов.
  2. Поддержка просмотра новостных лент, стен.
  3. Работа с комментариями, в том числе добавления, лайки и репосты.
  4. Поддержка работы с вложениями.
  5. Поддержка ростера в том числе отслеживание статуса собеседников.
  6. Поддержка аудиозаписей.
  7. Возможность напрямую работать с API из qml в привычном для многих XHTTPRequest стиле.
  8. Расширяемость.
  9. Свободная 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.

ссылка на оригинал статьи http://habrahabr.ru/post/157081/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *