Last active
February 16, 2018 11:26
-
-
Save luca-barbieri/9258bd399d1f5a83597b to your computer and use it in GitHub Desktop.
Facebook Login button for Xamarin Forms
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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