Итак, как и говорил ранее, сегодня я решил вытащить из черновиков блога и немного доработать статью, посвященную работе с API социальной Сети «ВКонтакте«. В принципе, REST Client Library, о которой я уже рассказывал не раз, вполне сгодится для работы с любой социальной сетью или онлайн сервисом, которые предоставляют нам в распоряжение API. Но «ВКонтакте», всё же из всех мне известных социальных сетей (за исключением, наверное, Twitter) является самой популярной в России, поэтому с ней и попробуем поработать, используя в работе Delphi XE6. Ну, а чтобы было ещё более занимательно, попробуем написать небольшое приложение для Android. Кому потребуется приложение для Windows и VCL, думаю легко разберется в том, какие модули следует подключить в uses, а какие наоборот — убрать.
1. Создаем свое приложение «ВКонтакте» и пробуем авторизовать пользователя.
Для начала работы с API «ВКонтакте» необходимо создать новое приложение и получить необходимые данные для авторизации пользователей. Для этого заходим на страницу разработчиков и жмем вверху страницы кнопку «Создать приложение«:
Далее придумываем нашему приложению название и задаем тип приложения — «Standalone-приложение«:
Жмем кнопку «Подключить приложение» после чего вам предложат подтвердить свое действие, выслав на мобильный телефон проверочный код. После подтверждения Вам станет доступно изменение настроек приложения:
Переходим на вкладку «Настройки» и запоминаем ID приложения и Защищенный ключ:
Теперь можно переходить к Delphi XE6 и попробовать реализовать авторизацию пользователя.
Запускаем Delphi XE6, создаем новый проект для мобильных устройств и на главную форму бросаем компоненты, покзанные на рисунке ниже:
Сейчас нам нужны будут следующие компоненты: TButton, TRESTClient, TRESTRequest, TRESTResponse и TOAuth2Authenticator. Клик по кнопке TButton будет вызывать процесс авторизации пользователя. Для начала, напишем процедуру авторизации пользователя.
Все необходимые данные для авторизации я определил как константы:
const cAppID = '427ххххх'; cAppKey = '94ххххххххххххххххххххххp'; cEndPoint = 'https://oauth.vk.com/authorize';
Теперь необходимо вызвать форму для авторизации пользователя «ВКонтакте» и получить Access Token. Как это делать я достаточно подробно рассказывал в самоё первой статье по REST Client Library. Подключаем в uses модуль REST.Authenticator.OAuth.WebForm.FMX и определяем следующую переменную:
type TForm1 = class(TForm) [...] private WebForm: Tfrm_OAuthWebForm; public { Public declarations } end;
Напомню, что Tfrm_OAuthWebForm — это форма, на которой расположен компонент TWebBrowser с помощью которого пользователь заходит на сайт, чтобы ввести свои логин/пароль и получить доступ для приложения к каким-либо данным своего аккаунта. Соответственно нам, как разработчикам, эта форма необходима, как минимум, для того, чтобы «отловить» редирект на специальный URL, который будет содержать необходимый нам Access Token. Для управления редиректами у Tfrm_OAuthWebForm определено сразу два события:
type TOAuth2WebFormRedirectEvent = procedure(const AURL: string; var DoCloseWebView : boolean) of object; property OnBeforeRedirect: TOAuth2WebFormRedirectEvent read FOnBeforeRedirect write FOnBeforeRedirect; property OnAfterRedirect: TOAuth2WebFormRedirectEvent read FOnAfterRedirect write FOnAfterRedirect;
Нам необходим обработчик события OnAfterRedirect. Напишем его:
type TForm1 = class(TForm) [...] private WebForm: Tfrm_OAuthWebForm; procedure AfterRedirect(const AURL: string; var DoCloseWebView : boolean); [...] public { Public declarations } end; procedure TForm1.AfterRedirect(const AURL: string; var DoCloseWebView: boolean); var i:integer; Str: string; Params: TStringList; begin i:=pos('#access_token=',AURL); if (i>0) and (OAuth2Authenticator1.AccessToken=EmptyStr) then begin Str:=AURL; Delete(Str,1,i); Params:=TStringList.Create; try Params.Delimiter:='&'; Params.DelimitedText:=Str; OAuth2Authenticator1.AccessToken:=Params.Values['access_token']; OAuth2Authenticator1.AccessTokenExpiry:=IncSecond(Now,StrToInt(Params.Values['expires_in'])); finally Params.Free; end; WebForm.Close; end; end;
Таким образом, после редиректа мы проверяем есть ли в URL подстрока #access_token= и, если такая строка имеется, то вытаскиваем из URL данные по Access Token и время его жизни — значение параметра expires_in.
Теперь нам необходимо создать форму, определить обработчик OnAfterRedirect и в нужный момент показать эту форму пользователю.
Что касается создания/уничтожения объекта формы, то это можно сделать где вам удобно. Для примера, я создаю форму авторизации в OnCreate главной формы, а уничтожаю, соответственно, в OnDestroy:
procedure TForm1.FormCreate(Sender: TObject); begin WebForm:=Tfrm_OAuthWebForm.Create(nil); WebForm.OnAfterRedirect:=AfterRedirect; end; procedure TForm1.FormDestroy(Sender: TObject); begin WebForm.Free; end;
Процедуру авторизации пользователя напишем следующим образом:
type TForm1 = class(TForm) [...] private WebForm: Tfrm_OAuthWebForm; procedure AfterRedirect(const AURL: string; var DoCloseWebView : boolean); procedure Auth; public { Public declarations } end; procedure TForm1.Auth; begin OAuth2Authenticator1.AccessToken:=EmptyStr; OAuth2Authenticator1.ClientID:=cAppID; OAuth2Authenticator1.ClientSecret:=cAppKey; OAuth2Authenticator1.ResponseType:=TOAuth2ResponseType.rtTOKEN; OAuth2Authenticator1.AuthorizationEndpoint:=cEndPoint; WebForm.ShowWithURL(OAuth2Authenticator1.AuthorizationRequestURI); end;
Здесь мы, опять же, используем компонент TOAuth2Authenticator — записываем в него данные нашего приложения (ID и секретный ключ), а также получаем URL, по которому необходимо перейти пользователю для авторизации.
Здесь стоит особое внимание обратить на следующую строку:
OAuth2Authenticator1.ResponseType:=TOAuth2ResponseType.rtTOKEN;
Здесь мы указываем какой тип ответа от сервера нам требуется и, в соответствии с этим параметром компонент будет формировать результат функции AuthorizationRequestURI. Если поле ResponseType оставить со значением по умолчанию (TOAuth2ResponseType.rtCode), то наш обработчик OnAfterRedirect окажется бесполезным, а вместо ключа доступа к API мы всегда будем получать на экране сообщение от VK вида:
Теперь вызываем метод Auth в обработчике OnClick кнопки и можем проверить наше приложение на каком-нибудь Android-устройстве:
procedure TForm1.Button1Click(Sender: TObject); begin Auth; end;
Вот так будет выглядеть окно авторизации пользователя в запущенном приложении:
Сразу после авторизации окно закроется и можно будет использовать API «ВКонтакте», что называется, на полную катушку.
2. Использование API «ВКонтакте»
Конечно, сегодня мы весь API «ВКонтакте» не переберем. Да и цели такой у меня не стоит. А вот некоторые моменты по работе с методами API рассмотрим.
С тем, как вызывать методы API вы можете ознакомиться на странице: http://vk.com/dev/api_requests.
Список всех доступных методов предоставлен на странице: http://vk.com/dev/methods
Вначале попробуем использовать какой-нибудь простенький метод. Например, в API есть довольно интересный метод — setOffline, который помечает текущего пользователя как offline. Метод доступен только приложениям с типом Standalone. Для вызова этого и других методов API и получения ответов сервера у нас на имеются следующие компоненты:
- RESTClient1: TRESTClient;
- RESTRequest1: TRESTRequest;
- RESTResponse1: TRESTResponse;
Чтобы выполнять запросы к API определим у компонента RESTClient1 свойство BaseURL — для «ВКонтакте» это свойство должно содержать следующий URL — https://api.vk.com/method.
У компонента RESTRequest1 необходимо выставить следующие значения свойств:
- Client = RESTClient1
- Response = RESTResponse1
Теперь попробуем вызвать метод account.setOffline API ВКонтакте и вывести результат в ListBox. Добавим на форму приложения ещё одну кнопку и напишем для неё такой обработчик OnClick:
procedure TForm1.Button2Click(Sender: TObject); begin RESTRequest1.Resource:='account.setOffline'; RESTRequest1.Method:=TRESTRequestMethod.rmGET; RESTRequest1.Execute; ListBox1.Items.Add(RESTResponse1.Content) end;
Теперь можно запустить приложение и проверить ответ сервера при вызове метода setOffline:
Соответствующим образом можно вызывать и другие методы API. Если же нам необходимо разобрать ответ сервера, то для этого можно воспользоваться свойством JSONValue компонента TRESTResponse.
Отмечусь :). Сразу говорю, про REST Client Library ничего не знаю, может оно и автоматом настраивается, тогда практически весь коммент можно отнести к флуду :))). Все нижесказанное именно для Standalone, ибо с другим не работал. основной список параметров для получения токена client_id=APP_ID&scope=PERMISSIONS& redirect_uri=REDIRECT_URI&display=DISPLAY&v=API_VERSION&response_type=token «пробегусь» по основным значениям (которых не заметил в статье) REDIRECT_URI — надо задать https://oauth.vk.com/blank.html PERMISSIONS — если хочется не только читать, но и постить (а иногда и для «читать»), обязательно надо настраивать права доступа. Естественно не усердствовать, чтоб пользователя в панику не вводить. API_VERSION — указывать обязательно. Они в последнее время частенько играются и обновляют версию. Можно… Подробнее »
Приветствую, Mifody! Коммент пусть висит — пригодится страждущим :) Что касается авторизации, то, в принципе, REST Client Library сама прекрасно понимает большинство способов авторизации по OAuth1 и OAuth2 и ничего сверхсложного городить не приходится. Единственный «глюк» обнаружился при работе с API Dropbox — почему-то в проге для Android (FMX) авторизация проходит нормально, а когда пишу Desktop-версию использованием VCL — нифига не получается, т.к. при авторизации данные дополнительно шлются на URL, которой не предусмотрен стандартом OAuth и авторизация прерывается на последнем шаге — вылетает 404 еггог. И тут то ли я чего-то недопонимаю, то ли VCL и FMX версии библиотеки работают… Подробнее »
не знаю не знаю, меня индя практически наглухо отучила от «умных» библиотек :))).
кстати, если боль/мень серьезно не писал еще под VK, очень рекомендую чекать на ошибки результат ;), особенно на #6, «превышение частоты запросов». Ибо у всех, кто под контакт начинает писать — она частенько выскакивает :).
Хотяяяя, чему я «грешный» тебя учу :))))
Привет. Как то странно, подуль REST.Authenticator.OAuth.WebForm.FMX не находит если активировать android SDK, если же поставить REST.Authenticator.OAuth.WebForm.FMX или REST.Authenticator.OAuth.WebForm.win при компиляции в win32 или под iOS, то все в норме. Не подскажете как решить проблему?
Артем, привет. Нет не подскажу пока, т.к. сам на эту фигню напоролся :)
Hello,
Is it possible to download this sample code?
Maybe can you send it to me through email?
Many Thanks
Ioannis
А как после авторизации на сайте, выйти из него?
Владимир Тютимов, лень искать на сайте, но, по-моему в API был специальный метод logout
Да, спасибо, уже разобрался.
Но вот появилась другая проблема. Отправляю сообщение (берется из Memo), но на сайт приходить абракадабра. Дело понятно в кодировке. Смотрю кодировку страницы Вк. Получаем windows-1251. Выставляю в компоненте RESTRequest вместо UTF-8 windows-1251. И ничего не вышло из этого успешного. Как правильно настроить кодировку?
Кодировка сайта и кодировка текста в запросах к API может и не совпадать. Так что надеяться на кодировку странички ВК не стоит. Что касается отправки текста, то перед записью в RESTRequest кодировку текста из Memo надо преобразовывать, т.к. в Delphi string = UnicodeString, а не UTF8String. Что касается того как перекодировть строки, то могу посоветовать воспользоваться классом TEncoding про который я писал здесь.
Спасибо, прочитаю.
Я так и не разобрался, как мне перевести текст из Мемо и отправить его в ВК. Ведь я не могу в параметр запроса включить массив байт, а из массива конвертировать могу только обратно в UnicodeString. Очень сильно прошу помочь.
Самый простой вариант:
var S: string;
begin
S:=AnsiToUTF8(Memo1.Lines.Text);
//Всё, что есть в переменной S записываем в параметры запроса
end;
Если не вдаваться в подробности с массивами байтов и чуть-чуть поговнокодить, то можно и так:
var StrStream: TStringStream;
begin
StrStream:=TStringStream.Create(Memo1.Lines.Text, TEncoding.UTF8);
try
//StrStream.DataString пишем в параметры запроса к ВК
finally
StrStream.Free;
end;
end;
Как-то так.
Оба варианта приводят к одному и тому же. В сообщении приходит абракадабра. А может настройки RESTClient и RESTRequest нужно поменять. У них ведь есть свойства: AcceptCharset, FallbackCharsetEncoding.
У меня установлены следующие параметры:
для RESTClient: AcceptCharset: windows-1251, *;q=0.8, FallbackCharsetEncoding: UTF-8
для RESTRequest: windows-1251, *;q=0.8
Владимир Тютимов, так у вас в ответе от сервера абракадабра? Или всё-таки при запросе на сервер появляется абракадабра? В предыдущем примере показано как преобразовывать кодировку в запросах к серверу. Если надо преобразовать кодировку ответа сервера ну воспользуйтесь обратной функцией — UTF8ToAnsi. И всё-таки посмотрите в документации к API VK с какой кодировкой работает сервер.
Мне нужно отправить сообщение из программы в ВК. Я отправляю. Когда заходишь через браузер в ВК сообщение показывается абракадаброй. Перепробовал разные варианты перекодировки все равно одно и тоже. Английские буквы нормально доходят.
Специально проверил свои пример из этой статьи. Нормально сообщения приходят…даже и перекодировать ничего не надо. Как отправлял сообщения рассказал тут. В той же статье на всякий случай и исходник приложения выложил — может пригодиться
Огромное спасибо!
Не за что. Надеюсь, что помог :)
[…] заметка по мотивам обсуждения предыдущей статьи на тему использования API ВКонтакте в Delphi. Чтобы […]
[…] я уже писал неоднократно и по-разному — кратко, подробно, подробно и с картинками, но, как показывает мой […]
[…] дам ссылку на статью где про это рассказывается — вот она. Отмечу только, […]
Уважаемый, Vlad, не могли бы прислать выложить проект целиком?
К сожалению нет, т.к. это только часть уже проданного проекта. Задавайте вопросы, что вам не понятно — попробую ответить
Я новичок в Delphi у меня всё рушится на строке
» if (i>0) and (OAuth2Authenticator1.AccessToken=EmptyStr) then»
Я так понимаю, что ругается он на знак амперсанда. Я удалил условие (i>0) и следующая ошибка у меня вылезла на строке:
«Params.Delimiter:=’&’;»
Как бы мне избавиться от этой проблемы?
Мньдя, без обид, но уж слишком «новичек» чтоб в такое лезть.
1. амперсанды лезут в HTML где есть спец символы. Посмотрите, у Вас ведь заменилось слово с авмерсандом на знак «меньше»
2. что за ошибка в строке «Params.Delimeder = …»?
чес слова, дальше будет хуже, «слизать» под чистую код не получится :). Даже еслиб Vlad дал все сырцы. В API еще есть маленькй «вагончик» тонкостей ;)
Mifody, это точно «вагончик» там не слабый :)
Да нет, никто не говорит про слизать. Просто есть конкретная задача, которую интересно делать. Просто, взяв, этот код, я начал его компилировать и у меня полезли ошибки там где есть знак амперсанда. В этом и непонимание, как у Влада всё собирается, а у меня нет.
kidrock — ответе на один вопрос «а должен ли быть этот апостроф?»
чес слово, тяжко Вам будет
кстати, посмотрите свое сообщение выше после строки «Я новичок в Delphi у меня всё рушится на строке». И сравните — то же самое у Вас в делфях или нет?
Пытаюсь сделать такое под Windows в FM но при запуске WebForm в ней нечего нет кроме кнопки Close. Как исправить?
Что означает «if (i>0)»? Делфи ругается…
Помогите пожалуйста, есть код
curl -X GET
-H ‘application-id : 42BB8529-901B-C64E-FF8E-782D215D9000’
-H ‘secret-key : CAB59AE0-D1CD-0F1B-FF14-CC8B18866D00’
http://api.backendless.com/v1/data/ChatUser
Как правильно написать запрос REST и получит ответ любая помощь.
Спасибо
Спасибо за статью! Но вот как после авторизации на сайте, выйти из него? Так и не разобрался.
Что значит «выйти»? Если снести сессию на сервере (если оно там конечно вообще храниться) — то имитация Logout браузера.
Если просто чтоб при следующем запросе попросило пароль — запрос без куков.
З.Ы. Лично мне, ни разу не понадобилось «выйти» из авторизации через Logout
Да как раз и нужен запрос без куков. Но как сделать используя WebBrowser? Уже мозг сломал.
не знаю как на счёт куков, но когда мне надо было сделать так, чтобы пользователь авторизовался в одном и том же сервисе несколько раз, например, в Яндекс.Диске, если у него несколько аккаунтов, то я просто вычищал кэш браузера вот этой процедурой: procedure DeleteIECache; var lpEntryInfo: PInternetCacheEntryInfo; hCacheDir: LongWord; dwEntrySize: LongWord; begin dwEntrySize := 0; FindFirstUrlCacheEntry(nil, TInternetCacheEntryInfo(nil^), dwEntrySize); GetMem(lpEntryInfo, dwEntrySize); if dwEntrySize > 0 then lpEntryInfo^.dwStructSize := dwEntrySize; hCacheDir := FindFirstUrlCacheEntry(nil, lpEntryInfo^, dwEntrySize); if hCacheDir 0 then begin repeat DeleteUrlCacheEntry(lpEntryInfo^.lpszSourceUrlName); FreeMem(lpEntryInfo, dwEntrySize); dwEntrySize := 0; FindNextUrlCacheEntry(hCacheDir, TInternetCacheEntryInfo(nil^), dwEntrySize); GetMem(lpEntryInfo, dwEntrySize); if dwEntrySize > 0 then lpEntryInfo^.dwStructSize := dwEntrySize; until not FindNextUrlCacheEntry(hCacheDir,… Подробнее »
Спасибо за вариант. Я делал тоже самое только вручную. Теперь автоматизирую
При сборке ругается на эти строки:
property OnBeforeRedirect: TOAuth2WebFormRedirectEvent read FOnBeforeRedirect write FOnBeforeRedirect;
property OnAfterRedirect: TOAuth2WebFormRedirectEvent read FOnAfterRedirect write FOnAfterRedirect;
Можете помочь?
Надо в Uses модули подключить: REST.Authenticator.OAuth.WebForm.FMX или REST.Authenticator.OAuth.WebForm.win
Автор, я делал как вы только под пк а не под андроид и вылазит куча ошибок. Можно с вами как то связаться что бы в ЛС?