如何login到Xamarin.Forms的Facebook
我想做一个Xamarin.Forms项目,瞄准iOs,Android和Windows Phone。
我的应用需要使用Facebook对用户进行身份validation。
我应该为每个平台独立实现login,还是使用手动stream程? https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.0
我更喜欢有一个loginstream的实现,并在所有平台上使用它。
我怎样才能得到一个facebookloginstream的实现?
你可以使用Xamarin.Social或Xamarin.Auth 。 它允许使用相同的API,无论平台是什么。
到目前为止,这些库并不是PCL,但你仍然可以从共享资源项目中使用它们,或者在接口中抽象出你需要的API,然后使用DependencyService
或任何其他DI容器注入。
更新(10/24/17):虽然这种做法在几年前是好的,但我现在强烈主张使用本机UI进行身份validation,而不是这里显示的webview方法。 通过使用各种各样的身份提供者,Auth0是完成您的应用的原生用户界面login的绝佳方式: 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()
方法。 这告诉应用程序启动时应该先加载哪个屏幕。
我们也有一个简单的属性和方法来存储从auth服务返回的Token
,以及一个简单的IsLoggedIn
属性。
还有一个Action属性, 东西我坚持在这里为了有一个平台的实现Xamarin.Forms导航行动的方式。 稍后再说。
您还会在IDE中注意到一些红色,因为我们还没有创buildProfilePage
类。 那么,让我们来做。
在Xamarin.Forms PCL项目中创build一个非常简单的ProfilePage
类。 我们甚至不会去做任何事情,因为这取决于你的特殊需求。 为了简单起见,它将包含一个标签:
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。 (在这个简化的演示,我们只是坚持用户信息内存,所以你需要重新 – 每次运行应用程序时,在真实世界的应用程序中,您将存储经过身份validation的用户信息到设备的钥匙串,这将消除在每次应用程序启动时需要login的情况。
在Xamarin.Forms PCL项目中创build一个BaseContentPage
类:
namespace OAuth2Demo.XForms { public class BaseContentPage : ContentPage { protected override void OnAppearing () { base.OnAppearing (); if (!App.IsLoggedIn) { Navigation.PushModalAsync(new LoginPage()); } } } }
这里有一些有趣的事情:
-
我们重写了
OnAppearing()
方法,它类似于iOS UIViewController中的ViewWillAppear方法。 你可以在这里执行任何你想在屏幕出现之前立即运行的代码。 -
我们在这个方法中唯一要做的就是检查用户是否login。如果他们不是,那么我们执行一个模式推送到一个名为
LoginPage
的类。 如果您不熟悉模式的概念,那么它只是一个视图,它将用户从正常的应用程序stream程中移出以执行一些特殊的任务; 在我们的情况下,执行login。
所以,我们在Xamarin.Forms PCL项目中创buildLoginPage
类:
namespace OAuth2Demo.XForms { public class LoginPage : ContentPage { } }
等等…为什么这个class没有身体?
由于我们使用Xamatin.Auth组件(它负责构build和呈现一个可以与提供的OAuth2信息一起工作的Web视图),我们实际上并不希望在LoginPage
类中实现任何types的实现。 我知道这似乎很奇怪,但忍受着我。
适用于iOS的LoginPageRenderer
到目前为止,我们一直在Xamarin.Forms PCL项目中工作 。 但是现在我们需要在iOS项目中提供我们LoginPage
的平台特定实现。 这是渲染器的概念来的地方。
在Xamarin.Forms中,当您想要提供平台特定的屏幕和控件(即不从Xamarin.Forms PCL项目的抽象页面中获取其内容的屏幕)时,您可以使用Renderer进行操作 。
在iOS平台项目中创build一个LoginPageRenderer
类:
[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's 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))]
的[assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]
行正在使用Xamarin.Forms DependencyService 。 这不是世界上最美丽的东西,因为它不是IoC / DI,但是无论什么…它的工作。 这是将我们的LoginPageRenderer
“映射”到LoginPage
。 -
这是我们实际使用Xamarin.Auth组件的类。 这就是
OAuth2Authenticator
引用来自的地方。 -
一旦login成功,我们通过
App.SuccessfulLoginAction.Invoke();
引发Xamarin.Forms导航App.SuccessfulLoginAction.Invoke();
。 这让我们回到ProfilePage
。 -
由于我们在iOS上,我们正在做
ViewDidAppear()
方法的所有逻辑sinde。
Android的LoginPageRenderer
在Android平台项目中创build一个LoginPageRenderer
类。 (请注意,您创build的类名与iOS项目中的类名相同,但是在Android项目中,PageRenderer从Android类inheritance,而不是从iOS类inheritance。)
[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))]
的[assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]
行正在使用Xamarin.Forms DependencyService 。 与iOS版本的LoginPageRenderer
没有什么不同。 -
再次,这是我们实际使用Xamarin.Auth组件的地方。 这就是
OAuth2Authenticator
引用来自的地方。 -
就像iOS版本一样,一旦login成功,我们通过
App.SuccessfulLoginAction.Invoke();
引发Xamarin.Forms导航App.SuccessfulLoginAction.Invoke();
。 这让我们回到ProfilePage
。 -
与iOS版本不同,我们正在执行
OnModelChanged()
方法内部的所有逻辑,而不是ViewDidAppear()
。
这里是在iOS上:
…和Android:
更新:我也在我的博客提供了一个详细的示例: http : //www.joesauve.com/using-xamarin-auth-with-xamarin-forms/
我已经创build了一个示例项目来展示如何使用本地Facebook组件创buildFacebooklogin,而不是像本文中提供的解决scheme那样通过webview。 你可以在这个地址查看:
IOS 8:对于那些正在使用@NovaJoe代码并被困在视图中的人,请将代码添加到解决方法:
bool hasShown; public override void ViewDidAppear(bool animated) { if (!hasShown) { hasShown = true; // the rest of @novaJoe code } }
这是一个很好的Xamarin.Formsauthentication示例。 代码中的文档很好。 它使用webview来呈现login屏幕,但是你可以select你想要的logintypes。 它还保存了一个用户令牌,所以他不必保持重新login。
在iOS8上使用Facebook的另一个@ NovaJoe代码,你需要修改Renderer类,如下所示,在authentication成功后closuresView。
auth.Completed += (sender, eventArgs) => { // We presented the UI, so it's up to us to dimiss it on iOS.
/ *导入并添加此行* /
DismissViewController (true, null);
/ * * /
if (eventArgs.IsAuthenticated) { App.Instance.SuccessfulLoginAction.Invoke (); // Use eventArgs.Account to do wonderful things App.Instance.SaveToken (eventArgs.Account.Properties ["access_token"]); } else { // The user cancelled } };