diff --git a/README.md b/README.md index 9c409b329..954a9cb16 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # cordova-plugin-facebook4 -> Use Facebook SDK version 4 in Cordova projects +> Use the latest Facebook SDK version in Cordova projects ## Installation @@ -9,14 +9,21 @@ See npm package for versions - https://www.npmjs.com/package/cordova-plugin-face Make sure you've registered your Facebook app with Facebook and have an `APP_ID` [https://developers.facebook.com/apps](https://developers.facebook.com/apps). ```bash -$ cordova plugin add cordova-plugin-facebook4 --save --variable APP_ID="123456789" --variable APP_NAME="myApplication" +$ cordova plugin add cordova-plugin-facebook4 --save ``` -If you need to change your `APP_ID` after installation, it's recommended that you remove and then re-add the plugin as above. Note that changes to the `APP_ID` value in your `config.xml` file will *not* be propagated to the individual platform builds. +If you want to use a different APP_ID than the one specified in the "Accessibility configuration" in your OutSystems application, you must provide a JSON file named ```facebook_login.json```, deployed to a directory named ```facebookLogin``` with the following format: + +```json +{ + "APP_ID": "123456789", + "APP_NAME": "myApplication" +} +``` ## Usage -This is a fork of the [official plugin for Facebook](https://github.com/Wizcorp/phonegap-facebook-plugin/) in Apache Cordova that implements the latest Facebook SDK. Unless noted, this is a drop-in replacement. You don't have to replace your client code. +This is an indirect fork of the [official plugin for Facebook](https://github.com/Wizcorp/phonegap-facebook-plugin/) via [Jeduan Cornejo Facebook Plugin for Cordova](https://github.com/jeduan/cordova-plugin-facebook4.git) in Apache Cordova that implements the latest Facebook SDK. Unless noted, this is a drop-in replacement. You don't have to replace your client code. The Facebook plugin for [Apache Cordova](http://cordova.apache.org/) allows you to use the same JavaScript code in your Cordova application as you use in your web application. However, unlike in the browser, the Cordova application will use the native Facebook app to perform Single Sign On for the user. If this is not possible then the sign on will degrade gracefully using the standard dialog based authentication. @@ -46,17 +53,19 @@ The Facebook plugin for [Apache Cordova](http://cordova.apache.org/) allows you Success function returns an Object like: - { - status: "connected", - authResponse: { - session_key: true, - accessToken: "", - expiresIn: 5183979, - sig: "...", - secret: "...", - userID: "634565435" - } - } +```json +{ + "status": "connected", + "authResponse": { + "session_key": true, + "accessToken": "", + "expiresIn": 5183979, + "sig": "...", + "secret": "...", + "userID": "634565435" + } +} +``` Failure function returns an error String. @@ -70,16 +79,16 @@ Failure function returns an error String. Success function returns an Object like: -``` +```json { - authResponse: { - userID: "12345678912345", - accessToken: "kgkh3g42kh4g23kh4g2kh34g2kg4k2h4gkh3g4k2h4gk23h4gk2h34gk234gk2h34AndSoOn", - session_Key: true, - expiresIn: "5183738", - sig: "..." + "authResponse": { + "userID": "12345678912345", + "accessToken": "kgkh3g42kh4g23kh4g2kh34g2kg4k2h4gkh3g4k2h4gk23h4gk2h34gk234gk2h34AndSoOn", + "session_Key": true, + "expiresIn": "5183738", + "sig": "..." }, - status: "connected" + "status": "connected" } ``` For more information see: [Facebook Documentation](https://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus) @@ -91,59 +100,69 @@ For more information see: [Facebook Documentation](https://developers.facebook.c Example options - Share Dialog: - { - method: "share", - href: "http://example.com", - caption: "Such caption, very feed.", - description: "Much description", - picture: 'http://example.com/image.png' - share_feedWeb: true, // iOS only - } +```json +{ + "method": "share", + "href": "http://example.com", + "caption": "Such caption, very feed.", + "description": "Much description", + "picture": "http://example.com/image.png", + "share_feedWeb": true +} +``` + +> Note ```share_feedWeb``` is ignored in Android For iOS, the default dialog mode is [`FBSDKShareDialogModeAutomatic`](https://developers.facebook.com/docs/reference/ios/current/constants/FBSDKShareDialogMode/). You can share that by adding a specific dialog mode parameter. The available share dialog modes are: `share_sheet`, `share_feedBrowser`, `share_native` and `share_feedWeb`. [Read more about share dialog modes](https://developers.facebook.com/docs/reference/ios/current/constants/FBSDKShareDialogMode/) Game request: - { - method: "apprequests", - message: "Come on man, check out my application.", - data: data, - title: title, - actionType: 'askfor', - filters: 'app_non_users' - } +```json +{ + "method": "apprequests", + "message": "Come on man, check out my application.", + "data": "dataString", + "title": "title", + "actionType": "askfor", + "filters": "app_non_users" +} +``` Send Dialog: - { - method: "send", - caption: "Check this out.", - link: "http://example.com", - description: "The site I told you about", - picture: "http://example.com/image.png" - } +```json +{ + "method": "send", + "caption": "Check this out.", + "link": "http://example.com", + "description": "The site I told you about", + "picture": "http://example.com/image.png" +} +``` Share dialog - Open Graph Story: (currently only fully available on Android, iOS currently does not support action_properties) - { - var obj = {}; - - obj['og:type'] = 'objectname'; - obj['og:title'] = 'Some title'; - obj['og:url'] = 'https://en.wikipedia.org/wiki/Main_Page'; - obj['og:description'] = 'Some description.'; - - var ap = {}; - - ap['expires_in'] = 3600; - - var options = { - method: 'share_open_graph', // Required - action: 'actionname', // Required - action_properties: JSON.stringify(ap), // Optional - object: JSON.stringify(obj) // Required - }; - } +```js +{ + var obj = {}; + + obj['og:type'] = 'objectname'; + obj['og:title'] = 'Some title'; + obj['og:url'] = 'https://en.wikipedia.org/wiki/Main_Page'; + obj['og:description'] = 'Some description.'; + + var ap = {}; + + ap['expires_in'] = 3600; + + var options = { + method: 'share_open_graph', // Required + action: 'actionname', // Required + action_properties: JSON.stringify(ap), // Optional + object: JSON.stringify(obj) // Required + }; +} +``` In case you want to use custom actions/objects, just prepend the app namespace to the name (E.g: ` obj['og:type'] = 'appnamespace:objectname' `, `action: 'appnamespace:actionname'`. The namespace of a Facebook app is found on the Settings page. @@ -161,7 +180,9 @@ Allows access to the Facebook Graph API. This API allows for additional permissi Example permissions: - ["public_profile", "user_birthday"] +```js +["public_profile", "user_birthday"] +``` Success function returns an Object. @@ -214,35 +235,36 @@ Please check out the [App Invites Overview](https://developers.facebook.com/docs Example options: - { - url: "http://example.com", - picture: "http://example.com/image.png" - } +```json +{ + "url": "http://example.com", + "picture": "http://example.com/image.png" +} +``` ## Sample Code ```js facebookConnectPlugin.appInvite( - { - url: "http://example.com", - picture: "http://example.com/image.png" - }, - function(obj){ - if(obj) { - if(obj.completionGesture == "cancel") { - // user canceled, bad guy - } else { - // user really invited someone :) - } +{ + url: "http://example.com", + picture: "http://example.com/image.png" +}, +function(obj){ + if(obj) { + if(obj.completionGesture == "cancel") { + // user canceled, bad guy } else { - // user just pressed done, bad guy + // user really invited someone :) } - }, - function(obj){ - // error - console.log(obj); + } else { + // user just pressed done, bad guy } -); +}, +function(obj){ + // error + console.log(obj); +}); ``` ### Login diff --git a/package.json b/package.json index 1ec515219..bb87c9ce5 100644 --- a/package.json +++ b/package.json @@ -25,5 +25,8 @@ "social", "sharing" ], - "license": "Apache-2.0" + "license": "Apache-2.0", + "dependencies": { + "plist": "^3.0.1" + } } diff --git a/plugin.xml b/plugin.xml index e35d806ed..da6985ead 100644 --- a/plugin.xml +++ b/plugin.xml @@ -177,5 +177,5 @@ - + diff --git a/scripts/after_prepare.js b/scripts/after_prepare.js deleted file mode 100755 index 57c96dc81..000000000 --- a/scripts/after_prepare.js +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -var fs = require('fs'); - -var getPreferenceValue = function(config, name) { - var value = config.match(new RegExp('name="' + name + '" value="(.*?)"', "i")) - if(value && value[1]) { - return value[1] - } else { - return null - } -} - -if(process.argv.join("|").indexOf("APP_ID=") > -1) { - var APP_ID = process.argv.join("|").match(/APP_ID=(.*?)(\||$)/)[1] -} else { - var config = fs.readFileSync("config.xml").toString() - var APP_ID = getPreferenceValue(config, "APP_ID") -} - -var files = [ - "platforms/browser/www/plugins/cordova-plugin-facebook4/www/facebook-browser.js", - "platforms/browser/platform_www/plugins/cordova-plugin-facebook4/www/facebook-browser.js", - "platforms/browser/www/cordova.js", - "platforms/browser/platform_www/cordova.js" -] - -for(var i in files) { - try { - var contents = fs.readFileSync(files[i]).toString() - fs.writeFileSync(files[i], contents.replace(/APP_ID/g, APP_ID)) - } catch(err) {} -} diff --git a/scripts/before_prepare.js b/scripts/before_prepare.js new file mode 100755 index 000000000..c8aeb9ee2 --- /dev/null +++ b/scripts/before_prepare.js @@ -0,0 +1,126 @@ +#!/usr/bin/env node +'use strict'; + +var fs = require('fs'); +var path = require('path'); +var plist = require('plist'); +var utils = require("./utils"); +var DOMParser = require('xmldom').DOMParser; +var XMLSerializer = require('xmldom').XMLSerializer; + +module.exports = function(context) { + return new Promise(function(resolve, reject) { + + var platform = context.opts.platforms[0]; + + function findFacebookConfigFile(base, files, result) { + var fileNameToFindRegEx = (platform == "ios" ? /[a-z]+-info.plist/gi : /facebookconnect\.xml/gi) + + files = files || fs.readdirSync(base); + result = result || (platform == "ios" ? "*-info.plist not found" : "facebookconnect.xml not found"); + + files.some(function(file) { + var newDir = path.join(base, file); + var isDirectory = false; + try { + isDirectory = fs.statSync(newDir).isDirectory(); + } catch (err) { + isDirectory = false; + } + if (isDirectory) { + result = findFacebookConfigFile(newDir, fs.readdirSync(newDir), result); + } else { + var match = fileNameToFindRegEx.exec(file); + if (match && match.length !== 0) { + result = path.join(base, file); + return true; + } + } + }); + + return result; + + } + + var getPreferenceValue = function(config, name) { + var value = config.match(new RegExp('name="' + name + '" value="(.*?)"', "i")) + if(value && value[1]) { + return value[1] + } else { + return null + } + } + + if(process.argv.join("|").indexOf("APP_ID=") > -1) { + var APP_ID = process.argv.join("|").match(/APP_ID=(.*?)(\||$)/)[1] + } else { + var config = fs.readFileSync("config.xml").toString() + var APP_ID = getPreferenceValue(config, "APP_ID") + } + + var files = [ + "platforms/browser/www/plugins/cordova-plugin-facebook4/www/facebook-browser.js", + "platforms/browser/platform_www/plugins/cordova-plugin-facebook4/www/facebook-browser.js", + "platforms/browser/www/cordova.js", + "platforms/browser/platform_www/cordova.js" + ] + + for(var i in files) { + try { + var contents = fs.readFileSync(files[i]).toString() + fs.writeFileSync(files[i], contents.replace(/APP_ID/g, APP_ID)) + } catch(err) {} + } + + console.log(context); + var wwwPath = utils.getWwwPath(context); + var configPath = path.join(wwwPath, "facebookLogin"); + + var preferredJSONFilename = "facebook_login.json"; + + var fullJSONPath = path.join(configPath, preferredJSONFilename); + + fs.readFile(fullJSONPath, 'utf8', (err, jsonString) => { + if (err) { + console.log("Error reading file: ", err); + return reject( + "Error reading JSON file: " + err + ); + } else { + var facebookLoginJSON = JSON.parse(jsonString); + + var notFoundRegEx = /not found/gi; + var result = findFacebookConfigFile(utils.getPlatformPath(context)); + console.log(platform + ": " + result); + var match = notFoundRegEx.exec(result); + if (!match) { + switch (platform) { + case "ios": + var jsonObj = plist.parse(fs.readFileSync(result, 'utf-8')); + jsonObj.FacebookAppID = facebookLoginJSON.APP_ID; + jsonObj.FacebookDisplayName = facebookLoginJSON.APP_NAME; + jsonObj.CFBundleURLTypes[0].CFBundleURLSchemes[0] = "fb" + facebookLoginJSON.APP_ID; + var builtJSON = plist.build(jsonObj); + fs.writeFileSync(result, builtJSON); + break; + + default: + var parser = new DOMParser(); + var xmlContents = fs.readFileSync(result, 'utf-8'); + var doc = parser.parseFromString(xmlContents, "text/xml"); + doc.getElementsByTagName("string")[0].textContent = facebookLoginJSON.APP_ID; + doc.getElementsByTagName("string")[1].textContent = facebookLoginJSON.APP_NAME; + var xmlSerializer = new XMLSerializer(); + console.log(xmlSerializer.serializeToString(doc)); + fs.writeFileSync(result, xmlSerializer.serializeToString(doc)) + break; + } + } else { + console.log(result); + } + } + }); + + return resolve(); + }); +}; diff --git a/scripts/utils.js b/scripts/utils.js new file mode 100644 index 000000000..d158a0a7a --- /dev/null +++ b/scripts/utils.js @@ -0,0 +1,79 @@ +var path = require("path"); +var fs = require("fs"); +/** + * Get the platform version for the current execution + * @param {object} context + * @returns {string} platform version + */ +function getPlatformVersion(context) { + var projectRoot = context.opts.projectRoot; + var platformsJsonFile = path.join( + projectRoot, + "platforms", + "platforms.json" + ); + var platforms = require(platformsJsonFile); + var platform = context.opts.cordova.version; + return platform; + //return platforms[platform]; +} + +function rmNonEmptyDir(dir_path) { + if (fs.existsSync(dir_path)) { + fs.readdirSync(dir_path).forEach(function(entry) { + var entry_path = path.join(dir_path, entry); + if (fs.lstatSync(entry_path).isDirectory()) { + rmNonEmptyDir(entry_path); + } else { + fs.unlinkSync(entry_path); + } + }); + fs.rmdirSync(dir_path); + } +} + + +/** + * Get the full path to the platform directory + * @param {object} context Cordova context + * @returns {string} absolute path to platforms directory + */ +function getPlatformPath(context) { + var projectRoot = context.opts.projectRoot; + var platform = context.opts.platforms[0]; + return path.join(projectRoot, "platforms", platform); +} + +/** + * Get absolute path to the www folder inside the platform + * and not the root www folder from the cordova project. + * Example: + * - Android: project_foo/platforms/android/app/src/main/assets/www + * - iOS: project_foo/platforms/ios/www + * @param {string} platform + */ +function getWwwPath(context) { + var platformPath = getPlatformPath(context); + var platform = context.opts.platforms[0]; + var wwwfolder; + if (platform === "android") { + var platformVersion = getPlatformVersion(context); + console.log("platformVersion: ", platformVersion); + if (platformVersion >= "7") { + wwwfolder = "app/src/main/assets/www"; + } else { + wwwfolder = "assets/www"; + } + } else if (platform === "ios") { + wwwfolder = "www"; + } + return path.join(platformPath, wwwfolder); +} + + +module.exports = { + getPlatformVersion: getPlatformVersion, + rmNonEmptyDir: rmNonEmptyDir, + getPlatformPath: getPlatformPath, + getWwwPath: getWwwPath, +}; \ No newline at end of file diff --git a/src/ios/FacebookConnectPlugin.m b/src/ios/FacebookConnectPlugin.m index e85a8944b..4ed07cbb1 100644 --- a/src/ios/FacebookConnectPlugin.m +++ b/src/ios/FacebookConnectPlugin.m @@ -212,7 +212,7 @@ - (void) logout:(CDVInvokedUrlCommand*)command } // Else just return OK we are already logged out - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; + CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"Logged out"]; [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; }