如何使用javascript在Phonegap上发布图片

时间:2013-04-22 07:25:03

标签: javascript cordova twitter

我目前正在使用Phonegap实施网络智能手机应用程序。在此应用程序中,用户可以使用手机摄像头在Facebook上发布他们拍摄的图像。通过发送基本64位编码图像,仅使用javascript成功实现了此功能。现在,我想使用Twitter实现相同的功能。

我发现了一些关于此的非常有趣的博客文章,我已经能够仅使用javascript更新用户状态...但我也无法使用update_with_media Twitter网络服务发布图像。

根据这个post,有人说如果不使用服务器端代码(例如php脚本)就无法实现此操作。

所以我的问题是:是否可以仅使用javascript来使用update_with_media Twitter网络服务?

我发送给您的代码以概述当前的解决方案。我把这篇文章作为工作基础:http://oodlestechnologies.com/blogs/Twitter-integration-on-PhoneGap-using-ChildBrowser-and-OAuth-for-iOS-and-Android-Platforms

这是我的HTML代码。

<!DOCTYPE html>
<html>
    <head>
        <title>Test</title>
        <script type="text/javascript" src="../js/jquery/jquery.min.js"></script>
        <script type="text/javascript" src="../cordova-2.5.0.js"></script>
        <script type="text/javascript" src="../js/childBrowser/childbrowser.js"></script>
        <script type="text/javascript" src="../js/helpers/jsOAuth-1.3.6.js"></script>
        <script type="text/javascript" src="../js/helpers/twitter.js"></script>
    </head>
    <body>
        <h4>Oodles Twitter App</h4>
        <table border="1">
            <tr>
                <th>Login using Twitter</th>
                <th>
                    <button id="loginBtn" onclick="Twitter.init();">Login</button>
                    <button id="logoutBtn" onclick="logOut();">Logout</button>
                </th>
            </tr>
            <tr id="tweetText">
                <td colspan="2"><textarea id="tweet"></textarea></td>
            </tr>
            <tr id="tweetBtn">
                <td colspan="2" align="right">
                    <button id="tweeter" onclick="Twitter.tweet();">Tweet</button>
                </td>
            </tr>
            <tr><td colspan="2"><div id="welcome">Please Login to use this app</div></td></tr>
        </table>
        <br/>
        <br/>
        <button onclick="javascript:location.reload();">Recharger la page</button>
    </body>
</html>

这是我的twitter.js代码:(重点是post方法)

$(document).ready(function() {
    document.addEventListener("deviceready", onDeviceReady, false);
});

function onDeviceReady() {
    var root = this;
    cb = window.plugins.childBrowser;
    if (!localStorage.getItem(twitterKey)) {
        $("#loginBtn").show();
        $("#logoutBtn").hide();
        $("tweetBtn").hide();
        $("tweetText").hide();
    }
    else {
        $("#loginBtn").hide();
        $("#logoutBtn").show();
        $("tweetBtn").show();
        $("tweetText").show();
    }

    if (cb != null) {
        cb.onLocationChange = function(loc) {
            root.locChanged(loc);
        };
        cb.onClose = function() {
            root.onCloseBrowser()
        };
        cb.onOpenExternal = function() {
            root.onOpenExternal();
        };
    }
}

function onCloseBrowser() {
    console.log("onCloseBrowser!");
}

function locChanged(loc) {
    console.log("locChanged!");
}

function onOpenExternal() {
    console.log("onOpenExternal!");
}

// Consumer key : ...
// Consumer secret : ...

// GLOBAL VARS
var oauth; // It Holds the oAuth data request
var requestParams; // Specific param related to request
var options = {consumerKey: '...', consumerSecret: '...', callbackUrl: "http://www.google.fr"};
var twitterKey = "twtrKey"; // This key is used for storing Information related   
var Twitter = {
    init: function() {
        // Apps storedAccessData , Apps Data in Raw format
        var storedAccessData, rawData = localStorage.getItem(twitterKey);
        // here we are going to check whether the data about user is already with us.
        if (localStorage.getItem(twitterKey) !== null) {
            // when App already knows data
            storedAccessData = JSON.parse(rawData); //JSON parsing
            //options.accessTokenKey = storedAccessData.accessTokenKey; // data will be saved when user first time signin
            options.accessTokenSecret = storedAccessData.accessTokenSecret; // data will be saved when user first first signin

            // javascript OAuth take care of everything for app we need to provide just the options
            oauth = OAuth(options);
            oauth.get('https://api.twitter.com/1/account/verify_credentials.json?skip_status=true',
                    function(data) {
                        var entry = JSON.parse(data.text);
                        console.log("USERNAME: " + entry.screen_name);
                    }
            );
        }
        else {
            // we have no data for save user
            oauth = OAuth(options);
            oauth.get('https://api.twitter.com/oauth/request_token',
                    function(data) {
                        requestParams = data.text;
                        cb.showWebPage('https://api.twitter.com/oauth/authorize?' + data.text); // This opens the Twitter authorization / sign in page
                        cb.onLocationChange = function(loc) {
                            Twitter.success(loc);
                        }; // Here will will track the change in URL of ChildBrowser
                    },
                    function(data) {
                        console.log("ERROR: " + JSON.stringify(data));
                    }
            );
        }
    },
    /*
     When ChildBrowser's URL changes we will track it here.
     We will also be acknowledged was the request is a successful or unsuccessful
     */
    success: function(loc) {

        // Here the URL of supplied callback will Load

        /*
         Here Plugin will check whether the callback Url matches with the given Url
         */
        if (loc.indexOf("http://www.google.fr") >= 0) {

            // Parse the returned URL
            var index, verifier = '';
            var params = loc.substr(loc.indexOf('?') + 1);

            params = params.split('&');
            for (var i = 0; i < params.length; i++) {
                var y = params[i].split('=');
                if (y[0] === 'oauth_verifier') {
                    verifier = y[1];
                }
            }

            // Here we are going to change token for request with token for access

            /*
             Once user has authorised us then we have to change the token for request with token of access
             here we will give data to localStorage.
             */
            oauth.get('https://api.twitter.com/oauth/access_token?oauth_verifier=' + verifier + '&' + requestParams,
                    function(data) {
                        var accessParams = {};
                        var qvars_tmp = data.text.split('&');
                        for (var i = 0; i < qvars_tmp.length; i++) {
                            var y = qvars_tmp[i].split('=');
                            accessParams[y[0]] = decodeURIComponent(y[1]);
                        }

                        $('#oauthStatus').html('<span style="color:green;">Success!</span>');
                        $('#stage-auth').hide();
                        $('#stage-data').show();
                        oauth.setAccessToken([accessParams.oauth_token, accessParams.oauth_token_secret]);

                        // Saving token of access in Local_Storage
                        var accessData = {};
                        accessData.accessTokenKey = accessParams.oauth_token;
                        accessData.accessTokenSecret = accessParams.oauth_token_secret;

                        // Configuring Apps LOCAL_STORAGE
                        console.log("TWITTER: Storing token key/secret in localStorage");
                        localStorage.setItem(twitterKey, JSON.stringify(accessData));

                        oauth.get('https://api.twitter.com/1/account/verify_credentials.json?skip_status=true',
                                function(data) {
                                    var entry = JSON.parse(data.text);
                                    console.log("TWITTER USER: " + entry.screen_name);
                                    $("#welcome").show();
                                    document.getElementById("welcome").innerHTML = "welcome " + entry.screen_name;
                                    successfulLogin();
                                    // Just for eg.
                                    app.init();
                                },
                                function(data) {
                                    console.log("ERROR: " + data);
                                }
                        );

                        // Now we have to close the child browser because everthing goes on track.

                        window.plugins.childBrowser.close();
                    },
                    function(data) {
                        console.log(data);


                    }
            );
        }
        else {
            // Just Empty
        }
    },
    tweet: function() {
        var storedAccessData, rawData = localStorage.getItem(twitterKey);

        storedAccessData = JSON.parse(rawData); // Paring Json 
        options.accessTokenKey = storedAccessData.accessTokenKey; // it will be saved on first signin
        options.accessTokenSecret = storedAccessData.accessTokenSecret; // it will be save on first login

        // javascript OAuth will care of else for app we need to send only the options
        oauth = OAuth(options);
        oauth.get('https://api.twitter.com/1/account/verify_credentials.json?skip_status=true',
                function(data) {
                    var entry = JSON.parse(data.text);
                    Twitter.post();
                }
        );
    },
    /*
     We now have the data to tweet
     */
    post: function() {
        alert('Post !');
        var theTweet = $("#tweet").val(); // You can change it with what else you likes.

        oauth.post('https://upload.twitter.com/1/statuses/update_with_media.json',
                {
                    'status': theTweet,
                    'media': //HERE IS THE PROBLEM, WHAT TO DO HERE ?
                }, "multipart/form-data",
                function(data)
                {
                    alert('Data 1 !');
                    console.log('------Data1 : ' + data);
                    var entry = JSON.parse(data.text);
                    console.log(entry);
                    done();
                },
                function(data) {
                    //var json_result = JSON.parse(data);
                    //alert(json_result.text.error);
                    var entry = JSON.stringify(data);
                    console.log('------Data2 : ' + entry);
                }
        );
    }

}

function done() {
    alert("OKKK !");
    $("#tweet").val('');
}


function successfulLogin() {
    $("#loginBtn").hide();
    $("#logoutBtn,#tweet,#tweeter,#tweetBtn,#tweetText").show();

}

function logOut() {
    //localStorage.clear();
    window.localStorage.removeItem(twitterKey);
    document.getElementById("welcome").innerHTML = "Please Login to use this app";
    $("#loginBtn").show();
    $("#logoutBtn,#tweet,#tweeter,#tweetText,#tweetBtn").hide();

}

经过多次测试(发送一个base64图像,发送一个blob,发送一个二进制文件,......),这是来自Twitter的返回消息:

  

{\ “错误\”:[{\ “消息\”:\“内部   错误\ “\ ”代码\“:131}]}”, “XML”: “”, “requestHeaders”:{ “内容类型”: “多部分/格式数据”}, “responseHeaders响应”:{“日期“:” 星期五,   2013年4月19日15:45:28   格林尼治标准时间“‘内容编码’:‘放气’,‘严格的运输安全’:‘最大年龄= 631138519’,‘状态’:” 500   内部服务器   错误 “ ”服务器“: ”TFE“, ”内容类型“:” 应用/ JSON;   字符集= UTF-8" , “版本”: “HTTP / 1.1”}}

一个“解决方案”(通过发送一个blob)已发布在Twitter开发论坛上但不适用于我:dev.twitter.com/discussions/6969

有人想要实现相同的功能或有解决方案吗?谢谢!

------已编辑:

我只想使用 Javascript ,我不想实现任何服务器端解决方案(没有PHP,C#,Java ......)。

2 个答案:

答案 0 :(得分:1)

根据文档,Twitter需要multipart/form-data enctype,这意味着base64字符串不起作用。

  

与POST状态/更新不同,此方法需要原始多部分数据。您的POST请求的Content-Type应使用media []参数〜https://dev.twitter.com/docs/api/1/post/statuses/update_with_media

设置为multipart / form-data

但是,您可以托管一个占用base64的端点,将其转换为真实文件,然后将请求转发给Twitter。例如(未经测试):

<?php

$base64 = $_POST['image'];
$data = base64_decode( $base64 );

// Make name unique to avoid conflicts.
$temp_file = uniqid() . $_POST['name'];

// Save the file to a temp location.
file_put_contents( $temp_file, $data );

$temp_info = pathinfo( $temp_file );
$temp_type = $temp_info['extension'];
$temp_name = basename( $temp_file, '.' . $temp_type );

// OAuth library recommended by Twitter: https://github.com/themattharris/tmhOAuth
// See original: https://github.com/themattharris/tmhOAuth-examples/blob/master/images.php

require 'tmhOAuth.php';
require 'tmhUtilities.php';

$tmhOAuth = new tmhOAuth( array(
    'consumer_key'    => $_POST['consumer_key'],
    'consumer_secret' => $_POST['consumer_secret'],
    'user_token'      => $_POST['user_token'],
    'user_secret'     => $_POST['user_secret'],
));

// note the type and filename are set here as well
// Edit: Not sure if the `type` and `filename` params are necessary.
$params = array( 'media[]' => "@{$temp_file};type={$temp_type};filename={$temp_name}" );

$code = $tmhOAuth->request( 'POST', $tmhOAuth->url( '1/status/update_with_media' ),
    $params,
    true, // use auth
    true  // multipart
);

// Remove temp file.
unlink( $temp_file );

if ( $code == 200 ) {
    tmhUtilities::pr( json_decode( $tmhOAuth->response['response'] ) );
}
tmhUtilities::pr( htmlentities( $tmhOAuth->response['response'] ) );

?>

你可以称之为:

    $.ajax({
        // You'll want to use https to protect the oauth info.
        url: "https://mysite.com/proxy.php",
        type: "POST",
        data: {
            image: "base64 data...",
            name: "foo.png",
            consumer_key: options.consumerKey,
            consumer_secret: options.consumerSecret,
            user_token: options.accessTokenKey,
            user_secret: options.accessTokenSecret
        },
        success: function( data ) {
            console.log( data );
        }
    });

答案 1 :(得分:0)

对于任何尝试使用客户端JS将图像发布到Twitter的人,我可以使用gary-buynary-co-za(https://github.com/bytespider/jsOAuth/pull/11)在本论坛结尾处的解决方案发布到Twitter。几乎最终使用Phonegap FileTransfer和FileTransferOptions对象将图像传输到twitter api,但使用jsOAuth来准备FileTransferOptions标头和签名。绝对可以清理解决方案。