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.
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 46

      –3
      Круто!
        –8
        >>Для уменьшения количества обязательных зависимостей все способы авторизации вынесены в отдельные статические библиотеки.

        Возможно паранойя, но где гарантия что в один прекрасный момент эта статическая библиотека не отправит всю прошедшею через неё информацию куда то?
          +9
          Наверное в том, что ее код представлен вот здесь и имеет объем пару сотен строчек кода?
            –3
            Ну не пара сотен строчек. Там в OAuthConnection::connectToHost есть параметры которые в этом файле не описаны, то есть надо искать где лежит файл в котором они описаны. Потом искать не используются ли эти параметры где то еще. То есть наличие исходников конечно аргумент за, но проверить это все равно достаточно сложно.

            Хочу просто чтобы быть понятным, я не пытаюсь сказать что эта библиотека — способ развода на пароль вконтакте. Но тут уже просто есть рефлекторное недоверие ко всему что просит пароль от вконтакте и если он где то запрашивается то почему это безопасно стоит отдельно и плотно расписывать.
              +7
              Вы не поверите, но дока на эти самые параметры есть на vk.com, а в коде где параметры используются можно посмотреть через IDE.
                –3
                Речь шла о «d->login» и «d->password» и о том что в этом файле класс d не описан. Описание этого класса надо искать на vk.com?

                Через IDE — это вариант. Но динамика хорошая, пару сообщение назад было достаточно одного файла из пары сотен строчек, а сейчас уже надо по всему проекту пройтись в поисках.
                  +2
                  «Класс d» — это класс OAuthConnectionPrivate и он там полностью описан.
                    –5
                    Я понимаю что он где то описан. Речь шла о том что одного файла из пары сотен строчек не хватит что бы понять что пароль и логин ни куда не уходят.
                      +1
                      Попробую доступнее: класс OAuthConnectionPrivate полностью определён в том файле, на который дана ссылка.
                    +4
                    «Иногда лучше жевать, чем говорить» ©
                      0
                      Да уж, я бы на его месте извинился за то, что народ в заблуждение пытался ввести!
                  +2
                  Это что за ололо комментарий? Мне хватило нескольких минут, чтобы убедиться в чистоте библиотеки.

                  А фраза «То есть наличие исходников конечно аргумент за» доставляет до глубины души. А без исходников ничего не надо было бы проверять?

                  Вы смотрите, а то ведь есть еще библиотеки boost, poco, фреймворк Qt и многое другое, жаждущее угнать Ваш пароль ВКонтакте. Ведь программисты-то все лошки, их проще всего надурить выложенным исходным кодом, из тысячи скачавших библиотеку ведь никто в код не посмотрит, в саппорт на проблему не напишет.
                    –4
                    в чем ололо заключается?

                    >>Мне хватило нескольких минут, чтобы убедиться в чистоте библиотеки.
                    как? расскажите методику как вы незнакомую программу за пару минут просмотрели всю, если даже сам автор согласился что надо искать параметры через IDE?

                    >>boost, poco, фреймворк Qt
                    Они у меня не просят пароля от вконтакте или учетной записи Windows. К тому же это крупные проекты, которые уже исследованы на наличие уязвимостей.

                    >>А фраза «То есть наличие исходников конечно аргумент за» доставляет до глубины души.
                    Чем? Вы считаете что наличие исходников — это аргумент против?
                      +5
                      как? расскажите методику как вы незнакомую программу за пару минут просмотрели всю, если даже сам автор согласился что надо искать параметры через IDE?

                      Открывается исходный код и смотрится. Там 400 строк кода вместе с хедером, чтобы их просмотреть на чистоту достаточно нескольких минут.

                      Вот код, который Вас так беспокоит:
                      void OAuthConnection::connectToHost(const QString &login, const QString &password)
                      {
                          Q_D(OAuthConnection);
                          if (d->options.value(Connection::KeepAuthData).toBool())
                              d->loadAuthData();
                      
                          if (d->login != login || d->password != password) {
                              if (!(d->login.isNull() || d->password.isNull()))
                                  d->clear();
                              d->login = login;
                              d->password = password;
                          }
                          if (!d->uid || d->accessToken.isNull()
                                  || (d->expiresIn && d->expiresIn < QDateTime::currentDateTime().toTime_t())) {
                              d->requestToken();
                              d->setConnectionState(Client::StateConnecting);
                          } else
                              d->setConnectionState(Client::StateOnline);
                      }


                      d — это экземпляр класса OAuthConnectionPrivate, который полностью описан и реализован в oauthconnection.cpp (т.е. входит в те самые 400 строк кода).
                      Я реально не вижу здесь проблемы для любого программиста.

                      Автор ни с чем не соглашался, он просто посоветовал использовать IDE для удобного перемещения по вызываемым функциям, раз в текстовом редакторе не получается. Там все лежит в двух файлах, один из которых хедер.

                      К тому же это крупные проекты, которые уже исследованы на наличие уязвимостей.

                      5 минут на главной хабра тоже обеспечивает проект исследованием на наличие уязвимостей.

                      Чем? Вы считаете что наличие исходников — это аргумент против?

                      Это вырванная из контекста фраза. Полностью она звучала как-то так: «сложно разобраться, где какие параметры используются. Исходный код, конечно, дали, но сложно». А как еще-то? Автор должен был сказать: «зуб даю»? Или патриарху кадилом помахать?

                      Просто, видимо, я таких моментов не понимаю: автор выкладывает [i]исходный код[/i] отличного качества (т.е. имена переменных говорящие, что, куда и откуда явно указано и т.д.), а ему совсем ленивые хабролюди говорят: «а не спиздишь ли ты пароли, часом?», вместо того, чтобы за пару минут убедиться самому — нет, не спиздит.
                +1
                А что мешает shared библиотеке поступить точно также? Это же всего лишь способ компоновки программы.
                И как заметил автор ниже, код открыт же.
                  –4
                  Если dll скачивается отдельно то (на сколько я знаю) из какого исходного текста она скомпилирована сказать сложно. Или её в виде апдейта можно заменить на другую.
                  Люди я думаю при желании и много чего более хитрого смогут придумать.
                +2
                Кстати, напоминаю, что есть еще библиотека для работы с XMPP под названием Jreen
                  0
                  Собственно, в Кутиме следует ожидать нативной поддержки VK через API, угу?
                  EDIT: ушёл читать под кат сразу, не заметил ответа на вопрос в шапке. Тем не менее, в базовую поставку включать думаете?
                    0
                    Давно уже блин она там!
                      0
                      Ставил на Wheezy из родного репозитория 0.3-шку. Не узрел.
                      То ли я в логике работы 0.3 ничего не понимаю, то ли её там нет.
                        0
                        Не слежу за пакетами для Дебиана, там может быть 0.3.1, которая еще не на vreen'е. На vreen только ветка в мастере переведена
                    0
                    Более того, есть библиотека Ireen, которая реализует протокол ICQ.
                    +1
                    Красиво и емко написанная, очень удобная библиотека.
                    Попробовал, понравилось. Рекомендую :)

                    Gorthauer87, спасибо!
                      +1
                      Отлично! Давно искал подобную библиотеку под Qt! Хм, а если запустить под Necessitas…
                        0
                        Попробуйте. Я честно сказать не пробовал, но должна заработать, вроде бы в cmake есть поддержка Necessitas. В Necessitas же есть QtWebkit? Если нету, то тогда придется колдовать с вызовом нативного браузера и доставанием у него каким-то образом токена, при условии, что в страничке авторизации можно редиректить после авторизации только на vk.com.
                        +5
                        Узнал автора по первым двум строчкам поста.
                        Вы один из немногих людей, которые пишут о Qt на хабре.
                          +1
                          Мне кажется меня проще по картинке распознать, она всегда будет справа от заголовка))
                          0
                          Добавил пример, который показывает список аудиозаписей текущего пользователя.
                            0
                            Спасибо, интересная штука! Все думал, чего бы такого написать на досуге на QML. Теперь появилась идея :)
                              0
                              Потом хотелось бы на результаты посмотреть :)
                                0
                                Обязательно поделюсь, вдруг кому пригодится :)
                              0
                              А с Qt 4.8 будет работать?

                              У меня процесс с cmake начался с сего:
                              CMake Error: Internal CMake error, TryCompile configure of cmake failed -- Looking for Q_WS_MAC - not found -- Found OpenGL: opengl32 -- Found Qt4: D:/Qt/bin/qmake.exe (found version "4.8.1") CMake Error at CMakeLists.txt:17 (include): include could not find load file: CommonUtils -- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE) -- Using internal copy of k8json CMake Error at src/3rdparty/CMakeLists.txt:13 (update_compiler_flags): Unknown CMake command "update_compiler_flags". -- Configuring incomplete, errors occurred!
                                0
                                Будет конечно. А здесь какой-то cmake internal error. Какая версия cmake и какая версия остальных компонент?
                                  0
                                  Qt у меня 4.8.1. Cmake скачал последний, какой нашел — 2.8.10.1
                                    0
                                    А что за компилятор? Очень похоже на то, что он почему-то не работает корректно. И сейчас последняя версия Qt это 4.8.3. Кстати, в случае с Qt из состава Qt SDK под win, то он не годится. Там gcc 4.4, а он хоть и удовлетворяет минимальному требованию для vreen'а с точки зрения фич, но не с точки зрения багов. Есть несколько багов в компиляторе из Qt SDK, из за которых vreen просто не собирается.
                                    Пути решения здесь два:
                                    1. Поставить mingw-gcc-4.7 и собрать им Qt
                                    2. Поставить Windows 7.1 SDK и собирать с помощью msvc2010
                                      0
                                      Так, вроде начало собираться.
                                      Правда теперь вот:
                                      .\json.cpp(26) : fatal error C1083: Cannot open include file: 'k8json/k8json.h': No such file or directory

                                      и
                                      .\audio.cpp(26) : fatal error C1083: Cannot open include file: 'client.h': No su ch file or directory
                                        0
                                        А компилятор MSVC 2010. Сверху результат nmake. cmake все тоже
                                          0
                                          git submodule update --init точно не забывали? По симптомам похоже на то, что k8json не скачался
                                            0
                                            Прошу прощения за нубство, у меня нет git, я пока пользователь svn, но я скачал Ваш источник архивом с сайта, есть разница в полученных данных разве? Я такого не предполагал.
                                              0
                                              Архив там автогенерированный и он не включает субмодулей. Поэтому в нем не хватает важных файлов. Поэтому же надо тянуть именно гитом и именно так, как описано в статье.
                                                0
                                                Установил git ради такого дела. Все собралось ок, примеры запустились.
                                                Проблема одна осталась, не хочет в студии собираться, пробовал в .pro файле указывать
                                                CONFIG += link_pkgconfig PKGCONFIG += vreen \ vreenoauth
                                                Но он не знает, что такое PKGCONFIG :(
                                                P.S. Попробовал вручную указать, ошибки линковки повылезали. Вечером попробую решить еще разок.
                                                  0
                                                  pkg-config это некая утилита, которая подставляет правильные флаги компилятору для подключения библиотек, к сожалению со студией она не совместима.
                                                  Да, при сборке cmake'ом надо еще указать префикс установки в Qt директорию -DCMAKE_INSTALL_PREFIX=%QTDIR% если это делать qt vs command prompt

                                                  А потом просто добавляем в переменную
                                                  LIBS=%QTDIR%/lib;%LIBS%
                                                  INCLUDEPATH=%QTDIR/include%;$INCLUDEPATH

                                                  ну и в pro файле по идеи тогда достаточно просто будет прописать
                                                  LIBS+= -lvreen
                                                  но тут я не уверен на все сто.
                                  0
                                  1. Круто, в избранное, однозначно
                                  2. Откуда Кирга знаете?)
                                    0
                                    Я уже сто лет как его знаю)
                                  • UFO just landed and posted this here
                                      0
                                      >Свободная LGPL лицензия, позволяющая использовать библиотеку с проприетарными приложениям.

                                    Only users with full accounts can post comments. Log in, please.