phonegapTwitterApp

This tutorial will walk you through creating a basic Twitter app with phonegap for iOS. While this code is specific to iPhone it could be ported over to Android as well.

I am splitting this up into two sections – 1 will walk you through how to create the app, the other will be the details about how it works and things to look for in the code.

 

 

 

 

 

 

Setup

1. Download the project from GIT

2. Create a new phonegap project in xCode.

3. Once you’re all set up open up the phonegapTwitterApp files from GIT

4. In your WWW folder create a new folder called “js” inside of that create two other folders “core”, and another called “plugins”.

5. Copy the files from the phonegapTwitterApp the js/core, js/plugins, and images folders into your www folder.

6. create a new js file called “init.js” in the root of your js folder.

so at this point you should have a file structure that looks like this…

 

 

 

Setup pt2. ( phonegap plugins )

1. In the phonegapTwitterApp project folder select the following files -

ChildBrowserCommand.m
ChildBrowserCommand.h
ChildBroswerViewController.m
ChildBrowserViewController.h

 

 

Drag those into xcode into the “plugins folder.

 

 

Now go to your PhoneGap.plist file and we need to add a couple things.

1. Add a new external host, the key is not important but set the value to * ( this is a catch all for all domains )

2. add ChildBroswerCommand to your plugins, as both the key and value.

 

 

 

Twitter App Setup
Go to https://dev.twitter.com/apps and create a new app. BE SURE TO INCLUDE A CALL BACK URL( this isn’t really important if it’s live or not, we need it for access though )

Once that’s created go to the settings page and select “Read and Write” in the access area.

 

GREAT! Now we’re set up to write some code!

CODE

First we will set up our index.html file.

<!DOCTYPE html>
<html>
  <head>
  <title></title>
 
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no;" />
	<meta charset="utf-8">
	<script type="text/javascript" charset="utf-8" src="phonegap-1.2.0.js"></script>
 
    <!-- CORE JS FILES -->
    <script type="text/javascript" charset="utf-8" src="js/core/phonegap-1.2.0.js"></script>
    <script type="text/javascript" charset="utf-8" src="js/core/jQuery.js"></script>
 
    <!-- PLUGINS -->
    <script type="text/javascript" charset="utf-8" src="js/plugins/jsOAuth.min.js"></script>
    <script type="text/javascript" charset="utf-8" src="js/plugins/ChildBrowser.js"></script>
 
    <!-- OUR INIT -->
    <script type="text/javascript" charset="utf-8" src="js/init.js"></script>
 
    <!-- STYLE STUFF -->
    <link rel="stylesheet" href="css/style.css" />
 
  </head>
  <body onload="app.bodyLoad()"> <!-- CALL TO OUR JS TO LET IT KNOW THE APP IS LOADED -->
  		<div id="header"></div>
  		<div id="loginArea"> <!-- If we don't have a user we will show this -->
			<div id="login" class="btn">Login</div>
        </div>
        <div id="tweetArea"> <!-- if we do have a user we will show this -->
        <div id='statusHold' style='text-align:center; width:100%;'><img src='images/loader.gif'/></div>
        	<textarea id="tweet"></textarea>
            <div id="tweetBTN" class="btn">tweet</div>
        </div>
  </body>
</html>

Basically we are setting up the layout first before we do heavy code.

Next lets create a css stylesheet and save it in our css folder. Call this file style.css

* {
	margin:0px;
}
body {
	font-family:Helvetica;
	-webkit-user-select: none;
	background-color:#f3f3f3;
}
#wrapper {
	width:100%;
	height:100%;
	padding-top:15px;
}
#header {
	height:150px;
	width:100%;
	background-image:url(../images/twitterBird.png);
	background-size:100%;
	margin-bottom:35px;
}
#loginArea {
	width:100%;
	display:none;
}
.btn {
	font-size:25px;
	text-align:center;
	padding-top:12px;
	padding-bottom:12px;
	width:95%;	
	border-radius: 5px;	
	background-color:#33ccff;
	margin:auto;
	color:#fff;
	font-weight:bold;
	box-shadow: 0px 0px 2px .6px #222222;
}
#tweetArea {
	width:100%;
	display:none;
	text-align:center;
}
#tweetArea textarea {
	border:1px solid #cccccc;
	width:94%;
	height:75px;
	margin:auto;
}

Now comes the fun stuff! In our init.js file we need to first set up our global variables.

A little background about localStorage – mobile devices have this great thing called localStorage, it will store all kinds of information, and it will always be saved until the app is deleted. So if you ever need to store say usernames, passwords, app information you can use localStorage!

Setting localStorage is easy -

localStorage.setItem("key","value");

Getting localStorage is easy too!

localStorage.getItem("key");

So for our app we need to set up some globals -
You can find your consumerKey and secret on our twitter app page copy those here.

// GLOBAL VARS
var oauth; // Holds out oAuth request
var requestParams; // Specific request params
var options = { 
            consumerKey: 'YOUR_CONSUMER_KEY', // REPLACE WITH YOUR CONSUMER_KEY
            consumerSecret: 'YOUR_CONSUMER_SECRET', // REPLACE WITH YOUR CONSUMER_SECRET
            callbackUrl: "http://www.YOU_DOMAIN.com" }; // YOUR URL 
 
var cb = ChildBrowser.install(); // install our ChildBrowser ( cb )
var twitterKey = "twttrKey"; // what we will store our twitter user information in

a note about your key and secret. These are VERY important, and the only reason we can use them like this is because we are compiling our code in xcode, if you ever share your project be sure to not share those!

Okay so now let’s build our app.

Our App is what is called when the document is ready – the bodyLoad is what the body of our HTML calls when loaded. our app.init() is called when the device is ready.

var app = {
	bodyLoad:function(){
		document.addEventListener("deviceready", app.deviceReady, false);
	},
	deviceReady:function(){
		app.init();
	},
	init:function(){
 
		// Lets start by checking if we have a twitter account or not...
		if(!localStorage.getItem(twitterKey)){
			$("#loginArea").fadeIn();
			$("#login").click(function(){
				Twitter.init();
			});
		}
		else {
			$("#loginArea").fadeOut();
			$("#tweetArea").fadeIn();
 
			$("#statusHold").hide();
			$("#tweetBTN").click(function(){
				if($("#tweet").val() == ""){
					alert("make sure you've filled out the text area!");
				}
				else {
					$("#statusHold").show();
					$("#tweet").hide();
					$("#tweetBTN").hide();
					Twitter.tweet();
				}
			});
		}
	},
	done:function(){
		$("#statusHold").hide();
		$("#tweet").val('');
		$("#tweet").show();
		$("#tweetBTN").show();
	}
};

Next step is to set up our twitter and check if we have a user or not.

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
var Twitter = {
    init:function(){
 
		// our storedAccessData and Raw Data
        var storedAccessData, rawData = localStorage.getItem(twitterKey);
 
		// First thing we need to do is check to see if we already have the user saved!
		if(localStorage.getItem(twitterKey) !== null){
 
			// If we already have them
			storedAccessData = JSON.parse(rawData); // Parse our JSON object
			options.accessTokenKey = storedAccessData.accessTokenKey; // This is saved when they first sign in
			options.accessTokenSecret = storedAccessData.accessTokenSecret; // this is saved when they first sign in
 
			// jsOAuth takes care of everything for us we just need to provide 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 don't have a user saved yet
			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); }; // When the ChildBrowser URL changes we need to track that
				},
				function(data) { 
					console.log("ERROR: "+data);
				}
			);
		}
    },
}

Now that we’ve got that lets set up our success ( the callback from our ChildBrowser ) This code should go right under our init function after the }, on line 65 of our javascript

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
        /*
	When The ChildBrowser URL changes we will track it here.
	We will also determine if the request was a success or not here
	*/
	success:function(loc){
 
		// The supplied oauth_callback_url for this session is being loaded
 
		/*
		We will check to see if the childBrowser's new URL matches our callBackURL
		*/
		if (loc.indexOf("http://www.YOUR_DOMAIN.com/?") >= 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];
				}
			}
 
			// Exchange request token for access token
 
			/*
			Once a user has given us permissions we need to exchange that request token for an access token
			we will populate our localStorage here.
			*/
			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]);
 
						// Save access token/key in localStorage
						var accessData = {};
						accessData.accessTokenKey = accessParams.oauth_token;
						accessData.accessTokenSecret = accessParams.oauth_token_secret;
 
						// SETTING OUR 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);
 
									// FOR EXAMPLE ONLY
									app.init();
								},
								function(data) {
									console.log("ERROR: " + data); 
								}
						);
 
						// Since everything went well we can close our childBrowser!                             
						window.plugins.childBrowser.close();
				},
				function(data) { 
					console.log(data);
 
				}
			);
		}
		else {
			// do nothing	
		}
	},

awesome. Still with me? We’re almost done!
Last step is to tweet!

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
        tweet:function(){
		var storedAccessData, rawData = localStorage.getItem(twitterKey);
 
			storedAccessData = JSON.parse(rawData); // Parse our JSON object
			options.accessTokenKey = storedAccessData.accessTokenKey; // This is saved when they first sign in
			options.accessTokenSecret = storedAccessData.accessTokenSecret; // this is saved when they first sign in
 
			// jsOAuth takes care of everything for us we just need to provide 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();
					}
			);
	},
	/*
	Now that we have the information we can Tweet!
	*/
	post:function(){
		var theTweet = $("#tweet").val(); // Change this out for what ever you want!
 
		oauth.post('https://api.twitter.com/1/statuses/update.json',
                    { 'status' : theTweet,  // jsOAuth encodes for us
                      'trim_user' : 'true' },
                    function(data) {
                        var entry = JSON.parse(data.text);
						console.log(entry);
 
						// FOR THE EXAMPLE
						app.done();
                    },
                    function(data) { 
						console.log(data);
                    }
            );		
	}

AND DONE! If you’ve replaced all the correct spots with your information you should be able to save and run!

You should be greeted with a screen like this if all went well

Hopefully this helps you out!

DOWNLOAD

This entry was posted in phonegap and tagged , , , . Bookmark the permalink.

11 Responses to phonegapTwitterApp

  1. Paul says:

    Have you used both the Twitter and Facebook methods on this blog simultaneously?

    So far, I haven’t been able to get them both working together within my app.

    I have, however, been able to get both buttons on the same page, but only the Facebook on works. Since these two methods share ID’s, I changed all the ID’s on the Twitter HTML, CSS and JS, which are the same in the Facebook code, and gave them a prefix of “twit-”:

    EX: login = twit-login

    I also did the same to how it’s called in the body from the Javascript:

    function Init()
    {
    app.bodyLoad();
    app2.bodyLoad(); //This is the Twitter call
    }
    <body onload="Init();">

    I also changed the VAR in the Init.js (For Twitter which I renamed: twit-init.js) to “app2″, and all corresponding code.

    This has gotten me only to where I now have a Twitter login button sharing the same page with the Facebook button, but no functionality for Twitter. My guess it has something to do with them sharing the ChildBrowser?

    When I tap on the Twitter login button, I get this error in Xcode 4.2:

    [INFO] ERROR: [object Object]

    • Drew says:

      Hey Paul,
      I have used them both. The examples aren’t set up exactly how you would do it, but I will put together another post about cross posting to each and getting permissions from each.

      Give me a bit as I am pretty slammed with work at the moment.

      Think of it this way though –
      You have each twitter and facebook objects and each has an init where we ask for permissions. You should be able to just have both in your main js file and call them as needed. Same with their post methods. Be sure you have all your localStorage set as well.

      • Paul says:

        Thanks, no hurry. It’s my first app I’m building, which is just a personal project for learning experience.

        I’ll look into your advice. Thanks!

  2. mayank says:

    I’m using above code it will genereate a pin
    “return to and enter the following PIN to complete the process. 1234567″

    What can i do. I m stuck

  3. Rajeev says:

    Wonderful work. I appreciate the help..

  4. vishal says:

    Hello Drew,

    Thanks for the valuable tutorials, i am able to integrate facebook within my app but i get an error msg when i try integrate twitter within my app. The error is :

    ERROR: {“text”:”Failed to validate oauth signature and token”,”xml”:”",”requestHeaders”:{},”responseHeaders”:{“X-Runtime”:”0.01167″,”Date”:”Wed, 23 May 2012 13:23:50 GMT”,”Content-Encoding”:”gzip”,”X-MID”:”01fc6cd4d4cc4f17e8ed00eb1187bbc1ab4474dc”,”Status”:”401 Unauthorized”,”Content-Length”:”62″,”Pragma”:”no-cache”,”Last-Modified”:”Wed, 23 May 2012 13:23:50 GMT”,”Server”:”tfe”,”X-Frame-Options”:”SAMEORIGIN”,”Vary”:”Accept-Encoding”,”Content-Type”:”text/html; charset=utf-8″,”Cache-Control”:”no-cache, no-store, must-revalidate, pre-check=0, post-check=0″,”Set-Cookie”:”_twitter_sess=BAh7CDoPY3JlYXRlZF9hdGwrCOUl3nk3ASIKZmxhc2hJQzonQWN0aW9uQ29u%250AdHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7ADoHaWQiJTAy%250AZjNhNmJiNGVhMWE1YmY2ZmUzOWRkZDU2NmMyOWNh–d6f23c3448f075f91f2a1907158a22babee329fa; domain=.twitter.com; path=/; HttpOnly”,”X-Transaction”:”14ee8118d331e2d8″,”Expires”:”Tue, 31 Mar 1981 05:00:00 GMT”}}

    Could you please help in resolving this error. I have to integrate twitter asap within the app.

    • Drew says:

      Hi Vishal,
      I would double check your settings on twitter to make sure you’ve set the correct domain as your callback url… It’s not super important but there needs to be one. I’ve got mine set to just go to something like http://www.drewdahlman.com, also make sure that same domain is in the locationChange event function.

      When our app detects a URL change in the child browser it checks to see if it matches our set domain, if it does then we grab all the data and are set.

      Let me know!

  5. vishal says:

    Hi Drew,

    when i am running your code on simulator its working fine. But when i am integrating that code in my Application its not working. its give me the error which i have mentioned above.
    I have made some changes while integrating the twitter code to my app which are:

    oauth.get(‘https://api.twitter.com/oauth/access_token?oauth_verifier=356890674-BaPH4mCxx29ka48hM8FqNmvs1fcgxxhSbhtQZ8Ew&’

    Please help me here to understand why its not working.

    I am using phonegap 1.4.1 is that an issue also i have integrated the facebook on my app which was taught by you.

    Regards
    Vishal

  6. Anenth Guru says:

    Thanks a lot for the detailed tutorial. I was struggling to do Phonegap + Twitter integration and this article was a true time saver!

  7. Andrew Barker says:

    Hi Drew,

    Great article,

    I’m trying to work with Twitter natively as part of iOS5. In my Phonegap app I have included the TwitterPlugin (https://github.com/phonegap/phonegap-plugins/tree/master/iOS/Twitter) and I am abale to check if Twitter is available and send tweets via the inbuilt Twitter functionality in iOS5.

    However I would like to be able to get the users Twitter accounts stored on the device. So I have two Twitter accounts on my device and I would like my Phonegap app to be able to go and display those two account in my app.

    Do you have any ideas on how to do that? Have you tried?

    Thanks :)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>