【问题标题】:Trouble integrating facebook authentication with cordova app无法将 facebook 身份验证与 cordova 应用程序集成
【发布时间】:2015-09-14 15:00:42
【问题描述】:

对不起,这篇文章太长了,但我在这里发疯了..

我已经解决这个问题 3 天了 - 我正在使用 Javascript 编写一个混合移动应用程序,我已将 Facebook 登录按钮集成到该应用程序中。我在我的 master.js 中添加了 Openfb.js api 来处理登录和所需的功能..

facebook 身份验证运行良好,它会打开特定应用程序所需的登录页面并允许您登录,返回“成功”,您会再次被重定向到应用程序(inAppBrowser)但您没有登录该应用程序并定向到 main.html 页面。我真的在这里绕圈子跑,这让我发疯。

点击facebook登录按钮时,下面会启动函数:

function facebookLogin() {
    showLoading(true);
    openFB.login(
        function (response) {
            if (response.status === 'connected') {
                getFacebookInfo();
                //showMessage('Facebook login succeeded, got access token: ' + response.authResponse.token);
            } else {
                showMessage('Facebook login failed: ' + response.error);
            }
        },
    { scope: 'email' });
}

下面是getFacebookInfo函数:

    function getFacebookInfo() {
    openFB.api({
        path: '/me',
        success: function (facebookData) {
            debugger;
            var data = new Object();
            var now = new Date();

            var dataLogin = new Object();
            data.profilePicture = new Object();

            data.username = facebookData.first_name + ' ' + facebookData.last_name;
            data.password = randomPassword();

            console.log(data.username);
            data.email = facebookData.email;
            data.gender = facebookData.gender;
            data.firstName = facebookData.first_name;
            data.surname = facebookData.last_name;
            data.mode = 'facebook';
            var dt = new Date();
            data.dateOfBirth = dt.getFullYear() + '/' + (dt.getMonth() + 1) + '/' + dt.getDate();
            postData("users", data, successFacebookRegistration);
            //getData("users", dataLogin, successLogin);            
        },
        error: function (data, obj) {
            debugger;
            showMessage('An error occurred acquiring account information from Facebook');
        }
    });
}

OpenFB.js 如下:

    /**
 * OpenFB is a micro-library that lets you integrate your JavaScript application with Facebook.
 * OpenFB works for both BROWSER-BASED apps and CORDOVA/PHONEGAP apps.
 * This library has no dependency: You don't need (and shouldn't use) the Facebook SDK with this library. Whe running in
 * Cordova, you also don't need the Facebook Cordova plugin. There is also no dependency on jQuery.
 * OpenFB allows you to login to Facebook and execute any Facebook Graph API request.
 * @author Christophe Coenraets @ccoenraets
 * @version 0.4
 */
var openFB = (function () {

    var FB_LOGIN_URL = 'https://www.facebook.com/dialog/oauth',
        FB_LOGOUT_URL = 'https://www.facebook.com/logout.php',

        // By default we store fbtoken in sessionStorage. This can be overridden in init()
        tokenStore = window.sessionStorage,

        fbAppId,

        context = window.location.pathname.substring(0, window.location.pathname.indexOf("/", 2)),

        baseURL = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '') + context,

        oauthRedirectURL = baseURL + '/oauthcallback.html',

        logoutRedirectURL = baseURL + '/logoutcallback.html',

        // Because the OAuth login spans multiple processes, we need to keep the login callback function as a variable
        // inside the module instead of keeping it local within the login function.
        loginCallback,

        // Indicates if the app is running inside Cordova
        runningInCordova,

        // Used in the exit event handler to identify if the login has already been processed elsewhere (in the oauthCallback function)
        loginProcessed;

    console.log(oauthRedirectURL);
    console.log(logoutRedirectURL);

    document.addEventListener("deviceready", function () {
        runningInCordova = true;
    }, false);

    /**
     * Initialize the OpenFB module. You must use this function and initialize the module with an appId before you can
     * use any other function.
     * @param params - init paramters
     *  appId: The id of the Facebook app,
     *  tokenStore: The store used to save the Facebook token. Optional. If not provided, we use sessionStorage.
     */
    console.log("init");
    function init(params) {
        if (params.appId) {
            fbAppId = params.appId;
            if (params.cordova != null) {
                runningInCordova = params.cordova;
            }
        } else {
            throw 'appId parameter not set in init()';
        }

        if (params.tokenStore) {
            tokenStore = params.tokenStore;
        }
    }

    /**
     * Checks if the user has logged in with openFB and currently has a session api token.
     * @param callback the function that receives the loginstatus
     */
    console.log("getLoginStatus");
    function getLoginStatus(callback) {
        var token = tokenStore['fbtoken'],
            loginStatus = {};
        if (token) {
            loginStatus.status = 'connected';
            loginStatus.authResponse = { token: token };
        } else {
            loginStatus.status = 'unknown';
        }
        if (callback) callback(loginStatus);
    }

    /**
     * Login to Facebook using OAuth. If running in a Browser, the OAuth workflow happens in a a popup window.
     * If running in Cordova container, it happens using the In-App Browser. Don't forget to install the In-App Browser
     * plugin in your Cordova project: cordova plugins add org.apache.cordova.inappbrowser.
     *
     * @param callback - Callback function to invoke when the login process succeeds
     * @param options - options.scope: The set of Facebook permissions requested
     * @returns {*}
     */
    console.log("login");
    function login(callback, options) {
        var loginWindow,
            startTime,
            scope = '';

        if (!fbAppId) {
            return callback({ status: 'unknown', error: 'Facebook App Id not set.' });
        }

        // Inappbrowser load start handler: Used when running in Cordova only
        function loginWindow_loadStartHandler(event) {
            var url = event.url;
            if (url.indexOf("access_token=") > 0 || url.indexOf("error=") > 0) {
                // When we get the access token fast, the login window (inappbrowser) is still opening with animation
                // in the Cordova app, and trying to close it while it's animating generates an exception. Wait a little...
                var timeout = 600 - (new Date().getTime() - startTime);
                setTimeout(function () {
                    loginWindow.close();
                }, timeout > 0 ? timeout : 0);
                oauthCallback(url);
            }
        }

        // Inappbrowser exit handler: Used when running in Cordova only
        function loginWindow_exitHandler() {
            console.log('exit and remove listeners');
            // Handle the situation where the user closes the login window manually before completing the login process
            deferredLogin.reject({ error: 'user_cancelled', error_description: 'User cancelled login process', error_reason: "user_cancelled" });
            loginWindow.removeEventListener('loadstop', loginWindow_loadStartHandler);
            loginWindow.removeEventListener('exit', loginWindow_exitHandler);
            loginWindow = null;
            console.log('done removing listeners');
        }

        if (options && options.scope) {
            scope = options.scope;
        }

        loginCallback = callback;
        loginProcessed = false;

        //logout();

        if (runningInCordova) {
            oauthRedirectURL = "https://www.facebook.com/connect/login_success.html";
        }

        startTime = new Date().getTime();
        loginWindow = window.open(FB_LOGIN_URL + '?client_id=' + fbAppId + '&redirect_uri=' + oauthRedirectURL +
            '&response_type=token&scope=' + scope, '_blank', 'location=yes');

        // If the app is running in Cordova, listen to URL changes in the InAppBrowser until we get a URL with an access_token or an error
        if (runningInCordova) {
            loginWindow.addEventListener('loadstart', loginWindow_loadStartHandler);
            loginWindow.addEventListener('exit', loginWindow_exitHandler);
        }
        // Note: if the app is running in the browser the loginWindow dialog will call back by invoking the
        // oauthCallback() function. See oauthcallback.html for details.

    }

    /**
     * Called either by oauthcallback.html (when the app is running the browser) or by the loginWindow loadstart event
     * handler defined in the login() function (when the app is running in the Cordova/PhoneGap container).
     * @param url - The oautchRedictURL called by Facebook with the access_token in the querystring at the ned of the
     * OAuth workflow.
     */
    console.log("oauthCallback");
    function oauthCallback(url) {
        // Parse the OAuth data received from Facebook
        var queryString,
            obj;
        debugger;
        loginProcessed = true;
        if (url.indexOf("access_token=") > 0) {
            queryString = url.substr(url.indexOf('#') + 1);
            obj = parseQueryString(queryString);
            tokenStore['fbtoken'] = obj['access_token'];
            if (loginCallback) loginCallback({ status: 'connected', authResponse: { token: obj['access_token'] } });
        } else if (url.indexOf("error=") > 0) {
            queryString = url.substring(url.indexOf('?') + 1, url.indexOf('#'));
            obj = parseQueryString(queryString);
            if (loginCallback) loginCallback({ status: 'not_authorized', error: obj.error });
        } else {
            if (loginCallback) loginCallback({ status: 'not_authorized' });
        }
    }

    /**
     * Logout from Facebook, and remove the token.
     * IMPORTANT: For the Facebook logout to work, the logoutRedirectURL must be on the domain specified in "Site URL" in your Facebook App Settings
     *
     */
    console.log("logout");
    function logout(callback) {
        var logoutWindow,
            token = tokenStore['fbtoken'];

        /* Remove token. Will fail silently if does not exist */
        tokenStore.removeItem('fbtoken');

        if (token) {
            logoutWindow = window.open(FB_LOGOUT_URL + '?access_token=' + token + '&next=' + logoutRedirectURL, '_blank', 'location=yes');
            if (runningInCordova) {
                setTimeout(function () {
                    logoutWindow.close();
                }, 700);
            }
        }

        if (callback) {
            callback();
        }
    }

    /**
     * Lets you make any Facebook Graph API request.
     * @param obj - Request configuration object. Can include:
     *  method:  HTTP method: GET, POST, etc. Optional - Default is 'GET'
     *  path:    path in the Facebook graph: /me, /me.friends, etc. - Required
     *  params:  queryString parameters as a map - Optional
     *  success: callback function when operation succeeds - Optional
     *  error:   callback function when operation fails - Optional
     */
    console.log("api");
    function api(obj) {

        var method = obj.method || 'GET',
            params = obj.params || {},
            xhr = new XMLHttpRequest(),
            url;

        console.log("access_token (api)");
        params['access_token'] = tokenStore['fbtoken'];

        url = 'https://graph.facebook.com' + obj.path + '?' + toQueryString(params);

        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    if (obj.success) obj.success(JSON.parse(xhr.responseText));
                } else {
                    var error = xhr.responseText ? JSON.parse(xhr.responseText).error : { message: 'An error has occurred' };
                    if (obj.error) obj.error(error);
                }
            }
        };

        xhr.open(method, url, true);
        xhr.send();
    }

    /**
     * Helper function to de-authorize the app
     * @param success
     * @param error
     * @returns {*}
     */
    console.log("revokePermissions");
    function revokePermissions(success, error) {
        return api({
            method: 'DELETE',
            path: '/me/permissions',
            success: function () {
                tokenStore['fbtoken'] = undefined;
                success();
            },
            error: error
        });
    }

    function parseQueryString(queryString) {
        var qs = decodeURIComponent(queryString),
            obj = {},
            params = qs.split('&');
        params.forEach(function (param) {
            var splitter = param.split('=');
            obj[splitter[0]] = splitter[1];
        });
        return obj;
    }

    function toQueryString(obj) {
        var parts = [];
        for (var i in obj) {
            if (obj.hasOwnProperty(i)) {
                parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
            }
        }
        return parts.join("&");
    }

    // The public API
    return {
        init: init,
        login: login,
        logout: logout,
        revokePermissions: revokePermissions,
        api: api,
        oauthCallback: oauthCallback,
        getLoginStatus: getLoginStatus
    }

}());

最后将 postData 指向用户 api:

    <?php
header("Access-Control-Allow-Origin: *");
require("json.php");    
require("utilities.php");    

class users extends rest_json_server{

    function get(){        
        $utils = new utilities();

        $mode           =   (isset($this->input['mode'])      ? $this->input['mode']      : '');
        $username       =   (isset($this->input['username'])  ? $this->input['username']  : '');
        $rawPassword    =   (isset($this->input['password'])  ? $this->input['password']  : '');
        $hashPassword   =   $utils->hash($rawPassword, null, true);
        $id             =   (isset($this->input['id'])        ? $this->input['id']        : '');

        if ($mode != 'recover'){
            $sql =  " SELECT *, ".
                    " (SELECT COUNT(p2.id) FROM posts p2 where p2.user_id = u.id) as totalPosts, ".
                    " (SELECT COUNT(f.id) FROM followings f where f.follower_id = u.id) as totalFollowings, ".
                    " (SELECT COUNT(f.id) FROM followings f where f.followed_id = u.id) as totalFollowers " .
                    " FROM users u ";

            $filter = '';

            if ($username != '' && $hashPassword != ''){
                $filter .= " WHERE (username = '" . $username . "' OR email = '" . $username . "') AND password = '" . $hashPassword . "' ";
            }
            else if ($id != ''){
                $filter .= " WHERE id = " . $id;
            }

            $result = $utils->useDatabase($sql . $filter);

            if (mysql_num_rows($result) == 0 || $filter == '')
            {
                $this->response(200, 'Username and password combination not found');
            }
            else
            {
                $this->response(201, mysql_fetch_assoc($result));
            }
        }
        else {
            $sql = ' SELECT * FROM users WHERE username = \'' . $username . '\' OR email = \'' . $username . '\' ';

            $result = $utils->useDatabase($sql);

            if (mysql_num_rows($result) == 0)
            {
                $this->response(200, 'Username not found');
            }
            else
            {
                $result = mysql_fetch_assoc($result);

                if (!$utils->sendEmail(
                    $result['email'], 
                    'Hi<br/><br/>' .
                    'Your password is: ' . $result['confirm'] .
                    '<br/><br/>' . 
                    'Best regards<br/>' .
                    'The Stylista team'))
                {
                    $this->response(500);
                }
                else
                {
                    $this->response(201, 'Your password has been emailed to you');
                }
            }
        }
    }

    function post(){
        $uploaddir = '../img/user-edit/';

        if (isset($_GET['file']))
        {
            $fileName = date('Ymdhis');
            foreach($_FILES as $file)
            {
                $fileName .= basename($file['name']);

                move_uploaded_file($file['tmp_name'], $uploaddir . $fileName);
            }
            $this->response(201, $fileName);
        }
        else
        {
            $utils = new utilities();

            $username =     (isset($this->input_json->username) ? $this->input_json->username : '');
            $rawPassword =  (isset($this->input_json->password) ? $this->input_json->password : '');
            $hashedPassword = $utils->hash($rawPassword, null, true);
            $firstName =    (isset($this->input_json->firstName) ? $this->input_json->firstName : '');
            $surname =      (isset($this->input_json->surname) ? $this->input_json->surname : '');
            $email =        (isset($this->input_json->email) ? $this->input_json->email : '');
            $gender =       (isset($this->input_json->gender) ? $this->input_json->gender : '');
            $dateOfBirth =  (isset($this->input_json->dateOfBirth) ? $this->input_json->dateOfBirth : '');
            $country =      (isset($this->input_json->country) ? $this->input_json->country : '');
            $province =     (isset($this->input_json->province) ? $this->input_json->province : '');
            $city =         (isset($this->input_json->city) ? $this->input_json->city : '');
            $blogURL =      (isset($this->input_json->blogURL) ? $this->input_json->blogURL : '');
            $websiteURL =   (isset($this->input_json->websiteURL) ? $this->input_json->websiteURL : '');
            $id =           (isset($this->input_json->id) ? $this->input_json->id : '');
            $about =        (isset($this->input_json->about) ? $this->input_json->about : '');
            $profilePicFileName = '';
            $success        = true;
            $mode =         (isset($this->input_json->mode) ? $this->input_json->mode : '');
            $existsFacebook = false;
            $processSQL     = true;

            if (isset($this->input_json->profilePicture) && isset($this->input_json->profilePicture->imageData) && isset($this->input_json->profilePicture->fileName)){
                $profilePicFileName = $this->input_json->profilePicture->fileName;

                // Save profile picture
                $profilePicData = $this->input_json->profilePicture->imageData;
                $profilePicData = str_replace('data:image/jpeg;base64,', '', $profilePicData);
                $profilePicData = str_replace(' ', '+', $profilePicData);
                $data = base64_decode($profilePicData);
                $file = $uploaddir . $profilePicFileName;
                $success = file_put_contents($file, $data);
            }

            if (!$success){
                $processSQL = false;
                $this->response(500, 'Failed to save profile picture');
            }

            if ($username = '' || $firstName = '' || $surname = '' || $email = '') {
                $processSQL = false;
                $this->response(400, 'Certain fields are blank');
            }

            $result = $utils->useDatabase(" SELECT * FROM users WHERE email = '" . $email . "' ");

            if (mysql_num_rows($result)!=0 && $id == '')
            {
                if ($mode == '')
                {
                    $processSQL = false;
                    $this->response(200,'Email exists');
                }
                else {
                    if ($id == '')
                    {
                        $id = mysql_fetch_assoc($result)['id'];
                    }

                    $existsFacebook = true;
                }
            }

            $result = $utils->useDatabase(" SELECT * FROM users WHERE username = '" . $username . "' ");

            if (mysql_num_rows($result)!=0 && $id == '')
            {
                if ($mode == '')
                {
                    $processSQL = false;
                    $this->response(200,'Username already exists');
                }
                else {
                    if ($id == '')
                    {
                        $id = mysql_fetch_assoc($result)['id'];
                    }

                    $existsFacebook = true;
                }
            }

            if ($processSQL)
            {
                $sql = '';

                if (($id == '' && $mode == '') || ($mode == 'facebook' && $existsFacebook == false)){
                    $sql =  " INSERT INTO users (password, created, modified, country, state_province, city, birthday, blog_url, website_url, email, first_name, last_name, username, email_ver, gender, confirm, banning, profile_pic) " .
                            " VALUES ('".$hashedPassword."', NOW(), NOW(), '".$country."', '".$province."', '".$city."', '".$dateOfBirth."', '".$blogURL."', '".$websiteURL."', '".$email."', '".$firstName."', '" .
                            $surname."', '".$username."', 1, '".$gender."', '".$rawPassword."', '', '" . $profilePicFileName . "')";

                    $result = $utils->useDatabase($sql);

                    $sql = 
                        " SELECT *, ".
                            " (SELECT COUNT(p2.id) FROM posts p2 where p2.user_id = u.id) as totalPosts, ".
                            " (SELECT COUNT(f.id) FROM followings f where f.follower_id = u.id) as totalFollowers, ".
                            " (SELECT COUNT(f.id) FROM followings f where f.followed_id = u.id) as totalFollowings " .
                        " FROM users u " .
                        " WHERE u.email = '" . $email . "'";

                    $result = $utils->useDatabase($sql);

                    $this->response(201, mysql_fetch_assoc($result));
                }
                else{
                    $updateSet = ($rawPassword != '' ? " password = '" . $hashedPassword ."', " : '') .
                            " modified = NOW(), ".
                            ($country != '' ? " country = '" . $country . "', " : '') .
                            ($province != '' ? " state_province= '" . $province . "', " : '') .
                            ($city != '' ? " city = '" . $city ."', " : '') .
                            ($dateOfBirth != '' ? " birthday = '" . $dateOfBirth ."', " : '') .
                            ($blogURL != '' ? " blog_url = '" . $blogURL . "', " : '') .
                            ($websiteURL != '' ? " website_url = '" . $websiteURL . "', " : '') .
                            ($email != '' ? " email = '" . $email . "', " : '') .
                            ($firstName != '' ? " first_name = '" . $firstName . "', " : '') .
                            ($surname != '' ? " last_name = '" . $surname . "', " : '') .
                            ($username != '' ? " username = '" . $username . "', " : '') .
                            ($gender != '' ? " gender = '" . $gender . "', " : '') .
                            ($about != '' ? " about = '" . $about . "', " : '') .
                            ($rawPassword != '' ? " confirm = '" . $rawPassword . "', " : '') .
                            ($profilePicFileName != '' ? " profile_pic = '" . $profilePicFileName . "', " : '');

                    $sql =
                        " UPDATE users " .
                        " SET " . 
                            substr($updateSet, 0, strlen($updateSet) - 2) .
                        " WHERE id = " . $id;

                    $result = $utils->useDatabase($sql);

                    $sql = 
                        " SELECT *, ".
                            " (SELECT COUNT(p2.id) FROM posts p2 where p2.user_id = u.id) as totalPosts, ".
                            " (SELECT COUNT(f.id) FROM followings f where f.follower_id = u.id) as totalFollowers, ".
                            " (SELECT COUNT(f.id) FROM followings f where f.followed_id = u.id) as totalFollowings " .
                        " FROM users u " .
                        " WHERE u.id = " . $id;

                    $result = $utils->useDatabase($sql);

                    $this->response(201, mysql_fetch_assoc($result));
                }
            }
        }
    }

    function put(){
        /**
         * No supported
         */
        $this->response(405);
    }


}

$start = new users();
$start->handle_request();

非常感谢任何建议。

【问题讨论】:

    标签: javascript facebook api cordova mobile


    【解决方案1】:

    我在使用 Cordova 时的经验是,它不能很好地处理 cookie 和会话状态。我的预感是 Facebook 设置了一个身份验证 cookie——它会立即被删除。 所以你可能做的一切都是正确的,只是科尔多瓦让你屈服了。

    因此您可能必须编写一个自定义插件,将 Facebook 身份验证状态存储在 web 视图之外。

    您的目标是 iOS 还是 Android,还是两者兼而有之?我知道在 iOS 上创建自定义 Facebook 插件来处理身份验证实际上很容易(我自己做了)。它将身份验证状态存储在 webview 外部 和应用数据本身内,因此即使在切换页面时它也会记住身份验证状态。

    应该说,在我的 iOS Cordova 应用程序中进行了大量工作之后,Cordova 的多个缺陷开始滚雪球......并决定只用原生方式编写它。

    IOS 自定义插件

    这假设您了解插件如何在 iOS 上为 Cordova 工作。还包括有关如何在某人的墙上分享锻炼活动的代码;)

    Facebook.h

    #import <Cordova/CDVCommandDelegate.h>
    #import <Cordova/CDV.h>
    #import <UIKit/UIKit.h>
    #import <AVFoundation/AVFoundation.h>
    #import <FBSDKCoreKit/FBSDKCoreKit.h>
    #import <FBSDKShareKit/FBSDKShareKit.h>
    
    @interface FacebookPlugin : CDVPlugin <FBSDKSharingDelegate>
    
    - (void) IsLoggedIn:(CDVInvokedUrlCommand *)command;
    - (void) LoginWithReadPermissions:(CDVInvokedUrlCommand *)command;
    - (void) LoginWithWritePermissions:(CDVInvokedUrlCommand *)command;
    - (void) Logout:(CDVInvokedUrlCommand *)command;
    @end
    

    Facebook.m

    #import "Facebook.h"
    #import <Foundation/Foundation.h>
    #import <FBSDKCoreKit/FBSDKCoreKit.h>
    #import <FBSDKLoginKit/FBSDKLoginKit.h>
    #import <FBSDKShareKit/FBSDKShareKit.h>
    #import <FBSDKShareKit/FBSDKShareOpenGraphObject.h>
    #import <FBSDKShareKit/FBSDKShareOpenGraphAction.h>
    
    @implementation FacebookPlugin
    
    // [FBSDKAccessToken setCurrentAccessToken:nil] and [FBSDKProfile setCurrentProfile:nil].
    
    - (void) IsLoggedIn:(CDVInvokedUrlCommand *)command
    {
        FBSDKAccessToken* token = [FBSDKAccessToken currentAccessToken];
        NSString* stringResult;
    
        if (token != nil)
        {
            stringResult = @"YES";
        } else {
            stringResult = @"NO";
        }
    
        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:stringResult];
        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
    }
    
    - (void) Logout:(CDVInvokedUrlCommand *)command
    {
        FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
        [login logOut];
    }
    
    - (void) LoginWithReadPermissions:(CDVInvokedUrlCommand *)command
    {
        FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
        [login logInWithReadPermissions:@[@"email"] handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
            if (error) {
                    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
                    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
              } else if (result.isCancelled) {
                    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
                    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
              } else {
                    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
                    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
              }
        }];
    }
    
    - (void) LoginWithWritePermissions:(CDVInvokedUrlCommand *)command
    {
        if ([[FBSDKAccessToken currentAccessToken] hasGranted:@"publish_actions"]) {
             CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
             [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
        } else {
            FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
            [login logInWithPublishPermissions:@[@"publish_actions"] handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
                  if (error) {
                        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
                        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
                  } else if (result.isCancelled) {
                        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
                        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
                  } else {
    
                        // If you ask for multiple permissions at once, you
                        // should check if specific permissions missing
                        if ([result.grantedPermissions containsObject:@"publish_actions"]) {
                            CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
                            [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
                        } else {
                            CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
                            [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
                        }
                  }
            }];
        };
    }
    
    - (void) ShareWorkout:(CDVInvokedUrlCommand *)command
    {
        NSDictionary* options = [command.arguments objectAtIndex:0 withDefault:nil];
    
        //get the app id
        NSString *appId = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FacebookAppID"];
    
        // Create an object
        NSDictionary *properties = @{
            @"fb:app_id": appId,
            @"og:type": @"fitness.course",
            @"og:url": [options objectForKey:@"websiteURL"],
            @"og:title": [options objectForKey:@"courseTitle"],
            @"og:image": [options objectForKey:@"logoURL"],
            //@"fitness:duration:value": [options objectForKey:@"workoutDuration"],
            //@"fitness:duration:value": [options objectForKey:@"workoutDurationUnit"],
            //@"fitness:custom_unit_energy:value": [options objectForKey:@"workoutCalories"],
            //@"fitness:custom_unit_energy:units": [options objectForKey:@"workoutCalorieUnit"]
        };
    
        FBSDKShareOpenGraphObject *graphObject = [FBSDKShareOpenGraphObject objectWithProperties:properties];
    
        // Create an action [fitness.runs, fitness.walks for actionType]
        FBSDKShareOpenGraphAction *action = [[FBSDKShareOpenGraphAction alloc] init];
        action.actionType = [options objectForKey:@"actionType"];
    
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateStyle:NSDateFormatterFullStyle];
        [action setObject:graphObject forKey:@"fitness:course"];
        //[action setString:[dateFormatter stringFromDate:[NSDate date]] forKey:@"created_time"];
        [action setObject:[options objectForKey:@"userMessage"] forKey:@"message"];
        [action setString:@"true" forKey:@"fb:explicitly_shared"];
        //[action setString:[options objectForKey:@"workoutStart"] forKey:@"start_time"];
    
        FBSDKShareOpenGraphContent *content = [[FBSDKShareOpenGraphContent alloc] init];
        content.action = action;
        content.previewPropertyName = @"fitness:course";
    
        [FBSDKShareDialog showFromViewController:self.viewController withContent:content delegate:self];
    }
    
    #pragma mark === delegate method
    - (void)sharer:(id<FBSDKSharing>)sharer didCompleteWithResults:(NSDictionary *)results
    {
        NSLog(@"completed share:%@", results);
    }
    
    - (void)sharer:(id<FBSDKSharing>)sharer didFailWithError:(NSError *)error
    {
        NSLog(@"sharing error:%@", error);
        NSString *message = error.userInfo[FBSDKErrorLocalizedDescriptionKey] ?:
        @"There was a problem sharing, please try again later.";
        NSString *title = error.userInfo[FBSDKErrorLocalizedTitleKey] ?: @"Oops!";
    
        [[[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
    }
    
    - (void)sharerDidCancel:(id<FBSDKSharing>)sharer
    {
        NSLog(@"share cancelled");
    }
    
    @end
    

    Facebook.js

    var Facebook = function() {}
    
    cordova.addConstructor(function() {
        console.log('initializing Facebook');
        if (!window.Cordova) {
            window.Cordova = cordova;
        };
    
        if(!window.plugins) window.plugins = {};
        window.plugins.Facebook = new Facebook();
    });
    
    
        Facebook.prototype.LoginWithReadPermissions = function(successCallback, errorCallback) {
                return cordova.exec(
                        function() {
                            successCallback();
                        }, 
                        function() {
                            errorCallback();
                        },
                        'FacebookPlugin', 'LoginWithReadPermissions', []);
    
        };
    
        Facebook.prototype.LoginWithWritePermissions = function(successCallback, errorCallback) {
                return cordova.exec(
                        function() {
                            successCallback();
                        }, 
                        function() {
                            errorCallback();
                        },
                        'FacebookPlugin', 'LoginWithWritePermissions', []);
    
        };
    
         Facebook.prototype.Logout = function(successCallback, errorCallback) {
                return cordova.exec(
                        function() {
    
                        }, 
                        function() {
    
                        },
                        'FacebookPlugin', 'Logout', []);
    
        };
    
        Facebook.prototype.ShareWorkout = function(successCallback, errorCallback, options) {
                return cordova.exec(
                        function() {
                            successCallback();
                        }, 
                        function() {
                            errorCallback();
                        },
                        'FacebookPlugin', 'ShareWorkout', [options]);
    
        };
    

    【讨论】:

    • 哈哈 非常好的斜体回复!当它从 inAppBrowser 切换到应用程序时,它可能会丢失身份验证状态吗?我测试了重定向回应用程序时存在的令牌的返回。我正在为 iOS 和 Android 构建,它也将用于 Blackberry(不要让我在那里开始我的问题)和 Windows 手机。介意给我一个示例看看吗?
    • 我想我发现了 Facebook 身份验证的问题 - UpdateSET 无法正常工作,因此当您选择使用 Facebook 登录时,您会获得一个自动生成的密码 - 然后 API 会检查如果您的电子邮件地址的记录已经存在,如果是这样,它应该用新的密码更新您的密码。但是它不是,因此密码/用户名组合总是错误的。叹息!
    猜你喜欢
    • 1970-01-01
    • 2011-07-06
    • 1970-01-01
    • 1970-01-01
    • 2012-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多