Facebook Login - Hybrid Apps - javascript

UPDATE:
In the end, I ended up imlementing using apache cordova/phonegap via Eclipse for android and xcode for iOS. This is the only solution that works on my preferred set up.
Link to download the plugin and documentation: https://github.com/phonegap/phonegap-facebook-plugin
Previous post:
I would like to implement facebook login into my hybrid apps. I already did few research in facebook documentation but I haven't found anything that works. If you can provide me some tips, that would be very helpful. I will reward a bounty for someone who can tell me how to do it.
I don't want to go through Phonegap/cordova and other framework since it would need me a lot of time to study those framework.
Hybrid apps - like native apps, run on the device, and are written with web technologies (HTML5, CSS and JavaScript). Hybrid apps run inside a native container, and leverage the device’s browser engine (but not the browser) to render the HTML and process the JavaScript locally. A web-to-native abstraction layer enables access to device capabilities that are not accessible in Mobile Web applications, such as the accelerometer, camera and local storage.
If anyone has any solution and willing to help, please let me know.
I've tried Javascript SDK but no luck.
Code:
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function() {
FB.init({
appId : 'xxxx', // App ID
channelUrl : '//xxxx/channel.html', // Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// Here we subscribe to the auth.authResponseChange JavaScript event. This event is fired
// for any authentication related change, such as login, logout or session refresh. This means that
// whenever someone who was previously logged out tries to log in again, the correct case below
// will be handled.
FB.Event.subscribe('auth.authResponseChange', function(response) {
// Here we specify what we do with the response anytime this event occurs.
if (response.status === 'connected') {
// The response object is returned with a status field that lets the app know the current
// login status of the person. In this case, we're handling the situation where they
// have logged in to the app.
testAPI();
} else if (response.status === 'not_authorized') {
// In this case, the person is logged into Facebook, but not into the app, so we call
// FB.login() to prompt them to do so.
// In real-life usage, you wouldn't want to immediately prompt someone to login
// like this, for two reasons:
// (1) JavaScript created popup windows are blocked by most browsers unless they
// result from direct interaction from people using the app (such as a mouse click)
// (2) it is a bad experience to be continually prompted to login upon page load.
FB.login();
} else {
// In this case, the person is not logged into Facebook, so we call the login()
// function to prompt them to do so. Note that at this stage there is no indication
// of whether they are logged into the app. If they aren't then they'll see the Login
// dialog right after they log in to Facebook.
// The same caveats as above apply to the FB.login() call here.
FB.login();
}
});
};
// Load the SDK asynchronously
(function(d){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
/* js.src = "//connect.facebook.net/en_US/all.js"; */
js.src="https://connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
// Here we run a very simple test of the Graph API after login is successful.
// This testAPI() function is only called in those cases.
function testAPI() {
console.log('Welcome! Fetching your information.... ');
FB.api('/me', function(response) {
console.log('Good to see you, ' + response.name + '.');
});
}
</script>
<!--
Below we include the Login Button social plugin. This button uses the JavaScript SDK to
present a graphical Login button that triggers the FB.login() function when clicked.
Learn more about options for the login button plugin:
/docs/reference/plugins/login/ -->
<!-- <fb:login-button show-faces="true" width="200" max-rows="1"></fb:login-button> -->
<!-- End script of Facebook Login -->

Are you currently testing it from your local computer or hosting the HTML on a server?
if on a server - what is your domain?
update it on the app domains (see image)
update it on section "Website with Facebook Login"
for testing the issue, remove FB.api call from testAPI(). just put an alert.
test it from a standard browser. If it works - nothing is wrong with your FB definition.

Instead of FB.Event.subscribe
use FB.getLoginStatus
FB.getLoginStatus(function(response) {
if (response.status === 'connected') {
// the user is logged in and has authenticated your
// app, and response.authResponse supplies
// the user's ID, a valid access token, a signed
// request, and the time the access token
// and signed request each expire
var uid = response.authResponse.userID;
var accessToken = response.authResponse.accessToken;
FB.api('/me', function(response) {
console.log(response);
});
} else if (response.status === 'not_authorized') {
// the user is logged in to Facebook,
// but has not authenticated your app
} else {
// the user isn't logged in to Facebook.
}
});
Reference link: https://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus/

I stumbled across a different solution which is working really well for me, and even better, no native code libraries! The trick here is to bypass the Facebook JavaScript SDK library and use the Facebook REST api endpoints directly.
I am using OpenFB javascript library (https://github.com/ccoenraets/OpenFB) to make this job easier, rather than write the calls all myself, but you can do it either way. I've outlined the steps on how to get it to work below.
1) Create a Facebook app and update the URL settings under Basic and Advanced to allow callbacks using facebook or your local urls. Then copy the Facebook ID ready for the next step
2) If you haven't already, download and install Cordova to put the tools in your command line. Then navigate to your Sites folder and run the following commands to create the project and add your platforms:
cordova create your-project-name
cordova platform add ios
cordova platform add android
3) Now we need to add a Cordova plugin to handle pop-up windows from facebook logins. To add a plugin use the command:
cordova plugin add org.apache.cordova.inappbrowser
4) Now we just need to download and configure OpenFB inside our new Cordova project. For this example we will just use the test page they provide, so download it from the OpenFB Github page and extract the files into your cordova project /www/ folder. After this open the index.html and edit the following line with your Facebook App ID from step 1:
openFB.init({appId: 'YOUR_FB_APP_ID'});
5) You should now be able to run the example and login using your local browser setup.
6) To test on iOS simulator you will need xCode installed then run the command:
cordova emulate ios
To test on an android emulator you will need the Android SDK installed and then run the command:
cordova emulate android
To test on an iOS device connected with a cable, run following command:
cordova run ios
To test on an Android device connected with a cable, run following command:
cordova run android

Related

Facebook Canvas, Unable to login from facebook on mobile devices

I have a canvas facebook application which has both a web page and a designated mobile page.
The web page works fine and also when simulating the browser to mobile with the console everything works fine.
But, when I try to run the app from the facebook mobile app the canvas app loads (which is correct), but it does not login.
I am using the FB.login function.
login: function () {
var deferred = $q.defer();
FB.login(function (response) {
if (!response || response.error) {
deferred.reject('Error occured');
} else {
deferred.resolve(response);
}
}, {
scope: 'email, user_friends'
});
return deferred.promise;
},
and in the settings > advanced - I have the:
Client OAuth Login,Web OAuth Login, Embedded Browser OAuth Login,Valid OAuth redirect URIs and Login from Devices filled correctly.
but still from the facebook mobile app the canvas app does not preform the login.
I have been trying to get this to work all day.
and I cant find a solution anywhere.
I also cant debug the mobile facebook app.
any ideas how to approach this issue?
EDIT
Also looked at my Node server logs and I see that the FB.login is not even called.
EDIT 2
I ended up replacing the login with getLoginStatus which poses no problem to me since its a facebook canvas app... but the question still remains on how to do the login.
EDIT 3 11/26/2015
well so getLoginStatus did not completely solve my issue since it does not in fact log the user in so for the canvas games you probably need to login for the first entry if you need permissions... my solution was to add the login if the getLoginStatus returns not_autorized like so:
/**
* [getLoginStatus get the FB login status]
* #return {[type]} [description]
*/
getLoginStatus: function () {
var deferred = $q.defer();
FB.getLoginStatus(function (response) {
if (response.status === 'connected') {
deferred.resolve(response);
} else if (response.status === 'not_authorized') {
_fbFactory.login().then(function (fbLoginResponse) {
deferred.resolve(fbLoginResponse);
});
} else {
deferred.reject('Error occured');
}
});
return deferred.promise;
},
But wait, there is more... the FB.login function will not work well on mobile canvas games (not sure if its just not triggered or the browsers blog the popups or both). anyway you need to actively call it via button... so for mobile canvas games I had to add a start playing button and then the login does work..
EDIT 4 (Final)
eventually I noticed that FB.login() does not get triggered unless its an external event that triggers it, so I had to make a change for Mobile canvas where if the getLoginStatus doesnt return connected then I show a login button which does the login... the rest stayed the same.
what I did for mobile was similar to the accepted answer only to suit my needs...
I hope this helps someone besides me...
Make sure you're calling FB.login() with an event triggered by the user, such as an onclick on a button, as browsers can block potentially unsafe/dangerous javascript that's called directly. This is an extra layer of security for the end-user. There's 2 ways to create a login button:
Generate a login button with facebooks login button generator:
https://developers.facebook.com/docs/facebook-login/web/login-button
The generated login button will look similar to this:
<fb:login-button scope="public_profile,email" onlogin="checkLoginState();">
</fb:login-button>
Create your own html and use an onclick event to call FB.init():
<button onclick="FB.init()">Login</button>
Notes from the Facebook developers website:
As noted in the reference docs for this function, it results in a
popup window showing the Login dialog, and therefore should only be
invoked as a result of someone clicking an HTML button (so that the
popup isn't blocked by browsers).
https://developers.facebook.com/docs/facebook-login/web
Also, FB.getLoginStatus is the correct first step in logging in to check whether your user is logged into facebook and into your app.
There are a few steps that you will need to follow to integrate
Facebook Login into your web application, most of which are included
in the quickstart example at the top of this page. At a high level
those are:
Checking the login status to see if someone's already logged into your app. During this step, you also should check to see if someone
has previously logged into your app, but is not currently logged in.
If they are not logged in, invoke the login dialog and ask for a set of data permissions.
Verify their identity.
Store the resulting access token.
Make API calls.
Log out.
I see that your game doesn't require a login anymore, but maybe others will find this answer useful. :)

Javascript Facebook SDK: how to really log out?

First of all: I'm aware that there's plenty of questions about the same topic, but none of them did the trick for me (I've already been like 3 days trying to get this working)...
I'm working on a Javascript mobile game which includes some FB functions (through the Javascript Facebook API). I'm having trouble while trying to really log out from Facebook to log in with another user: everytime I log out, I expect to call the log in function and prompt the FB login dialog where I can specify my e-mail and my password, but instead of this, Facebook logs in automatically with the last user without even asking me for anything... I'm using CocoonJS as the mobile platform and plain Javascript (no jQuery):
Log in function:
CocoonJS.Social.Facebook.init({
appId:<<MYAPPID>>,
channelUrl: "channel.html"
});
var socialService = CocoonJS.Social.Facebook.getSocialInterface();
socialService.login(function(loggedIn, error) {
if (error) {
console.error("login error: " + error.message);
}else if (loggedIn) {
console.log("login suceeded");
// Ask for extended permissions
CocoonJS.Social.Facebook.requestAdditionalPermissions("publish", "publish_actions",
function(response)
{
callback(response.error ? false : true);
}
);
CocoonJS.Social.Facebook.getLoginStatus(function(response) {
if (response.status === 'connected')
{
CocoonJS.Social.Facebook.api(
"/me",
function (response) {
if (response && !response.error) {
// Getting "me" returns the information of the "same" user!
console.log("User: "+response.first_name+" "+response.last_name);
}
}
);
}
});
}
});
Log out function:
CocoonJS.Social.Facebook.getLoginStatus(function(response) {
if (response.status === 'connected')
{
CocoonJS.Social.Facebook.logout(function(response) {
console.log("User logged out!");
});
}
});
The console log is thrown, so it seems that the user has actually logged out, but when I restart the game, a kind of "I'm doing something" screen appears for less than a second and the same user who logged out is logged in again (even throwing their personal information through calling "me")... I was expecting Facebook to ask me with which user I would like to log in to my app, but it doesn't...
I thing it has something to do with "session" or "cookies", but I don't know how to clear them through Javascript (and, as I'm using CocoonJS as the "browser", I have little control over it)... Any idea?
Thanks in advance for your time and effort! :)
CocoonJS uses native iOS and Android Facebook SDKs. The SDK itself takes care of the session storage, no cookies are used in CocoonJS.
Facebook SDK has two different methods to close the session:
close(): Closes the local in-memory session object, but does not clear the persisted token cache.
closeAndClearTokenInformation(): Closes the in-memory session, and clears any persisted cache related to the session
CocoonJS.Social.Facebook.logout calls internally to closeAndClearTokenInformation on Android and iOS. It erases all the cached tokens, so the next login starts from scratch.
Facebook SDK uses the Facebook Application to handle the login process if it's installed on the device, otherwise it fallbacks to a webview based login. The problem may be that you are testing on a device with the Facebook Application installed, so the SDK is able to get the logged in user from the Facebook App and doesn't need to ask for it again. If you logout from the Facebook Application or you test your app on a device with no Facebook App, Facebook will ask for a user and password.

FB.getLoginStatus returns status unknown

When calling FB.getLoginStatus using a valid Facebook App the response status is always unknown. Exact response is {authResponse: undefined, status: "unknown"}.
<html>
<body>
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function(){
FB.init({ appId:'1484134468466778', status:true, cookie:true, xfbml:true});
FB.getLoginStatus(function(response){
console.log(response);
});
};
(function(d){
var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
d.getElementsByTagName('head')[0].appendChild(js);
}(document));
</script>
</body>
</html>
Example URL:
http://media.tuentifotos.com/simple_test.html
Here a screenshot of the Facebook App Settings.
This was happening for me in Chrome, and was because Chrome was configured to block third-party cookies and data.
Once I made that configuration change, FaceBook is able to log me into my app without a problem.
Chrome Settings
Show advanced settings...
Privacy
Content settings...
uncheck Block third-party cookies and site data
I too faced this problem in Chrome. However, in Firefox it worked as expected with the status returned as connected when the user had logged in previously.
I found a clue about this from an answer to the similar question here.
The root cause of this issue is, on FB.logout(), Chrome is not removing the cookie fblo_<your-app-id> which is somehow affecting FB.getLoginStatus() function to return unknown
Fix: On calling FB.logout(), you may programmatically delete the cookie fblo_<your-app-id>
FB.logout(function(response) {
deleteCookie("fblo_" + fbAppId); // fblo_yourFBAppId. example: fblo_444499089231295
});
function deleteCookie(name) {
document.cookie = name +'=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
}
When I checked, the status is showing "not_authorized" and that's fine, since I've not authorized the app yet.
To complete the flow, you should add the FB.login whenever user id is not authorized or not logged-in to facebook:
window.fbAsyncInit = function(){
FB.init({ appId:'{APP-ID}', status:true, cookie:true, xfbml:true});
FB.getLoginStatus(function(response){
if (response.status === 'connected') {
//proceed
} else if (response.status === 'not_authorized') {
login();
} else {
login();
}
});
};
function login(){
FB.login(function(response) {
if (response.authResponse) {
// proceed
} else {
// not auth / cancelled the login!
}
});
}
For me this meant "on my login page" I needed to specify cookies.
window.fbAsyncInit = function() {
FB.init({
version: 'v2.8',
cookie : true,
});
};
But don't ask me why this was the case. It also fixed it needing to click twice on the login button to actually login, and doesn't even require an appId, seemingly, FWIW...
The final answer
Ok so I think I've finally figured this damn issue out.
What you need to know:
1) You authenticate with Facebook via an app ID. This sets various cookies, where your app ID is tagged on the end:
fblo_000000000000
fbm_000000000000
fbsr_000000000000
2) If you delete these cookies, you're still authenticated to facebook as a regular user (unless you log out completely). And on Facebook's servers they still know you are authorized on this app.
So when you run FB.getLoginStatus() again it will just recreate them and put them back again. This is not what your user expects. This is bad. They clicked 'Log out'.
3) The docs explicitly say this:
The user is either not logged into Facebook or explicitly logged out of your application so it doesn't attempt to connect to Facebook and thus, we don't know if they've authenticated your application or not. (unknown)
So they don't even TRY to check if this cookie is set. That's why you get null or undefined. So the fblo cookie is considered like an 'opt-out'. You're NOT ACTUALLY LOGGED OUT by what any regular person would consider being logged out as to mean. There's just a cookie saying you are! Of course if the user logs back in with the login button then the cookie will be deleted, which is what you and your user wants.
Therefore I believe the only thing that makes sense to do (if you truly need to know the user's status) is to:
Manually check the existance of fblo_<APPID> cookie before you run FB.getLoginStatus.
If the cookie doesn't exist then do nothing and run your normal flow.
If the cookie does exist you have several options :
1) Option 1
Do absolutely nothing. You now understand the issue, you understand not to delete the cookie and perhaps you don't need to do anything other than show the Facebook login button.
2) Option 2
You assume the person is a user of your app, and do whatever you need to do to show the UI. But you won't be running your full normal logic - this will be application specific to you .
3) Option 3
Manually set the cookie value fblo_<APPID> to n (instead of 'y'). Remember this cookie is set on your domain so you're allowed to change it. *Depending upon your development environment this will vary, but it needs to be done client side, and you may need to specify path of `/' and your cookie domain).
Run the getLoginStatus(..., true) - it will not be blocked now because the cookie is now n. However you must not run your normal logic here - because all you want to do is check if the user is actually a Facebook user and/or still authenticated with your app.
Manually set the cookie value back to y
Unfortunately I can't recommend this solution due to weird race conditions. It almost almost works, but FB could deliberately or accidentally break it at any time - and it actually ends up still getting confused thinking you're really logged in when you aren't. Plus it could have all kinds of complications with other plugins I haven't even observed.
I wish the getLoginStatus would just always run and give accurate information, but this is the only true solution I see. And it's been this way for 8 years so I think we're stuck with it.
4) Option 4 - Set your own cookie
You always have the option to set your own cookies to indicate certain things, like 'this user has at some point logged into Facebook' or 'this user is authenticated with my app'. But I'm cautious about doing this because it can quickly get complicated.
Incidentally I revisited this issue because I'm using the Messenger plugin for my website and I don't want it to display at all unless I know the person has a Facebook account. So I need an accurate response to login status.
This was happening to me until I turn on my browser to allow third-party websites to save and read cookies.
To do this go to
settings > advanced > site settings > Cookies and site data
Then uncheck the option blocking third-party websites from saving and reading cookies.
This might not be a good option but it solves these issues for me.
You just need make your site URL from http to https
DO NOT use http
I had the same issue in IE. Flimzy's answer got me thinking. I tried running IE as administrator and it worked.
I had the same problem, I fixed this by clearing all cache and cookies.
You have to test it from the live domain (which you provided in the app).
I had the same problem when testing locally (using local domain).
In my case I was using Brave browser which didn't allow cookies due to which it was giving status unknown. I switched to chrome and now it is working.

Receiving signed_request using Facebook JS SDK and Meteor

I am trying to build a facebook page tab application using Meteor and have spent an ungodly amount of time just trying to receive a signed_request using just JS. This is incredibly easy using php but I can't use php inside of a Meteor app.
I'm loading the JS SDK within my if (Meteor.isClient) {} Section and it appears to be working. I've tried using FB.Login to get the information I need (Has User Liked Page, Is Admin, ect) but I can't seem to get it working. With page tab applications a user doesn't need to authenticate the app it just runs. The admin is the only that authenticates while installing I think... I can't find anything helpful perusing the Facebook Developer section on creating a facebook page tab application using the JS SDK. Please Help!
Some of my code...
if (Meteor.isClient) {
Template.fbconnect.connect = function () {
if (!Session.get("is Facebook JDK loaded?")) {
Session.set("is Facebook JDK loaded?", true);
// https://developers.facebook.com/docs/reference/javascript/
window.fbAsyncInit = function() {
// init the FB JS SDK
FB.init({
appId : 'Removed', // App ID, Took away for online question
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// Additional initialization code such as adding Event Listeners goes here
FB.getAuthResponse(function(response) {
if (response.status === 'connected') {
console.log(response.session.access_token);
} else {
console.log('User cancelled login or did not fully authorize.');
console.log(response.session.access_token);
}
}, {scope: 'email,user_likes'});

Android app login

There are some apps that require login. May I know how the app manage user session on android? For example, once the user has sign in to the app, the next time user start the app, it will straight go to the home page instead of the login page. While if user start the app for the first time or before login, the app will start with the login page. Can phonegap handle this? Thank you.
Depending on which version of Android you are targeting and which version of PhoneGap you are running, you should use one of the built-in offline storage mechanisms available in the browser. These include localStorage and WebKitSQLite.
There is also a fantastic open source library that you can use that abstracts any specific offline storage mechanism and allows for swappable underlying storage adapters, and provides a single unified key/value interface. The library is called Lawnchair - check it out!
So on-load, you would instantiate Lawnchair and see if your saved user parameters exist:
function onLoad() {
myStore = new Lawnchair();
myStore.get('login', function(i) {
if (i == null) {
// user did not login before, no saved credentials.
} else {
// user DID login, we can now auto-login for the user.
}
});
}
Additionally, following a successful manual login, you can save the credentials to Lawnchair so that they will be available next time your PhoneGap app loads and checks for their existence:
function login(username, password) {
/*
* Do the login stuff here
*/
if (/* login was successful */) {
myStore.save({key:'login',value:{username:username, password:password}});
} else {
alert('Could not log you in!');
}
}
The most important bit between the two chunks of code you see here is the first parameter to the get() function, and the key property to the object passed into the save() function. Both of these need to match to retrieve the same object.
Hope that helps!
You can store it in the prefs. Here is how
SharedPreferences settings = .getSharedPreferences("some_key, MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
editor.putString("token", "123456");
editor.commit();
Next time the app starts up you can check to see if this exists. Hope it helps
Don't know what is phonegap, but I think usually apps simply store the login somewhere in shared preferences. So, all you need is to check on startup if there is some particular preference. If there isn't any, then the login page should be shown.

Categories