- PVSM.RU - https://www.pvsm.ru -
В прошлой статье мы рассмотрели вопрос с подключением нативных SDK от Facebook в ваших приложениях на Xamarin.Forms для удобной авторизации пользователей. Сегодня, как и обещали, рассмотрим подключение нативных SDK для социальной сети ВКонтакте. Новый SDK будет подключаться к проекту, который мы описывали в прошлой статье [1].

В целом, процесс интеграции ВКонтакте будет сильно напоминать работу с Facebook, так что смело заходите на страницу управления приложениями [2].
Нажимаем «Создать приложение» и выбираем «Standalone-приложение».

Далее идём в Настройки и вводим данные о приложении. «Отпечаток сертификата» это Key Hashes, полученные нами в прошлой статье.

На этом подготовительная часть завершена.
Для Xamarin доступно достаточно много готовых bindings, однако полноценный ВКонтакте SDK [3] появился совсем недавно. Библиотека какое-то время пребывала в стадии beta и сейчас готова к использованию. Большое спасибо Matthew Leibowitz!

Вносим правки в Info.plist. Расширяем CFBundleURLTypes значениями для ВКонтакте:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>vk5874073</string>
<key>CFBundleURLSchemes</key>
<array>
<string>fb1102463466549096</string>
<string>vk5874073</string>
</array>
</dict>
</array>
Добавляем новые LSApplicationQueriesSchemes:
<string>vk</string>
<string>vk-share</string>
<string>vkauthorize</string>
И также новый домен в NSAppTransportSecurity:
<key>vk.com</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
После этого вносим правки в AppDelegate.cs.
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
Xamarin.Forms.Forms.Init();
LoadApplication(new App());
Facebook.CoreKit.Profile.EnableUpdatesOnAccessTokenChange(true);
Facebook.CoreKit.ApplicationDelegate.SharedInstance.FinishedLaunching(app, options);
VKSdk.Initialize("5874073");
return base.FinishedLaunching(app, options);
}
public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
{
return VKSdk.ProcessOpenUrl(url, sourceApplication)
|| Facebook.CoreKit.ApplicationDelegate.SharedInstance.OpenUrl(application, url, sourceApplication, annotation)
|| base.OpenUrl(application, url, sourceApplication, annotation);
}
На этом первичная инициализация iOS завершена.
А вот для Android придётся дополнительно переопределить свой класс Application для корректной инициализации SDK.
[Application]
public class MainApplication : Application
{
public MainApplication(IntPtr handle, JniHandleOwnership transer)
:base(handle, transer)
{
}
public override void OnCreate()
{
base.OnCreate();
VKSdk.Initialize(this).WithPayments();
}
}
Теперь добавим ID приложения в strings.xml:
<integer name="com_vk_sdk_AppId">5874073</integer>
<string name="vk_data_theme">vk5874073</string>
Добавим немного кода в AndroidManifest.xml между <application ..> … :
<activity android:name="com.binwell.login.MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="@string/vk_data_theme" />
</intent-filter>
</activity>
И завершим расширением MainActivity:
protected override async void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
bool vkResult;
var task = VKSdk.OnActivityResultAsync(requestCode, resultCode, data, out vkResult);
if (!vkResult)
{
base.OnActivityResult(requestCode, resultCode, data);
AndroidFacebookService.Instance.OnActivityResult(requestCode, (int)resultCode, data);
return;
}
try
{
var token = await task;
// Get token
}
catch (Exception e)
{
// Handle exception
}
}
По аналогии с Facebook, мы создадим свой интерфейс в PCL-проекте для работы с новым SDK.
public interface IVkService
{
Task<LoginResult> Login();
void Logout();
}
Для iOS реализация будет выглядеть следующим образом:
[assembly: Dependency(typeof(AppleVkService))]
namespace Login.iOS
{
public class AppleVkService : NSObject, IVkService, IVKSdkDelegate, IVKSdkUIDelegate
{
readonly string[] _permissions = {
VKPermissions.Email,
VKPermissions.Offline
};
LoginResult _loginResult;
TaskCompletionSource<LoginResult> _completionSource;
public AppleVkService()
{
VKSdk.Instance.RegisterDelegate(this);
VKSdk.Instance.UiDelegate = this;
}
public Task<LoginResult> Login()
{
_completionSource = new TaskCompletionSource<LoginResult>();
VKSdk.Authorize(_permissions);
return _completionSource.Task;
}
public void Logout()
{
_loginResult = null;
_completionSource = null;
}
[Export("vkSdkTokenHasExpired:")]
public void TokenHasExpired(VKAccessToken expiredToken)
{
VKSdk.Authorize(_permissions);
}
public new void Dispose()
{
VKSdk.Instance.UnregisterDelegate(this);
VKSdk.Instance.UiDelegate = null;
SetCancelledResult();
}
public void AccessAuthorizationFinished(VKAuthorizationResult result)
{
if (result?.Token == null)
SetErrorResult(result?.Error?.LocalizedDescription ?? @"VK authorization unknown error");
else
{
_loginResult = new LoginResult
{
Token = result.Token.AccessToken,
UserId = result.Token.UserId,
Email = result.Token.Email,
ExpireAt = Utils.FromMsDateTime(result.Token.ExpiresIn),
};
Task.Run(GetUserInfo);
}
}
async Task GetUserInfo()
{
var request = VKApi.Users.Get(NSDictionary.FromObjectAndKey((NSString)@"photo_400_orig", VKApiConst.Fields));
var response = await request.ExecuteAsync();
var users = response.ParsedModel as VKUsersArray;
var account = users?.FirstObject as VKUser;
if (account != null && _loginResult != null)
{
_loginResult.FirstName = account.first_name;
_loginResult.LastName = account.last_name;
_loginResult.ImageUrl = account.photo_400_orig;
_loginResult.LoginState = LoginState.Success;
SetResult(_loginResult);
}
else
SetErrorResult(@"Unable to complete the request of user info");
}
public void UserAuthorizationFailed()
{
SetErrorResult(@"VK authorization unknown error");
}
public void ShouldPresentViewController(UIViewController controller)
{
Device.BeginInvokeOnMainThread(() => Utils.GetCurrentViewController().PresentViewController(controller, true, null));
}
public void NeedCaptchaEnter(VKError captchaError)
{
Device.BeginInvokeOnMainThread(() => VKCaptchaViewController.Create(csaptchaError).PresentIn(Utils.GetCurrentViewController()));
}
void SetCancelledResult()
{
SetResult(new LoginResult { LoginState = LoginState.Canceled });
}
void SetErrorResult(string errorString)
{
SetResult(new LoginResult { LoginState = LoginState.Failed, ErrorString = errorString });
}
void SetResult(LoginResult result)
{
_completionSource?.TrySetResult(result);
_loginResult = null;
_completionSource = null;
}
}
Для Android тоже ничего необычного.
[assembly: Dependency(typeof(AndroidVkService))]
namespace Login.Droid
{
public class AndroidVkService : Java.Lang.Object, IVkService
{
public static AndroidVkService Instance => DependencyService.Get<IVkService>() as AndroidVkService;
readonly string[] _permissions = {
VKScope.Email,
VKScope.Offline
};
TaskCompletionSource<LoginResult> _completionSource;
LoginResult _loginResult;
public Task<LoginResult> Login()
{
_completionSource = new TaskCompletionSource<LoginResult>();
VKSdk.Login(Forms.Context as Activity, _permissions);
return _completionSource.Task;
}
public void Logout()
{
_loginResult = null;
_completionSource = null;
VKSdk.Logout();
}
public void SetUserToken(VKAccessToken token)
{
_loginResult = new LoginResult
{
Email = token.Email,
Token = token.AccessToken,
UserId = token.UserId,
ExpireAt = Utils.FromMsDateTime(token.ExpiresIn)
};
Task.Run(GetUserInfo);
}
async Task GetUserInfo()
{
var request = VKApi.Users.Get(VKParameters.From(VKApiConst.Fields, @"photo_400_orig,"));
var response = await request.ExecuteAsync();
var jsonArray = response.Json.OptJSONArray(@"response");
var account = jsonArray?.GetJSONObject(0);
if (account != null && _loginResult != null)
{
_loginResult.FirstName = account.OptString(@"first_name");
_loginResult.LastName = account.OptString(@"last_name");
_loginResult.ImageUrl = account.OptString(@"photo_400_orig");
_loginResult.LoginState = LoginState.Success;
SetResult(_loginResult);
}
else
SetErrorResult(@"Unable to complete the request of user info");
}
public void SetErrorResult(string errorMessage)
{
SetResult(new LoginResult { LoginState = LoginState.Failed, ErrorString = errorMessage });
}
public void SetCanceledResult()
{
SetResult(new LoginResult { LoginState = LoginState.Canceled });
}
void SetResult(LoginResult result)
{
_completionSource?.TrySetResult(result);
_loginResult = null;
_completionSource = null;
}
}
}
Всё. ВКонтакте работает!

Напоминаем, что для публикации приложений (чтобы кто-нибудь кроме вас мог авторизоваться) необходимо выполнить дополнительные действия для каждой социальных сети.
Сегодня мы научились авторизовать пользователей, используя нативные ВКонтакте SDK. Если вам требуется более широкий функционал по работе с этой социальной сетью, то рекомендуем изучить примеры самого Matthew [4].
Полный код проекта с подключенными нативными SDK для Facebook и ВКонтакте можете найти по адресу [5].
В следующей статье мы рассмотрим универсальные способы авторизации пользователей через OAuth в приложениях Xamarin.Forms. Оставайтесь на связи, задавайте ваши вопросы в комментариях и вступайте в группу Xamarin Developers в Telegram [6].
Вячеслав Черников — руководитель отдела разработки компании Binwell [7]. В прошлом — один из Nokia Champion и Qt Certified Specialist, в настоящее время — специалист по платформам Xamarin и Azure. В сферу mobile пришел в 2005 году, с 2008 года занимается разработкой мобильных приложений: начинал с Symbian, Maemo, Meego, Windows Mobile, потом перешел на iOS, Android и Windows Phone.
Статьи Вячеслава вы также можете прочитать в блоге на Medium [8].
Если вы хотите пообщаться с сообществом Xamarin Developers, а также лично с Вячеславом, 9 марта в Москве пройдёт митап по теме «Сложные интерфейсы в Xamarin Forms».
Программа митапа:
18:00 — 18:30 Регистрация
18:30 — 19:30 Вячеслав Черников // Подключение RecyclerView/UICollectionView для вёрстки сложных интерфейсов
19:30 — 19:40 Кофе-брейк
19:40 — 20:40 Юрий Невалённый // Коллекции и списки на Xamarin Forms, паттерны виртуализации и быстрые ячейки (Android, iOS, Windows)
Участие бесплатно, регистрация обязательна [9].
Автор: Microsoft
Источник [10]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-2/248241
Ссылки в тексте:
[1] прошлой статье: https://aka.ms/habr_323296_2
[2] страницу управления приложениями: https://aka.ms/habr_323296_3
[3] ВКонтакте SDK: https://aka.ms/habr_323296_4
[4] примеры самого Matthew: https://aka.ms/habr_323296_5
[5] адресу: https://aka.ms/habr_323296_6
[6] Xamarin Developers в Telegram: https://aka.ms/habr_323296_7
[7] Binwell: https://aka.ms/habr_321454_4
[8] блоге на Medium: https://aka.ms/habr_323296_8
[9] регистрация обязательна: https://aka.ms/habr_323296_1
[10] Источник: https://habrahabr.ru/post/323296/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.