Working with Twitter API 1.1 with Unity

Update 9th Oct 2014: Let’s Tweet in Unity has been updated to work with API 1.1: https://www.assetstore.unity3d.com/en/#!/content/536

Back around late summer/early autumn, I was working on a project that involved showing Tweets in a unique way using Unity. The concept itself was not complicated and with Unity being Unity, we thought there would be a plugin or existing code to work with Twitter’s API and we could prototype the concept relatively quickly.

We were wrong. It took us a few days between us to get the search query working with Unity using Twitter API 1.1.

There are quite a few resources and plugins for Twitter’s old API (1.0) but none for 1.1. 1.0 was a really simple interface in terms of producing a URL query and the result would be a JSON string. 1.1 added the need to use OAuth authentication which has caused problems for many developers judging from the various forums littered with queries.

At this stage we had two problems, getting the OAuth Authentication correct and working with Unity’s WWW class for web queries instead of the .NET framework.

Twitter’s OAuth authentication is incredibly strict and even after trying several OAuth libraries (including the one I used with my previous Yelp OAuth entry) I had little luck. Thankfully, Twitter provides an OAuth Tool to that that creates the Signature Base String and Authorisation Header based on the queries allowing you to check if your implementation is correct. This was a huge help for us as it meant we could isolate the OAuth section of code and work on getting the signature correct before making a query to the Twitter servers. Just be sure to override the OAuth Nounce (which is normally a random number) and OAuth Timestamp to match the values used in Twitter’s tool otherwise you will get different results.

For us, it turned out to be not including correct parameters and also not having them in alphabetical order. We ended using a code sample from Steven Mosley’s blog and modifying it for our purposes.

Our next problem was a little more tricky and we wasted time because we read outdated information about was possible using the WWW class and could cause errors. The basic search API was a GET query  with parameters which meant we had to pass an object to the postData parameter. However, the Unity documentation states that passing an object in the postData parameter in the WWW constructor call would produce a POST query which would cause the API to fail on the Twitter servers and reading the comments from Let’s Tweet in Unity plugin code, passing a null would cause an exception to fire.

We wasted a solid day looking for a way to make a GET web query in Unity without the WWW class which proved to be fruitless and was ready to setup a local web server to make the Twitter that our prototype in Unity could access as a proxy. It was until I spoke to a few other developers on The Chaos Engine that it was possible to pass null in the WWW postData parameter and it would remain as a GET query without crashing.

After that, everything was working as it should and we had finally make search queries to Twitter.

Below is a link to a basic sandbox Unity product with a slightly more user friendly version of the code. It hasn’t been fully tested and just comes ‘as is’ but should be enough to get you going pretty quickly should you need it. The source can be found in Assets/Scripts

BitBucket Git Repo

About these ads
Tagged , , , ,

18 thoughts on “Working with Twitter API 1.1 with Unity

  1. David says:

    Hi,
    I was trying to use the Let’s Tweet in Unity plugin to make just a simple tweet, since it has been made for 1.0 I tried to put him working for 1.1, but it’s giving me an “STATUS: HTTP/1.1 401 Unauthorized” can you help me please?

    • yaustar says:

      What changes have you made to the ‘Let’s Tweet in Unity’ plugin to try and get it to work with API 1.1?

      • David says:

        I just changed the URL since it was outdated and the request when printed in console seemed ok. I found this rep: https://github.com/Peezus/UnityTwiTestGit

        It works but they are using ” Application.OpenURL()” to open the page to ask permissions to user and get PIN to generate the token, and for mobile that’s not very user friendly is there another way of getting the PIN?

      • yaustar says:

        Are you looking to post tweets from your own account or have someone be able to login via your application and tweet from their own account?

      • David says:

        Have someone login via my application and tweet from their own account.

      • yaustar says:

        In that case, you will end up with a similar use flow issue as the app will have to request permission from the Twitter via the user. i.e The user will enter login details, the app will open a page or open the Twitter app asking the user for permission (usually having a button that says ‘Allow’) to allow the app to post on their behalf.

        e.g http://en.support.files.wordpress.com/2009/10/screen-shot-2012-11-07-at-7-54-38-pm.png

        This isn’t something I have done from scratch yet and if you are using mobile then I can recommend Prime31’s Social Networking Plugin which is $65 but does the job pretty well in my experience.

        If I do get some time, I may look into it as I am a little interested in the API flow from Twitter.

      • rebolomo says:

        you have to change the code in this way:
        #region Twitter API Methods

        //private static readonly string PostTweetURL = “http://api.twitter.com/1.1/statuses/update.json?status={0}”;

        private static readonly string PostTweetURL = “https://api.twitter.com/1.1/statuses/update.json”;
        public static IEnumerator PostTweet(string text, string consumerKey, string consumerSecret, AccessTokenResponse response, PostTweetCallback callback)
        {
        if (string.IsNullOrEmpty(text) || text.Length > 140)
        {
        Debug.Log(string.Format(“PostTweet – text[{0}] is empty or too long.”, text));

        callback(false);
        }
        else
        {
        string url = PostTweetURL;//string.Format(PostTweetURL, UrlEncode(text));
        Dictionary parameters = new Dictionary();

        parameters.Add(“status”, text);

        // Need to fill body since Unity doesn’t like an empty request body.
        byte[] dummmy = new byte[1];
        dummmy[0] = 0;

        // HTTP header
        Hashtable headers = new Hashtable();
        headers["Authorization"] = GetHeaderWithAccessToken(“POST”, url, consumerKey, consumerSecret, response, parameters);

        WWWForm form = new WWWForm ();

        form.AddField (“status”, text);

        byte[] rawData = form.data;

        WWW web = new WWW(url, rawData, headers);
        yield return web;

        if (!string.IsNullOrEmpty(web.error))
        {
        Debug.Log(string.Format(“PostTweet – failed. {0}”, web.error));
        callback(false);
        }
        else
        {
        string error = Regex.Match(web.text, @”([^&]+)”).Groups[1].Value;

        if (!string.IsNullOrEmpty(error))
        {
        Debug.Log(string.Format(“PostTweet – failed. {0}”, error));
        callback(false);
        }
        else
        {
        callback(true);
        }
        }
        }
        }

        #endregion

  2. cheliotk says:

    Nice, this implementation works great!
    How do you access the next page results though, when results are more than the count? Do you need to re-authorize the request or would a simple WWW query with the next page results URL (without headers etc) work?

    • yaustar says:

      For the next ‘page’, you have to use the ‘since_id’ and ‘max_id’ parameters to navigate between ‘pages’ of tweets. The links on this page (https://dev.twitter.com/issues/1076) will explain more.

      I may update the sample to handle this as it wasn’t something I looked at before.

      Not sure about needing to re-authorization but I am guessing yes due to the timestamp used.

  3. Very nice, thanks! I ran into one bug:
    SearchTwitter_Coroutine hardcodes a search for #gdc instead of using the keywords.
    I changed it to this: {“q”, keywords}, and it seems to work fine…

  4. VamppiV says:

    I’m new in mixing Unity/Twitter and this solution helped me very much to understand everything – thanks! But I have a little problem, maybe you have idea what’s wrong?

    I changed a bit script “demo” for my needs. Actually I have three scripts:
    TwitterRegister, TwitterPinVerify and TwitterShare. Every of them is attached to corresponding button.

    Scripts look the same like a corresponding parts of Demo script.

    I’ve added just functions that “give tokens” from one script to next script (something like: public Twitter.RequestTokenResponse getRTR(){ return m_RequestTokenResponse;}

    Register – works. Verify pin – works. But when I’m trying to “tweet” in third script, I’m getting communicat: You are trying to load data from a www stream which had the following error when downloading.
    401 Authorization Required

    Maybe any idea what’s wrong?

    • yaustar says:

      Can you share the source? I can’t think off hand of what it could be beyond the usual stuff. Is the token correct when TwitterShare is pressed? Is the API being used correctly? etc

      • VamppiV says:

        Okey, that’s my scripts:

        BUTTON REGISTER:
        using UnityEngine;
        using System.Collections;

        public class TwitterRegisterButtonScript : MonoBehaviour {

        string CONSUMER_KEY=”************************”;
        string CONSUMER_SECRET=”*************************”;

        Twitter.RequestTokenResponse m_RequestTokenResponse;

        void OnClick () {
        StartCoroutine(Twitter.API.GetRequestToken(CONSUMER_KEY, CONSUMER_SECRET, new Twitter.RequestTokenCallback(this.OnRequestTokenCallback)));
        }

        void OnRequestTokenCallback(bool success, Twitter.RequestTokenResponse response)
        {
        if (success)
        {
        string log = “OnRequestTokenCallback – succeeded”;
        log += “\n Token : ” + response.Token;
        log += “\n TokenSecret : ” + response.TokenSecret;
        print(log);

        m_RequestTokenResponse = response;

        Twitter.API.OpenAuthorizationPage(response.Token);
        }
        else
        {
        print(“OnRequestTokenCallback – failed.”);
        }
        }

        public Twitter.RequestTokenResponse getRTR(){
        return m_RequestTokenResponse;
        }
        }

        BUTTON PIN VERIFY:
        using UnityEngine;
        using System.Collections;

        public class TwitterPinVerifyScript : MonoBehaviour {

        string CONSUMER_KEY=”*********************”;
        string CONSUMER_SECRET=”*****************************************”;

        const string PLAYER_PREFS_TWITTER_USER_ID = “TwitterUserID”;
        const string PLAYER_PREFS_TWITTER_USER_SCREEN_NAME = “TwitterUserScreenName”;
        const string PLAYER_PREFS_TWITTER_USER_TOKEN = “TwitterUserToken”;
        const string PLAYER_PREFS_TWITTER_USER_TOKEN_SECRET = “TwitterUserTokenSecret”;

        Twitter.RequestTokenResponse m_RequestTokenResponse;
        Twitter.AccessTokenResponse m_AccessTokenResponse;

        string m_PIN = “”;
        public UIInput input;

        TwitterRegisterButtonScript rbt;

        void OnClick () {
        Debug.Log (“twitter pin verify”);

        m_PIN = input.value;
        rbt = GameObject.FindGameObjectWithTag (“TwitterRegisterButton”).GetComponent ();
        m_RequestTokenResponse = rbt.getRTR ();

        StartCoroutine(Twitter.API.GetAccessToken(CONSUMER_KEY, CONSUMER_SECRET, m_RequestTokenResponse.Token, m_PIN,
        new Twitter.AccessTokenCallback(this.OnAccessTokenCallback)));
        }

        void OnAccessTokenCallback(bool success, Twitter.AccessTokenResponse response)
        {
        if (success)
        {
        string log = “OnAccessTokenCallback – succeeded”;
        log += “\n UserId : ” + response.UserId;
        log += “\n ScreenName : ” + response.ScreenName;
        log += “\n Token : ” + response.Token;
        log += “\n TokenSecret : ” + response.TokenSecret;
        print(log);

        m_AccessTokenResponse = response;

        PlayerPrefs.SetString(PLAYER_PREFS_TWITTER_USER_ID, response.UserId);
        PlayerPrefs.SetString(PLAYER_PREFS_TWITTER_USER_SCREEN_NAME, response.ScreenName);
        PlayerPrefs.SetString(PLAYER_PREFS_TWITTER_USER_TOKEN, response.Token);
        PlayerPrefs.SetString(PLAYER_PREFS_TWITTER_USER_TOKEN_SECRET, response.TokenSecret);
        }
        else
        {
        print(“OnAccessTokenCallback – failed.”);
        }
        }

        public Twitter.AccessTokenResponse getATR()
        {
        return m_AccessTokenResponse;
        }

        }

        BUTTON SHARE SCRIPT:
        using UnityEngine;
        using System.Collections;

        public class TwitterShareScript : MonoBehaviour {

        string CONSUMER_KEY=”**************************************”;
        string CONSUMER_SECRET=”***************************************;

        TwitterPinVerifyScript pvs;
        Twitter.AccessTokenResponse m_AccessTokenResponse;

        string m_Tweet = “tweet!”;

        void OnClick(){
        Debug.Log (“twitter share”);

        pvs = GameObject.FindGameObjectWithTag (“TwitterPinButton”).GetComponent ();
        m_AccessTokenResponse = pvs.getATR ();

        StartCoroutine (Twitter.API.PostTweet (m_Tweet, CONSUMER_KEY, CONSUMER_SECRET, m_AccessTokenResponse,
        new Twitter.PostTweetCallback (this.OnPostTweet)));
        }

        void OnPostTweet(bool success)
        {
        print(“OnPostTweet – ” + (success ? “succedded.” : “failed.”));
        }
        }

        —————————————————————————-
        How you can see that’s cutted ‘demo script’. Every token works (I was debuging). I’m logged at my account, I can see all information at debug.

        I have only this one error:
        You are trying to load data from a www stream which had the following error when downloading.
        401 Authorization Required
        UnityEngine.WWW:get_text()
        Twitter.c__IteratorF:MoveNext() (at Assets/Twitter/Twitter.cs:202)

        It’s when I’m clicking ‘share button’. I was debuging that too, key, tokens, tweet etc. are fine. I haven’t idea what’s wrong.

      • yaustar says:

        Quick Note: Let’s Tweet in Unity has been updated for API 1.1 so might be worth checking out: https://www.assetstore.unity3d.com/en/#!/content/536

        If you still want to look at debugging your current code, could you zip up the entire project and link it to me please? It’s a bit difficult to read and run the code from the comments.

  5. VamppiV says:

    I was at this link, I downloaded there my version (two days ago), so I think it’s actual. I can’t share all project… But I can put twitter functionality in smaller project with only this option. Then – I can send you that by mail. Can be? I really lost ideas what to do with that, your Demo works perfect :)

    • VamppiV says:

      Ok, I can’t. I forgot I have some commercial license in my project that I can’t share. But thanks for your trying, I hope I will think of why it doesn’t work. If yes, I will write you back :)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 200 other followers

%d bloggers like this: