Skip to content

Instantly share code, notes, and snippets.

@luca-barbieri
Last active February 16, 2018 11:26
Show Gist options
  • Save luca-barbieri/9258bd399d1f5a83597b to your computer and use it in GitHub Desktop.
Save luca-barbieri/9258bd399d1f5a83597b to your computer and use it in GitHub Desktop.
Facebook Login button for Xamarin Forms
// This code has been placed in the public domain.
// NO WARRANTY OF ANY KIND
// WORK IN PROGRESS AND ONLY LIMITED TESTING, MIGHT BE PARTIALLY BROKEN
// Note that you need to setup both your iOS and Android projects to include your app id and so on for this to actually work (see the Facebook docs for each platform)
// Common
public class FacebookLoginEventArgs : EventArgs
{
public string AccessToken {get; set;}
}
public class FacebookLoginButton : View
{
public static readonly BindableProperty ReadPermissionsProperty = BindableProperty.Create<FacebookLoginButton, string[]>(p => p.ReadPermissions, null);
public string[] ReadPermissions {get {return (string[])GetValue(ReadPermissionsProperty); } set {SetValue(ReadPermissionsProperty, value);}}
public static readonly BindableProperty PublishPermissionsProperty = BindableProperty.Create<FacebookLoginButton, string[]>(p => p.PublishPermissions, null);
public string[] PublishPermissions {get {return (string[])GetValue(PublishPermissionsProperty); } set {SetValue(PublishPermissionsProperty, value);}}
public static readonly BindableProperty LoggedInProperty = BindableProperty.Create<FacebookLoginButton, bool>(p => p.LoggedIn, false, BindingMode.OneWayToSource);
public bool LoggedIn {get {return (bool)GetValue(LoggedInProperty); } internal set { SetValue (LoggedInProperty, value); }}
public event EventHandler<FacebookLoginEventArgs> ShowingLoggedInUser;
public event EventHandler ShowingLoggedOutUser;
internal void SendShowingLoggedInUser(string accessToken) {
LoggedIn = true;
var eh = ShowingLoggedInUser;
if (eh != null)
eh (this, new FacebookLoginEventArgs {AccessToken = accessToken});
}
internal void SendShowingLoggedOutUser() {
LoggedIn = false;
var eh = ShowingLoggedOutUser;
if (eh != null)
eh (this, EventArgs.Empty);
}
public void Login()
{
MessagingCenter.Send(this, "Login");
}
public void Logout()
{
MessagingCenter.Send(this, "Logout");
}
}
// iOS
class FacebookLoginButtonRenderer : ViewRenderer<FacebookLoginButton, FBLoginView>
{
protected override void OnElementChanged (ElementChangedEventArgs<FacebookLoginButton> e)
{
base.OnElementChanged (e);
var element = Element;
var session = FBSession.ActiveSession;
element.LoggedIn = session != null && session.IsOpen;
var control = new FBLoginView (element.ReadPermissions);
SetNativeControl(control);
control.ShowingLoggedInUser += (s, ea) => {
var session2 = FBSession.ActiveSession;
var accessToken = (session2 != null && session2.IsOpen) ? session2.AccessTokenData.AccessToken : null;
element.SendShowingLoggedInUser (accessToken);
};
control.ShowingLoggedOutUser += (s, ea) => {element.SendShowingLoggedOutUser ();};
if (element.PublishPermissions != null)
control.PublishPermissions = element.PublishPermissions;
if (element.ReadPermissions != null)
control.ReadPermissions = element.ReadPermissions;
MessagingCenter.Subscribe(this, "Login", (s) => {
Login();
}, element);
MessagingCenter.Subscribe(this, "Logout", (s) => {
Logout();
}, element);
}
void Login()
{
var session = FBSession.ActiveSession;
if (session != null && session.IsOpen)
return;
var button = Control.Subviews.Select (x => x as UIButton).FirstOrDefault (x => x != null);
if (button == null)
throw new Exception ("cannot find FB login button");
button.SendActionForControlEvents (UIControlEvent.TouchUpInside);
}
void Logout()
{
var session = FBSession.ActiveSession;
if (session == null)
return;
session.CloseAndClearTokenInformation ();
}
protected override void OnElementPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged (sender, e);
if(e.PropertyName == FacebookLoginButton.ReadPermissionsProperty.PropertyName)
Control.ReadPermissions = Element.ReadPermissions;
else if(e.PropertyName == FacebookLoginButton.PublishPermissionsProperty.PropertyName)
Control.PublishPermissions = Element.PublishPermissions;
}
}
// Android
public class SessionStatusCallback : Java.Lang.Object, Session.IStatusCallback
{
Action<Session, SessionState, Java.Lang.Exception> _call;
public void Call (Session p0, SessionState p1, Java.Lang.Exception p2)
{
_call (p0, p1, p2);
}
public SessionStatusCallback (Action<Session, SessionState, Java.Lang.Exception> call)
{
_call = call;
}
}
public class FacebookLoginButtonRenderer : ViewRenderer<FacebookLoginButton, LoginButton>
{
protected override void OnElementChanged (ElementChangedEventArgs<FacebookLoginButton> ec)
{
base.OnElementChanged (ec);
var element = ec.NewElement;
{
var session = Session.ActiveSession;
element.LoggedIn = session != null && session.IsOpened;
}
var control = new LoginButton (base.Context);
control.SessionStatusCallback = new SessionStatusCallback((session, state, error) => {
if(session != null && session.IsOpened)
element.SendShowingLoggedInUser (session.AccessToken);
else
element.SendShowingLoggedOutUser();
});
if(element.ReadPermissions != null)
control.SetReadPermissions (element.ReadPermissions);
if(element.PublishPermissions != null)
control.SetPublishPermissions (element.PublishPermissions);
MessagingCenter.Subscribe(this, "Login", (s) => {
Login();
}, element);
MessagingCenter.Subscribe(this, "Logout", (s) => {
Logout();
}, element);
bool sentInitialEvent = false;
control.ViewAttachedToWindow += (s, e) => {
if (!sentInitialEvent && Element != null) {
sentInitialEvent = true;
var session = Session.ActiveSession;
if (session != null && session.IsOpened)
Element.SendShowingLoggedInUser (session.AccessToken);
else
Element.SendShowingLoggedOutUser ();
}
};
var oldControl = Control;
SetNativeControl (control);
if(oldControl != null)
oldControl.Dispose(); // collect Java Objects on Android
}
void Login()
{
var session = Session.ActiveSession;
if (session != null && session.IsOpened)
return;
// TODO: not sure if this works, might need to call it on a button subview
Control.PerformClick ();
}
void Logout()
{
var session = Session.ActiveSession;
if (session == null)
return;
session.CloseAndClearTokenInformation ();
}
protected override void OnElementPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged (sender, e);
if(e.PropertyName == FacebookLoginButton.ReadPermissionsProperty.PropertyName)
Control.SetReadPermissions(Element.ReadPermissions);
else if(e.PropertyName == FacebookLoginButton.PublishPermissionsProperty.PropertyName)
Control.SetPublishPermissions(Element.PublishPermissions);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment