Социальные сети, и особенно Facebook, уже давно используются в мобильных приложениях. Сегодня мы рассмотрим, как подключить нативные Facebook SDK к проекту на базе Xamarin.Forms (iOS и Android) для удобной авторизации пользователей и получения о них базовой информации. Вы также легко сможете расширить описанные в статье методы для того, чтобы реализовать полноценное взаимодействие с этим замечательным сервисом. Тема простая и понятная, поэтому без теорий и прелюдий перейдем сразу к практике.
Для тех, кто впервые создает своё приложение в Facebook, мы кратко расскажем о том, как это делается.
Сам по себе процесс это довольно простой и потребует от вас следующих данных:
Для Android ещё потребуются Key Hashes, которые можно получить командой:
Windows:
macOS:
Вместо
На выходе мы и получим нужные
Теперь заходим на developers.facebook.com и создаём новое приложение. Отдельно для iOS и Android. При создании приложения мы можем использовать режим с подсказками (Quick Start), где дополнительно описано как настроить проект. Из этого руководства нам и потребуются примеры кода.
Для начала необходимо установить пакеты Facebook SDK от Xamarin для iOS и Android из Nuget:
Обратите внимание, что с Xamarin.Forms 2.3 на текущий момент совместима только версия Xamarin.Facebook.Android 4.11.0.1. Версия Xamarin.Facebook.iOS ограничений по совместимости не имеет.
Для начала нам необходимо прописать специальные значения в файле
Где,
Далее вносим небольшие доработки в
На этом первичная инициализация Facebook SDK завершена.
По аналогии с Android, нам будет необходимо внести правки в файл
И немного кода в
На этом предварительная подготовка завершена и мы можем переходить к использованию Facebook SDK в нашем приложении.
Использовать Facebook SDK мы будем через механизм
Одной из целей подключения социальных сетей является возможность простого и удобного получения пользовательских данных, поэтому нам потребуется дополнительный запрос для получения email, который Facebook не отдает по умолчанию. Данные запросы будет необходимо реализовать отдельно для каждой платформы.
Для Android реализация интерфейса выглядит следующим образом:
Дополнительно потребуется добавить обработчик в
Делаем реализацию интерфейса для Facebook iOS SDK.
Для доступа к созданным реализациям достаточно вставить следующий обработчик события
На этом кодирование завершено!
Итак, волнительный момент. Делаем сборку, запускаем и… легко авторизуемся с помощью нативных SDK.
Полный код проекта с пошаговыми изменениями расположен в репозитории на Bitbucket.
Итак, сегодня мы подключили нативные Facebook SDK к приложению на Xamarin.Forms. Уже работает авторизация и получение базовой информации о пользователе, но при желании вы можете легко расширить набор методов для доступа ко всем возможностям Facebook SDK. В следующий раз мы возьмем задачку поинтересней и подключим нативные ВКонтакте SDK.
Оставайтесь на связи, задавайте ваши вопросы в комментариях и вступайте в группу Xamarin Developers в Telegram!
Вячеслав Черников — руководитель отдела разработки компании Binwell. В прошлом — один из Nokia Champion и Qt Certified Specialist, в настоящее время — специалист по платформам Xamarin и Azure. В сферу mobile пришел в 2005 году, с 2008 года занимается разработкой мобильных приложений: начинал с Symbian, Maemo, Meego, Windows Mobile, потом перешел на iOS, Android и Windows Phone.
1. Быстрое создание MVP (minimum viable product) на базе Microsoft Azure и Xamarin.Forms.
2. Готовим Xamarin.Forms: настройка окружения и первые шаги.
3. Повышаем эффективность работы в Xamarin.Forms.
4. Работаем с состояниями экранов в Xamarin.Forms.
5. Удобный REST для Xamarin-приложений.
Создаем приложение в Facebook
Для тех, кто впервые создает своё приложение в Facebook, мы кратко расскажем о том, как это делается.
Сам по себе процесс это довольно простой и потребует от вас следующих данных:
- Package Name для Android-проекта (например,
com.binwell.login
) - Bundle Identifier для iOS-проекта (например,
com.binwell.login
)
Для Android ещё потребуются Key Hashes, которые можно получить командой:
Windows:
keytool -exportcert -alias androiddebugkey -storepass android -keystore C:\Users\[USERNAME]\AppData\Local\Xamarin\Mono for Android\debug.keystore | openssl sha1 -binary | openssl base64
macOS:
keytool -exportcert -alias androiddebugkey -storepass android -keystore /Users/[USERNAME]/.local/share/Xamarin/Mono for Android/debug.keystore | openssl sha1 -binary | openssl base64
Вместо
[USERNAME]
необходимо подставить ваше имя пользователя в системе. Плюс можно прописать путь до openssl
, если путь до него не указан в PATH
. Скачать openssl
для Windows можно здесь.На выходе мы и получим нужные
Key Hashes
следующего вида: kGP2WMxohvxm/NiwR7H+Eb3/8qw=
Теперь заходим на developers.facebook.com и создаём новое приложение. Отдельно для iOS и Android. При создании приложения мы можем использовать режим с подсказками (Quick Start), где дополнительно описано как настроить проект. Из этого руководства нам и потребуются примеры кода.
Подключаем Facebook SDK к проектам iOS и Android
Для начала необходимо установить пакеты Facebook SDK от Xamarin для iOS и Android из Nuget:
Обратите внимание, что с Xamarin.Forms 2.3 на текущий момент совместима только версия Xamarin.Facebook.Android 4.11.0.1. Версия Xamarin.Facebook.iOS ограничений по совместимости не имеет.
Подключаем в Android
Для начала нам необходимо прописать специальные значения в файле
Resources/values/strings.xml
:<string name="facebook_app_id">1102463466549096</string>
<string name="fb_login_protocol_scheme">fb1102463466549096</string>
Где,
1102463466549096
это ваш App ID из настроек приложения Facebook. Дополнительно нам потребуется внести следующие изменения в AndroidManifest.xml
: <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:label="@string/app_name">
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
<activity android:name="com.facebook.FacebookActivity" android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation" android:theme="@android:style/Theme.Translucent.NoTitleBar" android:label="@string/app_name" />
<activity android:name="com.facebook.CustomTabActivity" 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/fb_login_protocol_scheme" />
</intent-filter>
<provider android:authorities="com.facebook.app.FacebookContentProvider1102463466549096" android:name="com.facebook.FacebookContentProvider" android:exported="true" />
</activity>
</application>
Далее вносим небольшие доработки в
MainActivity.cs
:protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
FacebookSdk.SdkInitialize(ApplicationContext);
Forms.Init(this, bundle);
LoadApplication(new App());
}
protected override void OnResume()
{
base.OnResume();
AppEventsLogger.ActivateApp(Application);
}
На этом первичная инициализация Facebook SDK завершена.
Подключаем в iOS
По аналогии с Android, нам будет необходимо внести правки в файл
Info.plist
, вставить следующие строки между <dict>...</dict>
:<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>fb1102463466549096</string>
</array>
</dict>
</array>
<key>FacebookAppID</key>
<string>1102463466549096</string>
<key>FacebookDisplayName</key>
<string>Binwell Social Demo</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
</array>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>facebook.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
<key>fbcdn.net</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
<key>akamaihd.net</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</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);
return base.FinishedLaunching(app, options);
}
public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
{
return Facebook.CoreKit.ApplicationDelegate.SharedInstance.OpenUrl(application, url, sourceApplication, annotation);
}
public override void OnActivated(UIApplication application)
{
Facebook.CoreKit.AppEvents.ActivateApp();
}
На этом предварительная подготовка завершена и мы можем переходить к использованию Facebook SDK в нашем приложении.
Интегрируем с Xamarin.Forms
Использовать Facebook SDK мы будем через механизм
DependencyService
. Для этого в первую очередь опишем нужные данные и интерфейс сервиса:public interface IFacebookService
{
Task<LoginResult> Login();
void Logout();
}
public enum LoginState
{
Failed,
Canceled,
Success
}
public class LoginResult
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string ImageUrl { get; set; }
public string UserId { get; set; }
public string Token { get; set; }
public DateTimeOffset ExpireAt { get; set; }
public LoginState LoginState { get; set; }
public string ErrorString { get; set; }
}
Одной из целей подключения социальных сетей является возможность простого и удобного получения пользовательских данных, поэтому нам потребуется дополнительный запрос для получения email, который Facebook не отдает по умолчанию. Данные запросы будет необходимо реализовать отдельно для каждой платформы.
Реализация для Android
Для Android реализация интерфейса выглядит следующим образом:
[assembly: Dependency(typeof(AndroidFacebookService))]
namespace Login.Droid
{
public class AndroidFacebookService: Java.Lang.Object, IFacebookService, GraphRequest.IGraphJSONObjectCallback, GraphRequest.ICallback, IFacebookCallback
{
public static AndroidFacebookService Instance => DependencyService.Get<IFacebookService>() as AndroidFacebookService;
readonly ICallbackManager _callbackManager = CallbackManagerFactory.Create();
readonly string[] _permissions = { @"public_profile", @"email", @"user_about_me" };
LoginResult _loginResult;
TaskCompletionSource<LoginResult> _completionSource;
public AndroidFacebookService()
{
LoginManager.Instance.RegisterCallback(_callbackManager, this);
}
public Task<LoginResult> Login()
{
_completionSource = new TaskCompletionSource<LoginResult>();
LoginManager.Instance.LogInWithReadPermissions(Forms.Context as Activity, _permissions);
return _completionSource.Task;
}
public void Logout()
{
LoginManager.Instance.LogOut();
}
public void OnActivityResult(int requestCode, int resultCode, Intent data)
{
_callbackManager?.OnActivityResult(requestCode, resultCode, data);
}
public void OnCompleted(JSONObject data, GraphResponse response)
{
OnCompleted(response);
}
public void OnCompleted(GraphResponse response)
{
if (response?.JSONObject == null)
_completionSource?.TrySetResult(new LoginResult {LoginState = LoginState.Canceled});
else
{
_loginResult = new LoginResult
{
FirstName = Profile.CurrentProfile.FirstName,
LastName = Profile.CurrentProfile.LastName,
Email = response.JSONObject.Has("email") ? response.JSONObject.GetString("email") : string.Empty,
ImageUrl = response.JSONObject.GetJSONObject("picture")?.GetJSONObject("data")?.GetString("url"),
Token = AccessToken.CurrentAccessToken.Token,
UserId = AccessToken.CurrentAccessToken.UserId,
ExpireAt = FromJavaDateTime(AccessToken.CurrentAccessToken?.Expires?.Time),
LoginState = LoginState.Success
};
_completionSource?.TrySetResult(_loginResult);
}
}
public void OnCancel()
{
_completionSource?.TrySetResult(new LoginResult { LoginState = LoginState.Canceled });
}
public void OnError(FacebookException exception)
{
_completionSource?.TrySetResult(new LoginResult
{
LoginState = LoginState.Failed,
ErrorString = exception?.Message
});
}
public void OnSuccess(Java.Lang.Object result)
{
var facebookLoginResult = result.JavaCast<Xamarin.Facebook.Login.LoginResult>();
if (facebookLoginResult == null) return;
var parameters = new Bundle();
parameters.PutString("fields", "id,email,picture.type(large)");
var request = GraphRequest.NewMeRequest(facebookLoginResult.AccessToken, this);
request.Parameters = parameters;
request.ExecuteAsync();
}
static DateTimeOffset FromJavaDateTime(long? longTimeMillis)
{
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return longTimeMillis != null ? epoch.AddMilliseconds(longTimeMillis.Value) : DateTimeOffset.MinValue;
}
}
}
Дополнительно потребуется добавить обработчик в
MainActivity.cs
:protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
AndroidFacebookService.Instance.OnActivityResult(requestCode, (int)resultCode, data);
}
Реализация для iOS
Делаем реализацию интерфейса для Facebook iOS SDK.
[assembly: Dependency(typeof(AppleFacebookService))]
namespace Login.iOS
{
public class AppleFacebookService: IFacebookService
{
readonly LoginManager _loginManager = new LoginManager();
readonly string[] _permissions = { @"public_profile", @"email", @"user_about_me" };
LoginResult _loginResult;
TaskCompletionSource<LoginResult> _completionSource;
public Task<LoginResult> Login()
{
_completionSource = new TaskCompletionSource<LoginResult>();
_loginManager.LogInWithReadPermissions(_permissions, GetCurrentViewController(), LoginManagerLoginHandler);
return _completionSource.Task;
}
public void Logout()
{
_loginManager.LogOut();
}
void LoginManagerLoginHandler(LoginManagerLoginResult result, NSError error)
{
if (result.IsCancelled)
_completionSource.TrySetResult(new LoginResult {LoginState = LoginState.Canceled});
else if (error != null)
_completionSource.TrySetResult(new LoginResult { LoginState = LoginState.Failed, ErrorString = error.LocalizedDescription });
else
{
_loginResult = new LoginResult
{
Token = result.Token.TokenString,
UserId = result.Token.UserID,
ExpireAt = result.Token.ExpirationDate.ToDateTime()
};
var request = new GraphRequest(@"me", new NSDictionary(@"fields", @"email"));
request.Start(GetEmailRequestHandler);
}
}
void GetEmailRequestHandler(GraphRequestConnection connection, NSObject result, NSError error)
{
if (error != null)
_completionSource.TrySetResult(new LoginResult { LoginState = LoginState.Failed, ErrorString = error.LocalizedDescription });
else
{
_loginResult.FirstName = Profile.CurrentProfile.FirstName;
_loginResult.LastName = Profile.CurrentProfile.LastName;
_loginResult.ImageUrl = Profile.CurrentProfile.ImageUrl(ProfilePictureMode.Square, new CGSize()).ToString();
var dict = result as NSDictionary;
var emailKey = new NSString(@"email");
if (dict != null && dict.ContainsKey(emailKey))
_loginResult.Email = dict[emailKey]?.ToString();
_loginResult.LoginState = LoginState.Success;
_completionSource.TrySetResult(_loginResult);
}
}
static UIViewController GetCurrentViewController()
{
var viewController = UIApplication.SharedApplication.KeyWindow.RootViewController;
while (viewController.PresentedViewController != null)
viewController = viewController.PresentedViewController;
return viewController;
}
}
}
Подключаем в Xamarin.Forms
Для доступа к созданным реализациям достаточно вставить следующий обработчик события
Clicked
для кнопки «Facebook Login»:var loginResult = await DependencyService.Get<IFacebookService>().Login();
switch (loginResult.LoginState)
{
case LoginState.Canceled:
// Обработать
break;
case LoginState.Success:
var str = $"Hi {loginResult.FirstName}! Your email is {loginResult.Email}";
break;
default:
// Обработать ошибки
break;
}
На этом кодирование завершено!
Используем
Итак, волнительный момент. Делаем сборку, запускаем и… легко авторизуемся с помощью нативных SDK.
Полный код проекта с пошаговыми изменениями расположен в репозитории на Bitbucket.
Итак, сегодня мы подключили нативные Facebook SDK к приложению на Xamarin.Forms. Уже работает авторизация и получение базовой информации о пользователе, но при желании вы можете легко расширить набор методов для доступа ко всем возможностям Facebook SDK. В следующий раз мы возьмем задачку поинтересней и подключим нативные ВКонтакте SDK.
Оставайтесь на связи, задавайте ваши вопросы в комментариях и вступайте в группу Xamarin Developers в Telegram!
Об авторе
Вячеслав Черников — руководитель отдела разработки компании Binwell. В прошлом — один из Nokia Champion и Qt Certified Specialist, в настоящее время — специалист по платформам Xamarin и Azure. В сферу mobile пришел в 2005 году, с 2008 года занимается разработкой мобильных приложений: начинал с Symbian, Maemo, Meego, Windows Mobile, потом перешел на iOS, Android и Windows Phone.
Предыдущие части
1. Быстрое создание MVP (minimum viable product) на базе Microsoft Azure и Xamarin.Forms.
2. Готовим Xamarin.Forms: настройка окружения и первые шаги.
3. Повышаем эффективность работы в Xamarin.Forms.
4. Работаем с состояниями экранов в Xamarin.Forms.
5. Удобный REST для Xamarin-приложений.
Поделиться с друзьями
Комментарии (8)
MakarkinPRO
09.02.2017 09:56Расскажите про интеграцию FaceBook Acoount KIT (там где смс) c backend в котором стандартный метод регистрации/аутентификации Email/Пароль, типа что нужно поменять чтобы это работало) спасибо)
devious
09.02.2017 11:12Не совсем понял о чем именно надо рассказать :) В любом случае, вопросы с сервером пока оставим за кадром и сфокусируемся на Xamarin.Forms
MakarkinPRO
09.02.2017 11:13)) понял, ну как сам процесс сделать понятно. А как переделать уже рабочую авторизацию на бэкенде с только email/пароль было бы интересно. Но хорошо, будет случай спрошу.
S_A
Нужно больше таких же годных статей про Xamarin. И про интеграцию с ВК, и oath2 тоже. И про интеграцию с магазинами и платежными системами.
Беда-то вот в чем: SDK выпускают многие, но в нативе. API приходиться часто повторять ручками. Биндить нативные либы кажется заморочным, хотя и не должно… Вот, тоже могла бы быть интересная статья.
Dageron
C VK и Xamarin еще год назад были сплошные танцы с бубном (т.е. если хочешь, чтобы что-то заработало, пиши свою обертку API прямо через нативные get/set запросы через xml или json). Как сейчас дела обстоят, тоже хотелось бы узнать подробнее.
devious
Глобально, VK для Xamarin цепляется вполне хорошо. Тогда в следующей статье рассмотрим. Потом до кучи разберем OAuth, чтобы и другие соц. сети можно было цеплять без проблем.
Dageron
Буду очень вам благодарен, хотелось бы почитать свежий материал на эту тему. Я сам свой опыт описывал в статье еще два года назад. Если за это время что-то сдвинулось с мертвой точки (в плане binding-а VK SDK с Android, либо адаптацией .NET VK SDK под специфику Xamarin), то это очень и очень жизнеутверждающе.
devious
Про binding были темы на одном из Meetup'ов и там надо скорее целый раздел книги писать, а не статью :)
По ВКонтакте и OAuth сделаем следующие статьи