Open Dhvl-Golakiya opened 7 years ago
Hey @Dhvl-Golakiya. When you say NativeFacebookLogin; are you talking about https://www.fusetools.com/docs/native-interop/facebook-login or https://github.com/fusetools/fuse-samples/tree/master/Samples/FacebookLogin or something else ?
Hi,
I am trying this example. https://github.com/fusetools/fuse-samples/tree/feature-NativeFacebookLogin/Samples/NativeFacebookLogin
Got it working. As I'm not sure this code is maintained (or that my updates are good quality code, for that matter), I will add them here. I have encountered 2 issues: the error above, incorrect CallbackManager use, or another one, sometimes, related to FacebookSDK init not being called, although it is bound in the beginning of the class. This may be mostly a preview issue, as it seems to be related to the fact that the Lifecycle bindings have no effect, especially the Started one. So, I checked if Start has been run and if not, run it. Also, made the whole thing return an object with a token key from the login() promise, which makes it then easy to make further FB calls. For this I am actually using the JS sdk, feeding it this token.
using Fuse;
using Fuse.Platform;
using Uno;
using Uno.Compiler.ExportTargetInterop;
[extern(iOS) Require("Xcode.FrameworkDirectory", "@('FacebookSDKs-iOS':Path)")]
[extern(iOS) Require("Xcode.Framework", "@('FacebookSDKs-iOS/FBSDKCoreKit.framework':Path)")]
[extern(iOS) Require("Xcode.Framework", "@('FacebookSDKs-iOS/FBSDKLoginKit.framework':Path)")]
[extern(iOS) ForeignInclude(Language.ObjC, "FBSDKCoreKit/FBSDKCoreKit.h")]
[extern(iOS) ForeignInclude(Language.ObjC, "FBSDKLoginKit/FBSDKLoginKit.h")]
[Require("Gradle.Dependency","compile('com.facebook.android:facebook-android-sdk:4.8.+') { exclude module: 'support-v4' }")]
[Require("Gradle.Repository","mavenCentral()")]
[ForeignInclude(Language.Java, "android.content.Intent")]
[ForeignInclude(Language.Java, "com.facebook.*")]
[ForeignInclude(Language.Java, "com.facebook.appevents.AppEventsLogger")]
[ForeignInclude(Language.Java, "com.facebook.login.*")]
[ForeignInclude(Language.Java, "com.fuse.Activity")]
public class FacebookLogin
{
public FacebookLogin()
{
Lifecycle.Started += Started;
Lifecycle.EnteringInteractive += OnEnteringInteractive;
Lifecycle.ExitedInteractive += OnExitedInteractive;
InterApp.ReceivedURI += OnReceivedUri;
}
[Foreign(Language.ObjC)]
extern(iOS) void Started(ApplicationState state)
@{
[[FBSDKApplicationDelegate sharedInstance]
application: [UIApplication sharedApplication]
didFinishLaunchingWithOptions: nil];
@}
extern(Android) Java.Object _callbackManager = null;
extern(Android) bool _started = false;
[Foreign(Language.Java)]
extern(Android) void Started(ApplicationState state)
@{
@{FacebookLogin:Of(_this)._started:Set(true)};
FacebookSdk.sdkInitialize(Activity.getRootActivity());
@{FacebookLogin:Of(_this)._callbackManager:Set(CallbackManager.Factory.create())};
Activity.subscribeToResults(new Activity.ResultListener()
{
@Override
public boolean onResult(int requestCode, int resultCode, Intent data)
{
return ((CallbackManager)@{FacebookLogin:Of(_this)._callbackManager:Get()}).onActivityResult(requestCode, resultCode, data);
}
});
@}
extern(!iOS && !Android) void Started(ApplicationState state)
{
}
[Foreign(Language.ObjC)]
static extern(iOS) void OnEnteringInteractive(ApplicationState state)
@{
[FBSDKAppEvents activateApp];
@}
[Foreign(Language.Java)]
static extern(Android) void OnEnteringInteractive(ApplicationState state)
@{
AppEventsLogger.activateApp(Activity.getRootActivity());
@}
static extern(!iOS && !Android) void OnEnteringInteractive(ApplicationState state)
{
}
[Foreign(Language.Java)]
static extern(Android) void OnExitedInteractive(ApplicationState state)
@{
AppEventsLogger.deactivateApp(Activity.getRootActivity());
@}
static extern(!Android) void OnExitedInteractive(ApplicationState state)
{
}
static void OnReceivedUri(string uri)
{
debug_log "Received Uri: " + uri;
if (uri.StartsWith("fb"))
{
OpenFacebookURL(uri);
}
}
[Foreign(Language.ObjC)]
static extern(iOS) void OpenFacebookURL(string url)
@{
[[FBSDKApplicationDelegate sharedInstance]
application: [UIApplication sharedApplication]
openURL: [NSURL URLWithString:url]
sourceApplication: @"com.apple.mobilesafari"
annotation: nil];
@}
static extern(!iOS) void OpenFacebookURL(string url)
{
}
public class AccessToken
{
extern(iOS) string _token;
extern(Android) string _token;
public extern(iOS) AccessToken(string token)
{
_token = token;
}
public extern(Android) AccessToken(string token)
{
_token = token;
}
public extern(iOS) string getTokenString()
{
return _token;
}
public extern(Android) string getTokenString()
{
return _token;
}
}
[Foreign(Language.ObjC)]
public extern(iOS) void Login(Action<AccessToken> onSuccess, Action onCancelled, Action<string> onError)
@{
FBSDKLoginManager* login = [[FBSDKLoginManager alloc] init];
[login
logInWithReadPermissions: @[@"public_profile",]
fromViewController: [[[UIApplication sharedApplication] keyWindow] rootViewController]
handler: ^(FBSDKLoginManagerLoginResult* result, NSError* error)
{
if (error)
{
onError([error localizedDescription]);
return;
}
if (result.isCancelled)
{
onCancelled();
return;
}
id<UnoObject> unoAccessToken = @{AccessToken(string):New(result.token.tokenString)};
onSuccess(unoAccessToken);
}
];
@}
[Foreign(Language.Java)]
[Require("Entity", "AccessToken(string)")]
public extern(Android) void Login(Action<AccessToken> onSuccess, Action onCancelled, Action<string> onError)
@{
if (!@{FacebookLogin:Of(_this)._started:Get()}) {
@{FacebookLogin:Of(_this).Started(ApplicationState):Call(@{ApplicationState.Foreground})};
}
LoginManager.getInstance().registerCallback((CallbackManager)@{FacebookLogin:Of(_this)._callbackManager:Get()},
new FacebookCallback<LoginResult>()
{
@Override
public void onSuccess(LoginResult loginResult)
{
AccessToken accessToken = loginResult.getAccessToken();
UnoObject unoAccessToken = @{AccessToken(string):New(accessToken.getToken())};
onSuccess.run(unoAccessToken);
}
@Override
public void onCancel()
{
onCancelled.run();
}
@Override
public void onError(FacebookException exception)
{
onError.run(exception.toString());
}
}
);
LoginManager.getInstance().logInWithReadPermissions(Activity.getRootActivity(), java.util.Arrays.asList("public_profile"));
@}
}
using Fuse.Scripting;
using Uno.Permissions;
using Uno.Threading;
using Uno.UX;
using Uno;
[UXGlobalModule]
public class FacebookLoginModule : NativeModule
{
class FacebookLoginPromise : Promise<FacebookLogin.AccessToken>
{
readonly FacebookLogin _facebookLogin;
public FacebookLoginPromise(FacebookLogin facebookLogin)
{
_facebookLogin = facebookLogin;
if defined(Android)
{
Permissions.Request(Permissions.Android.INTERNET).Then(
OnPermissionsPermitted,
OnPermissionsRejected);
}
else
{
Fuse.UpdateManager.AddOnceAction(Login);
}
}
void Login()
{
if defined(iOS || Android)
_facebookLogin.Login(this.Resolve, OnCancelled, OnError);
else
throw new NotImplementedException();
}
void OnCancelled()
{
Reject(new Exception("Cancelled"));
}
void OnError(string error)
{
Reject(new Exception(error));
}
extern(Android) void OnPermissionsPermitted(PlatformPermission p)
{
Fuse.UpdateManager.AddOnceAction(Login);
}
extern(Android) void OnPermissionsRejected(Exception e)
{
Reject(e);
}
}
static readonly FacebookLoginModule _instance;
readonly FacebookLogin _facebookLogin;
public FacebookLoginModule()
{
if (_instance != null)
return;
_facebookLogin = new FacebookLogin();
_instance = this;
Resource.SetGlobalKey(_instance, "FacebookLogin");
AddMember(new NativePromise<FacebookLogin.AccessToken, Fuse.Scripting.Object>("login", Login, Converter));
}
Future<FacebookLogin.AccessToken> Login(object[] args)
{
return new FacebookLoginPromise(_facebookLogin);
}
static Fuse.Scripting.Object Converter(Context context, FacebookLogin.AccessToken accessToken)
{
var wrapperObject = context.NewObject();
wrapperObject["token"] = accessToken.getTokenString();
return wrapperObject;
}
}
FacebookLogin.login()
.then(result => {
fetchFbData(result.token)
})
.catch(error => {
console.log('Login failed: ' + error)
})
@schniper thank you for your fix. It's works.
I have fix FacebookLoginModule class because I have an error on method Converter when I launched project on Desktop.
using Fuse.Scripting;
using Uno.Permissions;
using Uno.Threading;
using Uno.UX;
using Uno;
[UXGlobalModule]
public class FacebookLoginModule : NativeModule
{
class FacebookLoginPromise : Promise<FacebookLogin.AccessToken>
{
readonly FacebookLogin _facebookLogin;
public FacebookLoginPromise(FacebookLogin facebookLogin)
{
_facebookLogin = facebookLogin;
if defined(Android)
{
Permissions.Request(Permissions.Android.INTERNET).Then(
OnPermissionsPermitted,
OnPermissionsRejected);
}
else
{
Fuse.UpdateManager.AddOnceAction(Login);
}
}
void Login()
{
if defined(iOS || Android)
_facebookLogin.Login(this.Resolve, OnCancelled, OnError);
else
throw new NotImplementedException();
}
void OnCancelled()
{
Reject(new Exception("Cancelled"));
}
void OnError(string error)
{
Reject(new Exception(error));
}
extern(Android) void OnPermissionsPermitted(PlatformPermission p)
{
Fuse.UpdateManager.AddOnceAction(Login);
}
extern(Android) void OnPermissionsRejected(Exception e)
{
Reject(e);
}
}
static readonly FacebookLoginModule _instance;
readonly FacebookLogin _facebookLogin;
public FacebookLoginModule()
{
if (_instance != null)
return;
_facebookLogin = new FacebookLogin();
_instance = this;
Resource.SetGlobalKey(_instance, "FacebookLogin");
AddMember(new NativePromise<FacebookLogin.AccessToken, Fuse.Scripting.Object>("login", Login, Converter));
}
Future<FacebookLogin.AccessToken> Login(object[] args)
{
return new FacebookLoginPromise(_facebookLogin);
}
static Fuse.Scripting.Object Converter(Context context, FacebookLogin.AccessToken accessToken)
{
var wrapperObject = context.NewObject();
if defined(iOS || Android)
wrapperObject["token"] = accessToken.getTokenString();
return wrapperObject;
}
}
I know there was an issue, in the end my token class looked like this:
public class AccessToken
{
string _token;
public AccessToken(string token)
{
_token = token;
}
public string getTokenString()
{
return _token;
}
}
No native stuff. Of course, this works because for me it's enough to get the token so I can play with the JS API further, not use the native SDK.
If you use this update you don't have to change the other stuff.
Hi,
I am trying to run NativeFacebookLogin example on both iOS and Android. It is working on iOS but getting below error in Android.
Any idea how I can fix it?