Я хочу создать проект Xamarin.Forms, ориентированный на iOS, Android и Windows Phone.
Мое приложение должно аутентифицировать пользователей с помощью Facebook.
Я предпочитаю иметь единую реализацию потока входа в систему и использовать ее на всех платформах.
Ответ 2
ОБНОВЛЕНИЕ (24.10.17): Хотя несколько лет назад такой подход был нормальным, сейчас я настоятельно рекомендую использовать собственный пользовательский интерфейс для аутентификации, а не метод веб-просмотра, показанный здесь. Auth0 - отличный способ выполнить вход в пользовательский интерфейс для ваших приложений, используя широкий спектр провайдеров идентификации: https://auth0.com/docs/quickstart/native/xamarin
РЕДАКТИРОВАТЬ: я наконец-то положил образец для этого на Gihub
Я разместил ответ на форумах Xamarin. Я повторю это здесь.
Начнем с ядра приложения, проекта Xamarin.Forms PCL. Ваш класс App
будет выглядеть примерно так:
namespace OAuth2Demo.XForms
{
public class App
{
static NavigationPage _NavPage;
public static Page GetMainPage ()
{
var profilePage = new ProfilePage();
_NavPage = new NavigationPage(profilePage);
return _NavPage;
}
public static bool IsLoggedIn {
get { return !string.IsNullOrWhiteSpace(_Token); }
}
static string _Token;
public static string Token {
get { return _Token; }
}
public static void SaveToken(string token)
{
_Token = token;
}
public static Action SuccessfulLoginAction
{
get {
return new Action (() => {
_NavPage.Navigation.PopModalAsync();
});
}
}
}
}
Первое, на что нужно обратить внимание - это GetMainPage()
. Это сообщает приложению, какой экран должен быть загружен первым при запуске.
У нас также есть простое свойство и метод для хранения Token
который возвращается из службы аутентификации, а также простое свойство IsLoggedIn
.
Также есть свойство Action; что-то, что я застрял здесь, чтобы у реализаций платформы был способ выполнить навигационное действие Xamarin.Forms. Подробнее об этом позже.
Вы также заметите красный цвет в вашей IDE, потому что мы еще не создали класс ProfilePage
. Итак, давайте сделаем это.
Создайте очень простой класс ProfilePage
в проекте Xamarin.Forms PCL. Мы даже не собираемся делать с этим ничего особенного, потому что это будет зависеть от вашей конкретной потребности. Для простоты в этом примере он будет содержать одну метку:
namespace OAuth2Demo.XForms
{
public class ProfilePage : BaseContentPage
{
public ProfilePage ()
{
Content = new Label () {
Text = "Profile Page",
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
}
}
}
Опять же, у вас, вероятно, будет немного красного цвета в вашей IDE, потому что мы, кажется, пропускаем класс BaseContentPage
. Единственная цель класса BaseContentPage
- обеспечить, чтобы ни один из экранов приложения не отображался до тех пор, пока пользователь не вошел в систему. (В этой упрощенной демонстрации мы просто сохраняем информацию о пользователе в памяти, поэтому вам нужно -login каждый раз, когда приложение запускается. В реальном приложении вы сохраняете информацию аутентифицированного пользователя в цепочке ключей устройства, что устраняет необходимость входа при каждом запуске приложения.)
Создайте класс BaseContentPage
в проекте Xamarin.Forms PCL:
namespace OAuth2Demo.XForms
{
public class BaseContentPage : ContentPage
{
protected override void OnAppearing ()
{
base.OnAppearing ();
if (!App.IsLoggedIn) {
Navigation.PushModalAsync(new LoginPage());
}
}
}
}
Здесь происходит несколько интересных вещей:
-
Мы переопределяем метод OnAppearing()
, который похож на метод ViewWillAppear в iOS UIViewController. Здесь вы можете выполнить любой код, который хотите запустить непосредственно перед появлением экрана.
-
Единственное, что мы делаем в этом методе, это проверяем, вошел ли пользователь в систему. Если это не так, то мы выполняем модальный LoginPage
в класс с именем LoginPage
. Если вы не знакомы с концепцией модального режима, это просто представление, которое выводит пользователя из обычного потока приложений для выполнения какой-то специальной задачи; в нашем случае для входа в систему.
Итак, давайте создадим класс LoginPage
в проекте Xamarin.Forms PCL:
namespace OAuth2Demo.XForms
{
public class LoginPage : ContentPage
{
}
}
Подожди... почему у этого класса нет тела???
Поскольку мы используем компонент Xamatin.Auth (который выполняет работу по созданию и представлению веб-представления, работающего с предоставленной информацией OAuth2), мы фактически не хотим никакой реализации в нашем классе LoginPage
. Я знаю, что это кажется странным, но терпите меня.
LoginPageRenderer для iOS
До этого момента мы работали исключительно в рамках проекта Xamarin.Forms PCL. Но теперь нам нужно предоставить платформо- LoginPage
реализацию нашего LoginPage
в проекте iOS. Вот тут и приходит понятие рендерера.
В Xamarin.Forms, когда вы хотите предоставить платформо-зависимые экраны и элементы управления (то есть экраны, которые не получают свое содержимое от абстрактных страниц в проекте Xamarin.Forms PCL), вы делаете это с помощью Renderers.
Создайте класс LoginPageRenderer
в своем проекте платформы iOS:
[assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]
namespace OAuth2Demo.XForms.iOS
{
public class LoginPageRenderer : PageRenderer
{
public override void ViewDidAppear (bool animated)
{
base.ViewDidAppear (animated);
var auth = new OAuth2Authenticator (
clientId: "", // your OAuth2 client id
scope: "", // the scopes for the particular API you're accessing, delimited by "+" symbols
authorizeUrl: new Uri (""), // the auth URL for the service
redirectUrl: new Uri ("")); // the redirect URL for the service
auth.Completed += (sender, eventArgs) => {
// We presented the UI, so it up to us to dimiss it on iOS.
App.SuccessfulLoginAction.Invoke();
if (eventArgs.IsAuthenticated) {
// Use eventArgs.Account to do wonderful things
App.SaveToken(eventArgs.Account.Properties["access_token"]);
} else {
// The user cancelled
}
};
PresentViewController (auth.GetUI (), true, null);
}
}
}
}
Есть важные вещи, на которые стоит обратить внимание:
-
[assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]
вверху (и, что важно, до объявления пространства имен) использует Xamarin.Forms DependencyService. Это не самая красивая вещь в мире, потому что это не IoC/DI, а как угодно... это работает. Это механизм, который "отображает" наш LoginPageRenderer
на LoginPage
.
-
Это класс, в котором мы на самом деле используем компонент Xamarin.Auth. OAuth2Authenticator
ссылка на OAuth2Authenticator
.
-
После успешного входа в систему мы запускаем навигацию App.SuccessfulLoginAction.Invoke();
через App.SuccessfulLoginAction.Invoke();
, Это возвращает нас к ProfilePage
.
-
Поскольку мы работаем на iOS, мы выполняем все наши логические операции с ViewDidAppear()
.
LoginPageRenderer для Android
Создайте класс LoginPageRenderer
в своем проекте платформы Android. (Обратите внимание, что создаваемое вами имя класса совпадает с именем в проекте iOS, но здесь, в проекте Android, PageRenderer наследует классы Android вместо классов iOS.)
[assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]
namespace OAuth2Demo.XForms.Android
{
public class LoginPageRenderer : PageRenderer
{
protected override void OnModelChanged (VisualElement oldModel, VisualElement newModel)
{
base.OnModelChanged (oldModel, newModel);
// this is a ViewGroup - so should be able to load an AXML file and FindView<>
var activity = this.Context as Activity;
var auth = new OAuth2Authenticator (
clientId: "", // your OAuth2 client id
scope: "", // the scopes for the particular API you're accessing, delimited by "+" symbols
authorizeUrl: new Uri (""), // the auth URL for the service
redirectUrl: new Uri ("")); // the redirect URL for the service
auth.Completed += (sender, eventArgs) => {
if (eventArgs.IsAuthenticated) {
App.SuccessfulLoginAction.Invoke();
// Use eventArgs.Account to do wonderful things
App.SaveToken(eventArgs.Account.Properties["access_token"]);
} else {
// The user cancelled
}
};
activity.StartActivity (auth.GetUI(activity));
}
}
}
Опять же, давайте посмотрим на некоторые интересные вещи:
-
[assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]
вверху (и, что важно, до объявления пространства имен) использует Xamarin.Forms DependencyService. Здесь нет никаких отличий от версии LoginPageRenderer
для LoginPageRenderer
.
-
Опять же, именно здесь мы на самом деле используем компонент Xamarin.Auth. OAuth2Authenticator
ссылка на OAuth2Authenticator
.
-
Как и в версии для iOS, после успешного входа в систему мы запускаем навигацию App.SuccessfulLoginAction.Invoke();
через App.SuccessfulLoginAction.Invoke();
, Это возвращает нас к ProfilePage
.
-
В отличие от версии для iOS, мы выполняем всю логику внутри метода OnModelChanged()
вместо ViewDidAppear()
.
Вот это на iOS:
![Xamarin.Auth with Xamarin.Forms iOS example]()
... и Android:
![Xamarin.Auth with Xamarin.Forms Android example]()
ОБНОВЛЕНИЕ: я также предоставил подробный образец в своем блоге: http://www.joesauve.com/using-xamarin-auth-with-xamarin-forms/