4
votes

I'm developing a hybrid app with angular and ionic for iOS and Android and I have come upon an error when posting with an image to facebook. The error only appears when I run the app on an Android device. I am using the cordova-plugin-facebook4 and queries like get friends and login are working correctly.

The code for that specific part:

function makeCallToFacebookWithImage(url){
    console.log("share that to facebook with image");
    var facebookString = "/me/photos?method=post&url="+encodeURI(url)+"&caption="+$scope.comment;
    console.log("facebookString with image: "+facebookString);
    facebookConnectPlugin.getLoginStatus(function(loginStatus){
        // if already loggedIn
        if(loginStatus.status == "connected"){
            facebookConnectPlugin.api(facebookString, ["publish_actions"], function(response){
                // success
                console.log("success "+JSON.stringify(response));
            }, function(response){
                // error
                console.log("error "+JSON.stringify(response));
            });
        }
    }, function(error){
        console.log(error);
    })
}

The console.log of line 4:

facebookString with image: /me/photos?method=post&url=https://firebasestorage.googleapis.com/URL?alt=media&token=4420080a-41d8-4816-bf62-5bfb159d1da5&caption=FBTest

Error message:

error {"errorCode":"100","errorType":"OAuthException","errorMessage":"Invalid parameter","errorUserMessage":"Your photos couldn't be uploaded. Photos should be less than 4 MB and saved as JPG, PNG, GIF or TIFF files.","errorUserTitle":"Can't Read Files"}

As you can see I store the image in a firebase database (I replaced the exact url with URL to not publish it here), the image is already uploaded and compressed before I call the Facebook post function and it is in .jpg format, so the error message of the Facebook post is not accurate or does not help me. Besides that, the exact code works on iOS perfectly fine.

I am searching for a solution to this error for a few hours now, so may someone here can help me out with this issue. Did someone had this issue before and may know a solution?

EDIT:

The console.log with complete URL's:

iOS:

/me/photos?method=post&url=https://firebasestorage.googleapis.com/v0/b/appname-50cd0.appspot.com/o/post%252F-KbyHksSP_EV2MTjvCb5.jpg?alt=media&token=64f43c60-47fa-40b2-b85b-e1e5ae1dea13&caption=Rest

Android:

/me/photos?method=post&url=https://firebasestorage.googleapis.com/v0/b/appname-50cd0.appspot.com/o/post%252F-KbxypBFRqs6eyYNk8ZR.jpg?alt=media&token=4420080a-41d8-4816-bf62-5bfb159d1da5&caption=FB

Obviously different pictures, but the URL structures are the same.

EDIT2:

What I tried so far:

  • using the URL of an existing picture in the firebase storage, which was taken by the iOS device -> same error.
  • added the Android hash keys to the facebook development enviroment -> same error
  • whitelisted graph.facebook.com in the config.xml with:

    <access origin="*graph.facebook.com*" subdomains="true"/>
    

-> same error

  • using encodeURIComponent(url) instead of encodeURI(url) -> same error

I am using a Nexus 5 with Android 6.0.1 as test device, at the moment I don't have the access to another Android device, but I'll try it on a different device as soon as I get one.

EDIT 3:

  • So I tested it on 2 other Android devices and it did result in the same error

  • I updated the facebook4 plugin to newest version which support facebook sdk 4.22.1, but the error remains

  • I tried to change the version in cordova-plugin-facebook4/www/facebook-browser.js in the FB.init function (line 147) from version 2.7 to 2.9 (which is the newest) but the error remains

EDIT 4 SOLVED

finally, the solution is in the comments. It was a bug of cordova-plugin-facebook4 on android devices when you use a download url that contains parameter characters like ? & and =, which firebase storage does.

1
Can you verify that facebookString contains the exact same thing on both Android and iOS? - CBroe
I edited the post and added url examples. As far as I can see, they have the exact same structure, with different images though, but I tested it on both devices with different images, always the same result. - Jonas Ostergaard
That doesn’t look like the image URL was properly URL-encoded in both cases (although, might be a copy&paste issue, depending on where from exactly you got it.) But encodeURI is the wrong method to use here - try using encodeURIComponent instead, an see if that gives different results. (They encode a different set of characters - notably encodeURI does not include ? and &, and those need to be encoded most of all.) - CBroe
With encodeURIComponent the URL's are differently encoded, but it still throws the same error on android. I also tried to hardcode the link to a picture in firebase which was made with the iOS device, same error from facebook. So the image encoding itself is not the error source. I'm quite clueless at the moment. - Jonas Ostergaard
Some people have reported that Facebook occasionally has problems with images served via HTTPS … but serving them via HTTP does not seem to be an option here(?). And though I would not expect Google to have general issues with their HTTPS setup/certificates, it probably can’t hurt to run the URL through a few of the SSL Check services out there, and see if those report any problems. - CBroe

1 Answers

1
votes

SOLVED

after many of hours I found the Problem. The combination of cordova-plugin-facebook4 with an firebase storage does not work on Android, because the encoding inside of the plugin is wrong handled.

Inside of the file cordova-plugin-facebook4/src/android/ConnectPlugin.java there is this function:

private void makeGraphCall() {...}

This function decodes the whole "facebookString" and then sorts its segments by the special character ? & and =. A firebase storage download link does contain parameters for the security token, so at this point the plugin tries to interpret the firebase variables as facebook parameters and cuts the url parameter of the firebase url.

What I did was modifying this part of the function:

for (String query : queries) {
  int splitPoint = query.indexOf("=");
  if (splitPoint > 0) {
    String key = query.substring(0, splitPoint);
    String value = query.substring(splitPoint + 1, query.length());
    params.putString(key, value);
  }
}

to:

for (String query : queries) {
  int splitPoint = query.indexOf("=");
  if (splitPoint > 0) {
    String key = query.substring(0, splitPoint);
    String value = query.substring(splitPoint + 1, query.length());
    if(key.equals("url") || key.equals("caption")){
      value = URLDecoder.decode(value);
    }
    params.putString(key, value);
  }
}

And on the angular part I encoded the part of the original firebase URL which contains parameters, and after that I decoded the whole URL again before passing it to the facebookstring.

My Angular Code Snippet:

function makeCallToFacebookWithImage(url) {
  console.log("share to facebook with image");
  var newURL = url;
  var caption = $scope.comment;
  if (ionic.Platform.isAndroid()) { //prep only neccessary on android
    console.log("Is Android device");
    var index = url.indexOf("%2F"); //firebase link specific encoding for folders
    var leftSide = url.substring(0, index);
    var rightSide = url.substring(index, url.length);
    newURL = leftSide + encodeURIComponent(rightSide);
    caption = encodeURIComponent(caption);
  }
  newURL = encodeURIComponent(newURL);
  var facebookString = "/me/photos?method=post&url=" + newURL + "&caption=" + encodeURIComponent(caption);
...

I am going to contact the developers of the facebook4 plugin about this bug. I hope this helps others who may getting stuck on this specific bug.