We connect VK SDK for Xamarin.Forms

    In the last article, we examined the issue of connecting native SDKs from Facebook in your Xamarin.Forms applications for convenient user authorization. Today, as promised, we will consider connecting native SDKs for the social network VKontakte. The new SDK will connect to the project that we described in the last article .



    Create an application on VK


    In general, the integration process of VKontakte will strongly resemble work with Facebook, so feel free to go to the application management page .

    Click "Create application" and select "Standalone application."



    Next, go to Settings and enter data about the application. “Certificate Fingerprint” is the Key Hashes we received in a previous article.



    On this the preparatory part is completed.

    Connect VK SDK to iOS and Android projects


    A lot of ready-made bindings are available for Xamarin, however, a full-fledged VK SDK appeared recently. The library was in beta stage for some time and is now ready for use. Thanks a lot to Matthew Leibowitz!



    We connect in iOS


    We make changes to Info.plist. Expand the CFBundleURLTypesvalues ​​for VKontakte:

    CFBundleURLTypesCFBundleURLNamevk5874073CFBundleURLSchemesfb1102463466549096vk5874073

    Add new ones LSApplicationQueriesSchemes:

    vkvk-sharevkauthorize

    And also the new domain in NSAppTransportSecurity:

    vk.comNSExceptionRequiresForwardSecrecyNSIncludesSubdomainsNSExceptionAllowsInsecureHTTPLoads

    After that we make changes to 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);
            }

    This completes the initial initialization of iOS.

    We connect in Android


    But for Android, you will have to additionally redefine your class Applicationto correctly initialize the 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();
            }
        }

    Now add the application ID to strings.xml:

    5874073vk5874073


    Add some code in AndroidManifest.xmlbetween :


    And end with the extension 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
                }
            }

    Integrate with Xamarin.Forms


    By analogy with Facebook, we will create our own interface in a PCL project for working with the new SDK.

        public interface IVkService
        {
            Task Login();
            void Logout();
        }

    IOS implementation


    For iOS, the implementation will look like this:

    [assembly: Dependency(typeof(AppleVkService))]
    namespace Login.iOS
    {
        public class AppleVkService : NSObject, IVkService, IVKSdkDelegate, IVKSdkUIDelegate
        {
            readonly string[] _permissions = {
                VKPermissions.Email,
                VKPermissions.Offline
            };
            LoginResult _loginResult;
            TaskCompletionSource _completionSource;
            public AppleVkService()
            {
                VKSdk.Instance.RegisterDelegate(this);
                VKSdk.Instance.UiDelegate = this;
            }
            public Task Login()
            {
                _completionSource = new TaskCompletionSource();
                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 implementation


    Nothing unusual for Android either.

    [assembly: Dependency(typeof(AndroidVkService))]
    namespace Login.Droid
    {
        public class AndroidVkService : Java.Lang.Object, IVkService
        {
            public static AndroidVkService Instance => DependencyService.Get() as AndroidVkService;
            readonly string[] _permissions = {
                VKScope.Email,
                VKScope.Offline
            };
            TaskCompletionSource _completionSource;
            LoginResult _loginResult;
            public Task Login()
            {
                _completionSource = new TaskCompletionSource();
                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;
            }
        }
    }

    We connect in Xanarin.Forms


    All. VKontakte works!



    We remind you that to publish applications (so that anyone other than you can log in), you must perform additional steps for each social network.

    Use


    Today we learned how to authorize users using the native VKontakte SDK. If you need wider functionality for working with this social network, we recommend that you study examples of Matthew himself .

    The full project code with native SDKs for Facebook and VKontakte can be found at .

    In the next article, we will look at universal ways to authorize users through OAuth in Xamarin.Forms applications. Stay in touch, ask your questions in the comments and join the Xamarin Developers group on Telegram .

    about the author


    Vyacheslav Chernikov - Head of Development, Binwell . In the past, one of Nokia Champion and Qt Certified Specialist, currently a specialist in Xamarin and Azure platforms. He came into the mobile sphere in 2005, since 2008 he has been developing mobile applications: he started with Symbian, Maemo, Meego, Windows Mobile, then switched to iOS, Android and Windows Phone.

    You can also read Vyacheslav's articles on the blog on Medium .

    Other articles of the author:


    Xamarin Meetup: Sophisticated Interfaces in Xamarin.Forms


    If you want to chat with the Xamarin Developers community, as well as personally with Vyacheslav, a meeting on the topic “Complex interfaces in Xamarin Forms” will be held on March 9 in Moscow.

    Mitap program:

    18:00 - 18:30 Registration
    18:30 - 19:30 Vyacheslav Chernikov // Connecting RecyclerView / UICollectionView for layout of complex interfaces
    19:30 - 19:40 Coffee-break
    19:40 - 20:40 Yuri Nevalenny / / Collections and lists on Xamarin Forms, virtualization patterns and fast cells (Android, iOS, Windows)

    Participation is free, registration is required .

    Also popular now: