2013-04-22 9 views
13

Attualmente sto implementando un'applicazione web smartphone con PhoneGap. Su questa applicazione, gli utenti possono pubblicare le immagini scattate con la fotocamera del telefono su Facebook. Questa funzione è stata implementata correttamente usando javascript, inviando un'immagine codificata in base 64. Ora, voglio implementare la stessa funzionalità usando Twitter.Come pubblicare un'immagine su Twitter in PhoneGap utilizzando javascript

Ho trovato alcuni post di blog molto interessanti su questo e sono già in grado di aggiornare lo stato dell'utente solo utilizzando javascript ... ma non riesco a pubblicare immagini anche utilizzando il servizio web Twitter update_with_media.

Secondo questo post, qualcuno dice che è impossibile implementare questa operazione senza utilizzare un codice lato server (come uno script php, ad esempio).

Quindi la mia domanda è: è possibile utilizzare il servizio web Twitter update_with_media solo con javascript?

Vi invio il mio codice per avere una panoramica della soluzione corrente. Ho preso questo articolo come base di lavoro: http://oodlestechnologies.com/blogs/Twitter-integration-on-PhoneGap-using-ChildBrowser-and-OAuth-for-iOS-and-Android-Platforms

Ecco il mio codice 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> 

Ecco il mio codice twitter.js: (Il punto è nel metodo 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(); 

} 

Dopo molte prove (l'invio di un'immagine base64, l'invio di un blob, l'invio di un file binario,. ..) ecco il messaggio di ritorno da Twitter che ho:

{\ "errori \": [{\ "messaggio \": \ " errore interno \", \ "\ code": 131} ]} " "xml": "", "requestHeaders": { "Content-Type": "multipart/form-data"}, "responseHeaders": { "data":" P. i, 19 apr 2013 15:45:28 GMT "," content-encoding ":" deflate "," strict-transport-security ":" max-age = 631138519 "," status ":" 500 Server interno Errore "," server ":" tfe "," content-type ":" application/json; charset = utf-8" , "versione": "HTTP/1.1"}}

una "soluzione" (per inviare un blob) sono stati pubblicati sul forum Twitter dev ma non funziona per me: dev .twitter.com/discussioni/6969

qualcuno vuole implementare la stessa funzione o avere una soluzione Grazie

------ a CURA:?!

voglio solo utilizzare Javascript e I non voglio implementare alcuna soluzione lato server (nessun PHP, C#, Java ...).

+0

Si sta utilizzando il framework PhoneGap corretto? È possibile esaminare la creazione di un plug-in (http://docs.phonegap.com/en/2.7.0/guide_plugin-development_index.md.html#Plugin%20Development%20Guide) che consente di agganciare un'azione JavaScript al codice nativo. Tuttavia, dovresti scrivere codice nativo (ios, android, wp, ecc.) Invece di scrivere un service wrapper (php, asp) in una lingua. Consiglierei, anche se non è quello che chiedi, scrivere un service wrapper che crei il file che ti serve. – Markus

+0

Leggi di più su questo. Hai cercato di fare qualcosa di simile a questo 'var pngData = canvas.toDataURL();' allora avresti bisogno di tagliare i contenuti solo per i dati che stai cercando. – Markus

+0

L'immagine che voglio postare è in realtà generata convertendo una parte della pagina HTML in una tela HTML5 e quindi recuperando la rappresentazione base64 della tela dal metodo toDataURL() ... – Antoine

risposta

1

Secondo i documenti, Twitter richiede la codifica multipart/form-data, il che significa che una stringa base64 non funzionerà.

A differenza degli stati/aggiornamenti POST, questo metodo si aspetta dati multipart raw.Content-Type del tuo richiesta POST deve essere impostato su multipart/form-data con i media [] parametro ~ https://dev.twitter.com/docs/api/1/post/statuses/update_with_media

Tuttavia, si potrebbe ospitare un endpoint che prende base64, lo converte in un file reale, e inoltra la richiesta per Twitter. Per esempio (non testata):

<?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'])); 

?> 

E si potrebbe chiamare piace:

$.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); 
     } 
    }); 
+0

Non voglio usare alcun codice lato server per fare ciò. Ho già implementato una soluzione C# che funziona perfettamente con un file reale come in PHP, ma non è questo il punto. Voglio solo usare il codice Javascript. – Antoine

+1

Supponendo che tu non stia usando gli elementi 'input' per caricare file e hai solo dati base64 con cui lavorare, credo che quello che stai cercando di fare sia impossibile dato che i browser non hanno attualmente un modo di convertire una stringa base64 a un caricamento di file. Se si stava utilizzando un elemento di input, è possibile utilizzare la tecnica iframe o inviare direttamente i dati (solo il browser HTML5), ma non è questo il caso. –

+1

Non uso alcun elemento 'input' perché voglio pubblicare un'immagine" generata "su Twitter. L'utente non seleziona l'immagine nella sua galleria o nel file system del telefono. L'immagine viene generata convertendo una parte della pagina HTML in un canvas HTML5 e quindi recuperando la rappresentazione base64 del canvas dal metodo 'toDataURL()'. Qualche idea con questa informazione? – Antoine

0

per chiunque cerchi di inviare le immagini a Twitter utilizzando il client JS, ho potuto Pubblica su Twitter utilizzando la soluzione gary-buynary-co-za (https://github.com/bytespider/jsOAuth/pull/11) alla fine di questo forum. Praticamente sono stati utilizzati gli oggetti Phonegap FileTransfer e FileTransferOptions per il trasferimento dell'immagine su twitter api, ma ho utilizzato jsOAuth per preparare intestazioni e firme FileTransferOptions. La soluzione potrebbe sicuramente essere pulita.

Problemi correlati