如何在Xamarin.Forms中登录facebook

Mor*_*yhr 45 xamarin xamarin.forms

我想制作一个Xamarin.Forms项目,目标是iOs,Android和Windows Phone.

我的应用需要使用Facebook验证用户身份.

我应该独立实现每个平台的登录,还是使用手动流程? https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.0

我更喜欢单一的登录流程实现,并在所有平台上使用它.

如何才能获得facebook登录流程的单一实现?

Nov*_*Joe 104

更新(10/24/17):虽然几年前这种做事方式还可以,但我现在强烈主张使用本机UI进行身份验证,而不是此处显示的webview方法.Auth0是使用各种身份提供商完成应用程序本机UI登录的好方法: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();
                });
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

首先要注意的是GetMainPage()方法.这告诉app应该在启动时首先加载哪个屏幕.

我们还有一个简单的属性和方法来存储Token从auth服务返回的属性和方法,以及一个简单的IsLoggedIn属性.

还有一个Action属性; 我在这里停留的东西是为了让平台实现能够执行Xamarin.Forms导航操作.稍后会详细介绍.

您还会注意到IDE中有一些红色,因为我们尚未创建ProfilePage该类.所以,让我们这样做.

ProfilePageXamarin.Forms PCL项目中创建一个非常简单的类.我们甚至不打算用它做任何事情因为这取决于你的特殊需要.为了简化此示例,它将包含一个标签:

namespace OAuth2Demo.XForms
{
    public class ProfilePage : BaseContentPage
    {
        public ProfilePage ()
        {
            Content = new Label () {
                Text = "Profile Page", 
                VerticalOptions = LayoutOptions.CenterAndExpand,
                HorizontalOptions = LayoutOptions.CenterAndExpand, 
            };
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

同样,你的IDE中可能会有一些红色,因为我们似乎错过了这个BaseContentPage类.本BaseContentPage课程的唯一目的是确保在用户登录之前不会显示任何应用程序的屏幕.(在这个简化的演示中,我们只是将用户信息保存到内存中,因此您需要重新每次运行应用程序时都会登录.在真实应用程序中,您将经过身份验证的用户信息存储到设备的钥匙串中,这样就无需在每个应用程序启动时登录.)

BaseContentPageXamarin.Forms PCL项目中创建一个类:

namespace OAuth2Demo.XForms
{
    public class BaseContentPage : ContentPage
    {
        protected override void OnAppearing ()
        {
            base.OnAppearing ();

            if (!App.IsLoggedIn) {
                Navigation.PushModalAsync(new LoginPage());
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这里有一些有趣的事情:

  1. 我们重写了这个OnAppearing()方法,类似于iOS UIViewController中的ViewWillAppear方法.您可以在此处执行任何您希望在屏幕出现之前立即运行的代码.

  2. 我们在这个方法中唯一要做的就是检查用户是否登录.如果不是,那么我们对一个名为的类执行模态推送LoginPage.如果您不熟悉模态的概念,那么它只是一个将用户从正常的应用程序流中移出以执行某项特殊任务的视图; 在我们的例子中,执行登录.

那么,让我们LoginPageXamarin.Forms PCL项目中创建类:

namespace OAuth2Demo.XForms
{
    public class LoginPage : ContentPage
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

等等......为什么这堂课没有身体???

由于我们使用的是Xamatin.Auth组件(它负责构建和呈现与提供的OAuth2信息一起使用的Web视图),因此我们实际上不希望在我们的LoginPage类中进行任何类型的实现.我知道这看起来很奇怪,但请耐心等待.

适用于iOS的LoginPageRenderer

到目前为止,我们一直只在Xamarin.Forms PCL项目中工作.但是现在我们需要LoginPage在iOS项目中提供我们特定于平台的实现.这就是渲染器概念的用武之地.

在Xamarin.Forms中,当您想要提供特定于平台的屏幕和控件(即不从Xamarin.Forms PCL项目中的抽象页面派生其内容的屏幕)时,您可以使用Renderers.

LoginPageRendereriOS平台项目中创建一个类:

[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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有一些重要的事情需要注意:

  1. [assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]顶部的行(重要的是命名空间声明之前)使用Xamarin.Forms DependencyService.它不是世界上最美丽的东西,因为它不是IoC/DI,但无论如何......它都有效.这是"映射"我们的机制LoginPageRendererLoginPage.

  2. 这是我们实际使用Xamarin.Auth组件的类.这就是OAuth2Authenticator参考文献的来源.

  3. 登录成功后,我们将启动Xamarin.Forms导航App.SuccessfulLoginAction.Invoke();.这让我们回到了ProfilePage.

  4. 因为我们在iOS上,所以我们正在做我们所有的逻辑ViewDidAppear()方法.

适用于Android的LoginPageRenderer

LoginPageRendererAndroid平台项目中创建一个类.(请注意,您创建的类名与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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

再说一次,我们来看看一些有趣的事情:

  1. [assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]顶部的行(重要的是命名空间声明之前)使用Xamarin.Forms DependencyService.这里与iOS版本没什么区别LoginPageRenderer.

  2. 同样,这是我们实际使用Xamarin.Auth组件的地方.这就是OAuth2Authenticator参考文献的来源.

  3. 与iOS版本一样,一旦登录成功,我们就会启动Xamarin.Forms导航App.SuccessfulLoginAction.Invoke();.这让我们回到了ProfilePage.

  4. 与iOS版本不同,我们正在使用OnModelChanged()方法内部的所有逻辑而不是ViewDidAppear().

这是在iOS上:

Xamarin.Auth与Xamarin.Forms iOS示例

...和Android:

Xamarin.Auth与Xamarin.Forms Android示例

更新: 我还在我的博客上提供了详细的样本:http://www.joesauve.com/using-xamarin-auth-with-xamarin-forms/

  • 你是一个了不起的人.如果你曾经在大急流城,MI地区,请让我给你买啤酒.twitter.com/kingdango (6认同)
  • 我并不总是回答关于SO的问题,但是当我这样做时,他们很有趣.;) (2认同)
  • @NovaJoe问题是我正在使用xamarin的另一个.dll你正在使用v1.0.0.0而我正在使用v1.2.1.0,它有一个名为`OnElementChanged的不同函数(ElementChangedEventArgs <Xamarin.Forms.Page> e) ;`显然接受不同的参数 (2认同)

Ste*_*oix 20

您可以使用Xamarin.SocialXamarin.Auth.无论平台是什么,它都允许使用相同的api.

截至目前,这些库还不是PCL,但您仍然可以从共享资产项目中使用它们,或者在界面中抽象您需要的API并注入DependencyService或使用任何其他DI容器.


Ido*_*doT 9

我已经创建了一个示例项目来展示如何使用本机Facebook组件创建Facebook登录,而不是通过像这里建议的解决方案那样的webview.你可以在这个地址看看:

https://github.com/IdoTene/XamarinFormsNativeFacebook


Ale*_*dre 5

IOS 8:对于那些正在使用@NovaJoe代码并且仍然停留在视图上的人,请将以下代码添加到变通方法中:

 bool hasShown;

    public override void ViewDidAppear(bool animated)
    {
        if (!hasShown)
        {
            hasShown = true;

            // the rest of @novaJoe code
        }

    }
Run Code Online (Sandbox Code Playgroud)