diff --git a/README.md b/README.md index cfbf9dc..8e3870d 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ These samples are supplied directly from the feature teams of Fuse and we welcom + diff --git a/Samples/NativeFacebookLogin/FacebookAppId.uxl b/Samples/NativeFacebookLogin/FacebookAppId.uxl new file mode 100644 index 0000000..ced65ff --- /dev/null +++ b/Samples/NativeFacebookLogin/FacebookAppId.uxl @@ -0,0 +1,3 @@ + + + diff --git a/Samples/NativeFacebookLogin/FacebookLogin/FacebookLogin.uno b/Samples/NativeFacebookLogin/FacebookLogin/FacebookLogin.uno new file mode 100644 index 0000000..5a9d24f --- /dev/null +++ b/Samples/NativeFacebookLogin/FacebookLogin/FacebookLogin.uno @@ -0,0 +1,234 @@ +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")] +// Reference for excludes - https://stackoverflow.com/questions/46212449/facebook-sdk-dependency-conflict +[Require("Gradle.Dependency","implementation('com.facebook.android:facebook-android-sdk:[4,5)') { exclude group: 'com.android.support', module: 'support-v4' \nexclude group: 'com.android.support', module: 'support-core-utils' }")] +[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, "org.json.JSONObject")] +[ForeignInclude(Language.Java, "org.json.JSONException")] +[ForeignInclude(Language.Java, "android.os.Bundle")] +[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; + + [Foreign(Language.Java)] + extern(Android) void Started(ApplicationState state) + @{ + FacebookSdk.sdkInitialize(Activity.getRootActivity()); + final CallbackManager callbackManager = CallbackManager.Factory.create(); + @{FacebookLogin:Of(_this)._callbackManager:Set(callbackManager)}; + Activity.subscribeToResults(new Activity.ResultListener() + { + @Override + public boolean onResult(int requestCode, int resultCode, Intent data) + { + return callbackManager.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 User + { + extern string _id; + extern string _name; + extern string _email; + extern string _token; + + public User(String id, String name, String email, String token) + { + _id = id; + _name = name; + _email = email; + _token = token; + } + + public string getId() { + return _id; + } + + public string getName() { + return _name; + } + + public string getEmail() { + return _email; + } + + public string getTokenString() { + return _token; + } + } + + [Foreign(Language.ObjC)] + public extern(iOS) void Login(Action onSuccess, Action onCancelled, Action onError) + @{ + FBSDKLoginManager* login = [[FBSDKLoginManager alloc] init]; + [login + logInWithReadPermissions: @[@"public_profile", @"email"] + fromViewController: [[[UIApplication sharedApplication] keyWindow] rootViewController] + handler: ^(FBSDKLoginManagerLoginResult* result, NSError* error) + { + if (error) + { + onError([error localizedDescription]); + return; + } + if (result.isCancelled) + { + onCancelled(); + return; + } + if ([FBSDKAccessToken currentAccessToken]) + { + NSMutableDictionary* parameters = [NSMutableDictionary dictionary]; + [parameters setValue:@"id,name,email" forKey:@"fields"]; + + [[[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:parameters] startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + if (!error) + { + id user = @{User(string, string, string, string):New(result[@"id"], result[@"name"], result[@"email"], [FBSDKAccessToken currentAccessToken].tokenString)}; + onSuccess(user); + } + }]; + } + } + ]; + @} + + [Foreign(Language.Java)] + [Require("Entity", "User(string, string, string, string)")] + public extern(Android) void Login(Action onSuccess, Action onCancelled, Action onError) + @{ + CallbackManager callbackManager = (CallbackManager)@{FacebookLogin:Of(_this)._callbackManager:Get()}; + LoginManager.getInstance().registerCallback(callbackManager, + new FacebookCallback() + { + @Override + public void onSuccess(LoginResult loginResult) + { + final AccessToken accessToken = loginResult.getAccessToken(); + + GraphRequest request = GraphRequest.newMeRequest( + loginResult.getAccessToken(), + new GraphRequest.GraphJSONObjectCallback() { + @Override + public void onCompleted( + JSONObject object, + GraphResponse response) { + try { + String fbUserId = object.getString("id"); + String fbUserName = object.getString("name"); + String fbEmail = object.getString("email"); + String tokenString = accessToken.getToken(); + + UnoObject user = @{User(string, string, string, string):New(fbUserId, fbUserName, fbEmail, tokenString)}; + onSuccess.run(user); + } catch (JSONException e) { + e.printStackTrace(); + } + } + }); + Bundle parameters = new Bundle(); + parameters.putString("fields", "id,name,email"); + request.setParameters(parameters); + request.executeAsync(); + } + + @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", "email")); + @} +} diff --git a/Samples/NativeFacebookLogin/FacebookLogin/FacebookLogin.unoproj b/Samples/NativeFacebookLogin/FacebookLogin/FacebookLogin.unoproj new file mode 100644 index 0000000..8e98979 --- /dev/null +++ b/Samples/NativeFacebookLogin/FacebookLogin/FacebookLogin.unoproj @@ -0,0 +1,17 @@ +{ + "IsTransitive": true, + "Packages": [ + "Fuse", + "Fuse.Platform", + "Fuse.Scripting", + "FuseJS", + "Uno.Permissions", + "Uno.Threading", + ], + "Includes": [ + "FacebookLogin.uno", + "FacebookLogin.uxl", + "FacebookLoginModule.uno", + "FacebookSDKs-iOS.stuff", + ], +} diff --git a/Samples/NativeFacebookLogin/FacebookLogin/FacebookLogin.uxl b/Samples/NativeFacebookLogin/FacebookLogin/FacebookLogin.uxl new file mode 100644 index 0000000..e4e2c4d --- /dev/null +++ b/Samples/NativeFacebookLogin/FacebookLogin/FacebookLogin.uxl @@ -0,0 +1,76 @@ + + + @(Facebook.AppID) + fb@(Facebook.AppID) + ]]> + + + + + + + + + + + + + + + + ]]> + + + CFBundleURLTypes + + + CFBundleURLSchemes + + fb@(Facebook.AppID) + + + + FacebookAppID + @(Facebook.AppID) + FacebookDisplayName + Fuse Test App + + NSAppTransportSecurity + + NSExceptionDomains + + facebook.com + + NSIncludesSubdomains + NSThirdPartyExceptionRequiresForwardSecrecy + + fbcdn.net + + NSIncludesSubdomains + NSThirdPartyExceptionRequiresForwardSecrecy + + akamaihd.net + + NSIncludesSubdomains + NSThirdPartyExceptionRequiresForwardSecrecy + + + + + LSApplicationQueriesSchemes + + fbauth2 + + ]]> + + diff --git a/Samples/NativeFacebookLogin/FacebookLogin/FacebookLoginModule.uno b/Samples/NativeFacebookLogin/FacebookLogin/FacebookLoginModule.uno new file mode 100644 index 0000000..8773e0c --- /dev/null +++ b/Samples/NativeFacebookLogin/FacebookLogin/FacebookLoginModule.uno @@ -0,0 +1,87 @@ +using Fuse.Scripting; +using Uno.Permissions; +using Uno.Threading; +using Uno.UX; +using Uno; + +[UXGlobalModule] +public class FacebookLoginModule : NativeModule +{ + class FacebookLoginPromise : Promise + { + 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("login", Login, Converter)); + } + + Future Login(object[] args) + { + return new FacebookLoginPromise(_facebookLogin); + } + + static Fuse.Scripting.Object Converter(Context context, FacebookLogin.User user) + { + var wrapperObject = context.NewObject(); + wrapperObject["id"] = user.getId(); + wrapperObject["email"] = user.getEmail(); + wrapperObject["name"] = user.getName(); + wrapperObject["tokenString"] = user.getTokenString(); + return wrapperObject; + } +} diff --git a/Samples/NativeFacebookLogin/FacebookLogin/FacebookSDKs-iOS.stuff b/Samples/NativeFacebookLogin/FacebookLogin/FacebookSDKs-iOS.stuff new file mode 100644 index 0000000..d2e12de --- /dev/null +++ b/Samples/NativeFacebookLogin/FacebookLogin/FacebookSDKs-iOS.stuff @@ -0,0 +1,6 @@ +if iOS { + FacebookSDKs-iOS: "https://lookaside.facebook.com/developers/resources/?id=facebook-ios-sdk-current.zip" +} +if Android { + FacebookSDKs-Android: "https://lookaside.facebook.com/developers/resources/?id=facebook-android-sdk-current.zip" +} diff --git a/Samples/NativeFacebookLogin/FacebookLoginExample.unoproj b/Samples/NativeFacebookLogin/FacebookLoginExample.unoproj new file mode 100644 index 0000000..a959d37 --- /dev/null +++ b/Samples/NativeFacebookLogin/FacebookLoginExample.unoproj @@ -0,0 +1,26 @@ +{ + "iOS": { + "BundleIdentifier": "com.uno.test", + }, + "Android": { + "Package": "com.uno.test", + "Activity": "MainActivity", + "SDK": { + "BuildToolsVersion": "29.0.2", + "CompileVersion": 29, + "MinVersion": 19, + "TargetVersion": 29 + } + }, + "Packages": [ + "Fuse", + "Uno.Permissions", + ], + "Projects": [ + "FacebookLogin/FacebookLogin.unoproj", + ], + "Includes": [ + "FacebookAppId.uxl", + "MainView.ux", + ], +} diff --git a/Samples/NativeFacebookLogin/MainView.ux b/Samples/NativeFacebookLogin/MainView.ux new file mode 100644 index 0000000..0b91355 --- /dev/null +++ b/Samples/NativeFacebookLogin/MainView.ux @@ -0,0 +1,24 @@ + + + var FacebookLogin = require("FacebookLogin"); + + function login() { + FacebookLogin.login().then(function(user) { + console.log(JSON.stringify(user)); + // {"id":"XXXXXXXXX","email":"XXXCX@hotmail.com","name":"Jesús Martínez", "tokenString": "NUMBER5_L3TTERS_NUMB3RS_LETTERS"} + }, function(err) { + console.log("Login failed: " + err); + }); + } + + module.exports = { + login: login, + }; + + + + +
Native Facebook Login AmazonS3 Azure AD B2C login Facebook login