Facebook 3.1.1 SDK breaks A LOT

@olav.morkrid,

I think returning the error code indicating that the user revoked the permission is the right thing to do instead of logging back in to the user’s account automatically. As a user of an app if I revoke permission, it may mean I don’t want your app to access my account. Your app should recognize that and ask the user if he/she still wants to enable Facebook.

Maybe we can handle things better but going through the extra steps should be required (just my opinion).

Not all Facebook 400 errors are because of problems in Corona. From searching the Internet, that error is a general error for things Facebook doesn’t like (e.g., posting to many times within a short period of time). I’m still looking into the errors that have been reported here so I haven’t ruled anything out yet.

@haakon,
It’s my view that logging out of Facebook using the Corona logout API just affects the Corona app. Facebook’s SSO (single sign on) means it uses the current account that’s active on the device. If you are signed into one Facebook account using the Facebook app, I wouldn’t expect signing out of a Corona app would sign you out of the Facebook app. You would need to sign out of your account (Facebook app) to sign into another account with the Corona app. I believe this is built in to the Facebook SDK.

Like I said before, we are still looking into this.

-Tom [import]uid: 7559 topic_id: 34416 reply_id: 141260[/import]

Tom, I tested this just now using the xcode simulator. It has no Facebook app. I also checked under Settings => Facebook, and I have no credentials entered there. I know our support is getting asked about this frequently, so it’s obvious that the users too expects logout to make it possible to use a different Facebook account when logging in again.

I’d say this needs to be handled by Corona. [import]uid: 21746 topic_id: 34416 reply_id: 141262[/import]

And here’s how you should implement it:

http://stackoverflow.com/questions/13457625/facebook-ios-sdk-logout

You need to clear the safari cookie when facebook.logout() is called.

EDIT - there is a sample project in the facebook sdk download, “SwitchUser” that may give you an idea:

"From your context, I’m assuming your device(s) does not have the Facebook app installed nor do you expect to use iOS 6 system authentication which would leave the default login behavior to use Safari. If you were to clear the Safari cookies, that should work but for a smoother experience in your scenario you should use the FBSession openWithBehavior:completionHandler: method and specify a behavior of FBSessionLoginBehaviorForcingWebview so that it uses the inline webview dialog for authentication.

See the SwitchUserSample in the Facebook iOS SDK for an example since that sample demonstrates an app that can toggle between multiple accounts." [import]uid: 21746 topic_id: 34416 reply_id: 141264[/import]

Regarding the Error 400 caused by posting too many times within a short period of time, I believe it isn’t the cause for CASE 5 or CASE 7. If it is, then why will it not trigger the error again after restarting the app? For example, once the app gets error under CASE 7 and the app is restarted, posting high score one after the other does not trigger Error 400. Every high score gets posted to FB and friends scores are retrieved every time thereafter.

BTW, I found that wiping the device is not necessary for this error to occur. I moved on to install the app, go through CASE 7, restart the app and normalize the app, and then delete the app (without logging out of FB and without de-authorizing the app from the user’s Facebook account,) reinstall the app, go through CASE 7 again, and the exact same error occurs in the exact same way.

Naomi

[import]uid: 67217 topic_id: 34416 reply_id: 141268[/import]

@Tom: Maybe I was unclear. I’ll try to explain my view on this again:

If access is revoked, and the user tries to use Facebook functionality, then the user should be presented with Facebook’s standard “Do you want to grant access to this app?” again, without any unnecessary or confusing error dialogs or failures of any kind.

It should be just like the first time the user tries to couple the app with his Facebook account: The standard “Grant access” page should be presented, because after all, the user tries to use something with Facebook, so that must mean he changed his mind, and wants to access Facebook even though he revoked access earlier on, and thus we should help him proceed.

[import]uid: 73434 topic_id: 34416 reply_id: 141269[/import]

I implemented this myself in our nativefacebook enterprise plugin that contains a lot of missing Corona=>Facebook implementations. Works like a charm. [import]uid: 21746 topic_id: 34416 reply_id: 141270[/import]

This is very frustrating! This bug (20096) was filed on January 9th and reported as soon as build 993 came out which implemented the Facebook 3.1 API.

We have received no fix for this or a date for when it might be fixed. We have received no workaround or working sample code.

This is a showstopper for us. We have a game pretty much ready to go except we can’t get around this bug.

I don’t believe this is a Facebook bug. I believe it’s a Corona bug.

Please, Corona, assign somebody to this that can fix it.

Thank you,
Christopher Bodine
President, CloverLeaf Mobile Apps
http://www.cloverleafmobile.com [import]uid: 120928 topic_id: 34416 reply_id: 142001[/import]

Looks like this bug will be just as badly handled as the Android Push Notification feature was “back then”.

I suggest that you rely on facebook.showDialog() for everything related to posting stuff. Getting a user’s friends or extra user info is not requiring any permissions. If you need extra user info in /me, you can set that up on developers.facebook.com in your app.

The main things you’ll be missing is the ability to post photos, post on behalf of the user on his/hers friends wall (it’s already deprecated by Facebook, so that possiblity is about to go away). And if you have a server that posts achievements, scores etc on behalf of the user, that wont work without the publish_actions permission. The final part is what we miss the most => we’ve seen a dramatic change (negative) in user activity and reach after we lost that possibility.

If you are an Enterprise user you can implement the native share dialog to fix the photo posting issue.

I’ll be writing a brand new facebook integration for Corona next week to get the publish permissions working again, since it’s an important part of our marketing strategy. We can concider selling that plugin to other (frustrated) devs in the need of a working facebook integration. But you’ll need Enterprise to use it. [import]uid: 21746 topic_id: 34416 reply_id: 142005[/import]

I agree with Christopher @cebodine. This bug is a show stopper for me too. It really destroys Facebook aspect of the app. At this point, I’m sure it’s Corona bug (not Facebook SDK bug, especially since haakon was able to fixed it with his version of FB SDK integration.)

I could use 990 as a stop gap measure – perhaps get Apple to approve the app ahead of time and then do a quick update before releasing the app, but it really is going to be a very short term solution, especially since there are a whole host of other bugs that’s been fixed since 990. I definitely need to use latest build for the final release that includes additional monetization features (such as iAds, RevMob, Chartboost, if ever it becomes available, etc.) Besides, I think using latest build is absolutely necessary for the Android version (again due to number of bug fixes that went in since 990.)

So, I’d very much like to know where we are at with this bug. Please?

Naomi [import]uid: 67217 topic_id: 34416 reply_id: 142007[/import]

@Naomi - Tom asked you to continue the discussion per e-mail. What happened with that? Was it just an attempt to silence this thread and hope that the community stopped asking for a fix? That’s funny :slight_smile: [import]uid: 21746 topic_id: 34416 reply_id: 142008[/import]

@haakon, I sent him a few emails detailing my finding but I have not heard back from him. Maybe my email wasn’t helpful? Because I thought I found the fix, and then it turned out it was a false alarm? I dunno.

BTW, the publish_actions permission is required for FB Score API too. Even though I use showDialog for posting anything on friend’s wall, I still need publish_actions permission to post user’s high score and retrieve friends’ high scores. There’s no way around it (short of begging users to restart the app as soon as they sign in to FB – which is not an option at alll, honestly.)

Naomi [import]uid: 67217 topic_id: 34416 reply_id: 142010[/import]

I sat down to crack this thing, and have made a completely new implementation of facebooking for Corona. No need to own enterprise or anything, just copy this and use it instead of your old lua code.

I did not bother to change any of the code, so this is how we’re using it. You need to clean it up and make adjustments for yourself.

We’re giving NO SUPPORT for this piece of code! :slight_smile:

With this Facebook implementation, you’ll get the publish_actions permission from the user and will be able to post photos, scores, achievements etc. No more facebook sdk error #5.

So why does this work? By checking the access_token validity with facebooks open graph server, we’re able to know if the access token is ok to use or not. If it is ok, then we can skip the login phase completely. Second, if the token is _not_ valid, we can clean up our facebook variables, logout the user (logout is not a global function in terms of Corona Facebooking, but app-sandboxed), and pop up the auth dialog.

How to use?

FaceSingleSignon(your\_listener)  
local obj = {  
 message = "Message",  
 source = { baseDir=system.TemporaryDirectory, filename="image.png", type="image" }  
}  
FacePublishPhoto(obj)  
local facebook = require("facebook")  
local appId = "YOUR APP ID"  
local fbListener  
local fbCommand  
local fbData  
local fbCallback  
local fbId  
  
local LOGOUT = 0  
local POST\_MSG = 1  
local POST\_PHOTO = 2  
local GET\_FRIENDS = 3  
local INVITE\_REQUEST = 4  
local SINGLE\_SIGNON = 5  
local FEED\_GAME = 6  
  
local function printTable( t, label, level )  
 if label then print( label ) end  
 level = level or 1  
 if type(t) ~= "table" then  
 t = json.decode(t)  
 end  
 if t then  
 for k,v in pairs( t ) do  
 local prefix = ""  
 for i=1,level do  
 prefix = prefix .. "\t"  
 end  
  
 print( prefix .. "[" .. tostring(k) .. "] = " .. tostring(v) )  
 if type( v ) == "table" then  
 print( prefix .. "{" )  
 printTable( v, nil, level + 1 )  
 print( prefix .. "}" )  
 end  
 end  
 end  
end  
  
if simulator then  
 facebook.login = function()  
 native.setActivityIndicator(false)  
 ui.newNotification("Facebook not available in simulator...", "error")  
 end  
else  
 local old\_login = facebook.login  
  
 facebook.login = function(appId, params)  
 if not \_G.access\_token then  
 print("Got no access token")  
 old\_login(appId, fbListener, params)  
 else  
 network.request("https://graph.facebook.com/me?access\_token=" .. \_G.access\_token, "GET", function(event)  
 printTable(event, "facebook.login")  
 if not event.isError then  
 local data = event.response or "{}"  
 data = json.decode(data)  
  
 if data and data.error and data.error.type == "OAuthException" then  
 print("OAuthException")  
 \_G.access\_token = nil  
 facebook.logout()  
 old\_login(appId, fbListener, {"publish\_actions"})  
 return false  
 else  
 -- Everything ok! We'll completely skip the login phase by hacking Coronas native implementation  
 fbListener({type = "session"})  
 end  
 else  
 -- Something unexpected happened, go ahead with a regular login  
 print("Face, unexpected error")  
 old\_login(appId, fbListener, params)  
 end  
 end)  
 end  
 end  
end  
  
fbListener = function(event)  
 if ("session" == event.type) then  
  
 if event.phase == "logout" then  
 return false  
 end  
  
 -- Save Access Token  
 if event.token then  
 \_G.access\_token = event.token  
 end  
  
 if fbCommand == FEED\_GAME then  
 facebook.showDialog("feed", fbData)  
 end  
  
 if fbCommand == POST\_MSG then  
 facebook.showDialog("feed", fbData)  
 end  
  
 if fbCommand == POST\_PHOTO then  
 facebook.request("me/photos", "POST", fbData)  
 end  
  
 if fbCommand == GET\_FRIENDS then  
 facebook.request("me/friends", "GET", {fields = "id, name, installed"})  
 end  
  
 if fbCommand == INVITE\_REQUEST then  
 facebook.showDialog("apprequests", fbData)  
 end  
  
 if fbCommand == SINGLE\_SIGNON then  
 facebook.request("me", "GET", {fields="id,username,name"})  
 end  
  
-----------------------------------------------------------------------------------------  
  
 elseif "request" == event.type then  
 native.setActivityIndicator(false)  
  
 if not event.isError then  
  
 local response = json.decode(event.response)  
 if response then   
 if fbCommand == POST\_MSG then  
 ui.newNotification(t("notification.facebook\_message\_posted"))  
  
 elseif fbCommand == POST\_PHOTO then  
 ui.newNotification(t("notification.facebook\_message\_posted"))  
  
 elseif fbCommand == GET\_FRIENDS then  
 fbCallback(response)  
  
 elseif fbCommand == SINGLE\_SIGNON then  
 fbCallback(response)  
  
 end  
 else  
 ui.newNotification(t("notification.facebook\_request\_failed"), "error")  
 end  
 else  
 -- Error  
 facebook.logout()  
 ui.newNotification(t("notification.facebook\_request\_failed"), "error")  
 fbCallback = nil  
 fbData = nil  
 fbCommand = nil  
 end  
 elseif "dialog" == event.type then  
 native.setActivityIndicator(false)  
  
 if event.didComplete == true then  
 if fbCommand == FEED\_GAME or fbCommand == POST\_MSG then  
 if string.find(event.response or "", "fbconnect://success?post\_id=", 1, true) then  
 ui.newNotification(t("notification.facebook\_message\_posted"))  
 end  
  
 elseif fbCommand == INVITE\_REQUEST then  
 local status = "success"  
 if ios and not string.find(event.response or "", "request=", 1, true) then  
 status = "error"  
 end  
 fbCallback(status)  
 end  
 end  
  
 fbCallback = nil  
 fbData = nil  
 fbCommand = nil  
  
 end  
end  
  
-- Publish a feed  
function FacePublishFeedGame(data)  
 fbCommand = FEED\_GAME  
 fbData = data  
 facebook.login(appId)  
end  
  
function FacePublishFeed(data)  
 fbCommand = POST\_MSG  
 fbData = data  
 facebook.login(appId)  
end  
  
function FacePublishPhoto(data)  
 fbCommand = POST\_PHOTO  
 fbData = data  
 facebook.login(appId)  
end  
  
function FaceInviteFriends(data, cb)  
 fbCommand = INVITE\_REQUEST  
 fbData = data  
 fbCallback = cb  
 facebook.login(appId)  
end  
  
function FaceGetFriends(cb)  
 fbCommand = GET\_FRIENDS  
 fbCallback = cb  
 facebook.login(appId)  
end  
  
function FaceSingleSignon(cb)  
 fbCommand = SINGLE\_SIGNON  
 fbCallback = cb  
 facebook.login(appId, {"publish\_actions"})  
end  
  
function FaceLogout()  
 \_G.access\_token = nil  
 facebook.logout()  
end  
  
end  

Enjoy a working Facebook implementation again! [import]uid: 21746 topic_id: 34416 reply_id: 142075[/import]

Hey, Haakon, thank you for posting this. I’ll give it a shot and see if it works for what I need to do with mine. I appreciate you sharing your code.

Thanks again.

Naomi

Edit: Haakon, unfortunately, your workaround doesn’t work for my FB login/request flow… The initial FB login through the series of request (connecting to FB, retrieving me, posting score, retrieving app/score) works, but all subsequent requests do not work (not only retrieving me/friends or posting with showDialog but any new round of posting high score and retrieving app/score), which basically kills FB feature. In my case, with this workaround, restarting the app doesn’t fix the FB issue the way it did before. I’m still better off reverting back to how it was before. It works perfectly fine with 990, and with 1025, killing the app once fixes the issue (although, it really isn’t an option for Apple submission candidate.) That said, I’m glad it works for you. It could be that I didn’t implement your workaround exactly how it should be done, but then, my app is different from yours, and it goes through different steps. Please note, FB issue only occurs on specific FB login/request flow, i.e., CASE 5 and CASE 7. If the user logs in with permission in a separate scene from where subsequent FB login/requests take place, my app does not trigger any FB error. [import]uid: 67217 topic_id: 34416 reply_id: 142102[/import]

@Naomi, the things you say about scenes really don’t make any sense to me. The class above should be referenced in your main.lua file, and you should keep a global variable for the access_token.

main.lua

face = require("Face")  
access\_token = nil  

If you keep the code I posted as it is (but remove ui.newNotification or replace it with prints, showAlert or something else), and adds in your own shorthand functions for stuff like FacePostScore etc, using the same code style as I have done, it should work fine.

I’m quite sure you have done something to the code that makes it break, there’s no reason it should break if you stick to the patterns in my code. Don’t change facebook.login = function, for instance. That override is there by purpose. [import]uid: 21746 topic_id: 34416 reply_id: 142138[/import]

@haakon, thank you for the note. I do use a variable for access_token that is not global but accessible from any scene that I need to retrieve the token for (and I override and re-save a new token if/when FB listener returns valid event.token just to make sure.) I also require facebook as local function in each module where facebook is called for. Perhaps making it global is necessary, and maybe that’s the whole problem I encountered with your workaround…

But then, it still doesn’t make much sense, because the entire workaround I implemented takes place inside a single module/scene, and I call facebok.login with permission only once (and only if/when there’s no access_token.)

Hmmm… as I was writing, I generated a new built with the pre-workaround code. Very odd. Native alert message pops up upon initial login – which is rather very strange. I attributed this native alert to your workaround, but perhaps its something else. I built my app and tested CASE 5 & CASE 7 using daily build 990 and 1013 previously. This morning, however, I downloaded daily build 1025 (and deleted 1013) before implementing your workaround. And then I get this native alert message, and other issues. So, I reverted back to my pre-workaround code and built my app again… and it still brings up this native.alert… I thought it was your workaround that caused it to show up, but maybe it’s the latest daily build that does it, and whatever else is odd about it may have something to do with it too? I don’t know. I’ll try CASE 7 with 990 and 1013 (using my pre-workaround code.) And if it behaves the way I’m familiar with, I’ll try your workaround and see if works with daily build 1013. How confusing…

Naomi [import]uid: 67217 topic_id: 34416 reply_id: 142145[/import]

Okay, I get same native alert with both daily build 990 and 1013, plus errors that previously did not exist.

It turns out it has something to do with installing it on iOS6.1 device. The app built with iOS SDK 6.0 via daily build 990 spits out the very same errors when installed on a device with iOS6.1.

The app works only if I build it with daily build 990 and install it on a device with iOS 6.0 (or pre-iOS 6.0) At this point, I don’t have an app with FB feature that runs without any error on iOS6.1 device. Yikes. This is a major setback. Back to code review – and I really have to work on getting Haakon’s workaround working with daily build 1025 – otherwise, my app submission is not happening.

EDIT: The strange native alert was something to do with testing on a device that has already FB approved (via a version of an app built with iOS6.0 SDK). Instead of wiping the device, I simply deleted the app and then installed a new version of the app built with iOS6.1 SDK – this triggered this strangeness and inexplicable errors that I could not work around. Once I wiped the device (by resetting all content) and installed the new version of the app built with iOS6.1 SDK, the odd alerts and error messages went away – meaning, once I clean slated the devices (both iOS6.0 device and iOS6.1 device), the app built with 1025 returned back to the behavior I observed in CASE 5 & CASE 7, and yes, restarting the app does fix the Facebook issue and normalize the app. (The strange errors would’ve been worrisome if I had an already released app built with pre-iOS6.1SDK that desperately needed the update/fix with the new Facebook SDK.)

The next step – if I got the energy and can put aside some time for it, I might just go ahead and create a test project that only include main.lua with code that demonstrates CASE 7 (and perhaps I’ll send it in to Corona in case that helps identify where our trouble lies.) And then, I may proceed to convert the test project to include Haakon’s work around. If the work around works in the reworked version of the test project, then I have a reason to further rework my app – and perhaps send the reworked test project to Corona too so that they may finally get around to fixing the issue…

EDIT 2: I filed Case 20794 with the test project that demonstrates CASE 7 (tested with daily build 1025 on both iOS 6.0.1 and iOS 6.1 devices). The test project is stripped down to the core FB mechanics that fails. In the process, I found that if I install the test app on cleanly wiped device, it normalizes after I restart the app upon encountering the HTTP 400 error and other FB failures. Once it normalizes, the FB feature works flawlessly. However, if I delete the app from the device, and reinstall the very same app, the FB feature is completely destroyed, and the app becomes utterly dysfunctional. [import]uid: 67217 topic_id: 34416 reply_id: 142154[/import]

I hope you don’t mind me jumping into this thread…

I’ve been reading this thread over and over with a lot of interest (thanks Naomi and haakon), but I am unsure what I need to do to make my app play nice with Facebook.

I want to add a Like button, wall posting, and maybe a way to grab friends for a challenge mode in my app (that depends on what Game Minion will deliver I guess), and I am unsure what build to use, what params to pass to FB, and what return and/or error values to expect.

Even in simpler times, facebook integration was something I wasn’t sure about successfully implementing. With my new app, I need to add more fb features, and now I am just completely confused.

Will there be an improvement in the builds to handle this (soon)? If not, what’s the solution? I also tried the GGFacebook library with limited success… perhaps whatever happened also affected this library?

FB integration is almost a must now, so any help sorting this out woudl be great. [import]uid: 114363 topic_id: 34416 reply_id: 142285[/import]

Hi, Tom, where are we with this? Do you think the HTTP Error 400 issue would be fully addressed anytime soon, or do you recommend I seriously consider reverting back to daily build 990? Not so far in the distant future (meaning definitely this month, and perhaps within the next couple of weeks), I’d like to finalize and submit my app for release.

If I can’t expect this error to be fixed (or Corona side to come to some sort of resolution) sometime this week, I would need to revert back to 990 and test the app thoroughly to ensure nothing is breaking as I finalize the app. So please please please let me know the status of things.

Thanks,
Naomi

P.S. If you need more information as to where and how things break, please give me a shout. I’m more than happy to help getting this issue resolved. [import]uid: 67217 topic_id: 34416 reply_id: 141593[/import]

Just an update on this issue. We understand this is a major issue and we are looking into this problem now and hope to have a resolution very soon.

Thanks,
Tom [import]uid: 7559 topic_id: 34416 reply_id: 142418[/import]

Naomi (and Tom),

By accident I tried to post a payload to facebook.request that had illegal content. It actually led to the problems described in this thread, the facebook error 5.

I know for sure my implementation works fine, we have tested it extensively for several days. So Naomi, I’m thinking that you are maybe posting some data that is not valid since you’re still getting the error.

You can test it by trying to issue a post to me/photos with this payload:

WORKS

local obj = {  
 message = "Corona SDK",  
 source = { baseDir=system.TemporaryDirectory, filename="image.png", type="image" }  
}  
FacePublishPhoto(obj)  

FAILS with error and causes a lot of trouble

local obj = {  
 message = "Corona SDK",  
 source = 'http://www.coronalabs.com/wp-content/uploads/2012/06/Built\_with\_Corona\_SM.png',  
}  
FacePublishPhoto(obj)  

My point is, if you have a payload that does not validate, Corona handles the error from Facebook horribly. It completely destroys the facebook functionality in Corona. Which is what is happening for you, Naomi. I’d like to see that test project you created, would you mind sending it to me? haakon ÆT monkeybin.no [import]uid: 21746 topic_id: 34416 reply_id: 142422[/import]