The Official Ionic Blog

Build amazing native and progressive web apps with HTML5

This is a guest post by Simon Reimler, software developer at arvato Bertelsmann, experienced with iOS, Android, AngularJS, Ionic and Python. Simon often writes about Ionic, web and mobile development. Read more on Simon’s Blog, DevDactic.

Getting the Twitter timeline of a user into your Ionic app can be a challenging task. Lucky for us, we can use the simple ngCordova OAuth wrapper previously described by Nic Raboy to solve the basic authentication. But what happens after the token authentication?

In this post, I will take things one step further and show you how to authenticate with OAuth, make signed calls to the well documented Twitter REST API, and parse the home timeline of a user inside your Ionic app.

Set Up a Simple App

We’ll start with a simple blank Ionic app, install ngCordova and ngResource (needed for the REST calls later) via the bower package manager and add a Cordova plugin we will need for the OAuth:

ionic start devdactic-twitterfeed blank --appname “My Twitter Feed”
cd devdactic-twitterfeed
bower install angular-resource ngCordova --save
cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-inappbrowser.git

Additionally, we need the jsSHA Library inside our project, because Twitter requires request signing using HMAC-SHA1. Go to the jsSHA Github project, download it, and copy the sha.js file from the archive into the www/lib/ folder of your app.

Now, we need to include all these files inside our index.html. Make sure to add the ngCordova file before the cordova.js script tag that is already included! We also already included our services, and later, we will create and add a controller.

<!-- Before cordova.js -->
<script src="lib/sha.js"></script>
<script src="lib/angular-resource/angular-resource.js"></script>
<script src="lib/ngCordova/dist/ng-cordova.js"></script>

<!-- After cordova.js -->
<script src="js/controllers.js"></script>
<script src="js/services.js"></script>

Finally, we must add the dependencies to our AngularJS module inside our app.js file:

angular.module('starter', ['ionic', 'ngResource', 'ngCordova'])

Our app is now ready to connect with Twitter. The last thing we must do is to create an app on Twitter that will give us the credentials we need. Go to the Twitter Application Management page and create a simple app.

After creation, we need to change the callback URL of our Twitter app to http://localhost/callback. As this is currently not possible via Twitter, make yourself a tiny URL, and insert that one instead.
Leave the created app for now; we will need to copy some keys from it in a later step.

Writing a Twitter Service

The heart of our app will be the TwitterService, which will handle our calls to the REST API and give us the data we need. Therefore, create a new file named services.js next to the app.js file, and insert this (I will discuss the functions in detail afterwards):

.factory('TwitterService', function($cordovaOauth, $cordovaOauthUtility, $http, $resource, $q) {
    // 1
    var twitterKey = "STORAGE.TWITTER.KEY";
    var clientId = 'TwitterAppConsumerKey';
    var clientSecret = 'TwitterAppConsumerSecret';

    // 2
    function storeUserToken(data) {
        window.localStorage.setItem(twitterKey, JSON.stringify(data));
    }

    function getStoredToken() {
        return window.localStorage.getItem(twitterKey);
    }

    // 3
    function createTwitterSignature(method, url) {
        var token = angular.fromJson(getStoredToken());
        var oauthObject = {
            oauth_consumer_key: clientId,
            oauth_nonce: $cordovaOauthUtility.createNonce(10),
            oauth_signature_method: "HMAC-SHA1",
            oauth_token: token.oauth_token,
            oauth_timestamp: Math.round((new Date()).getTime() / 1000.0),
            oauth_version: "1.0"
        };
        var signatureObj = $cordovaOauthUtility.createSignature(method, url, oauthObject, {}, clientSecret, token.oauth_token_secret);
        $http.defaults.headers.common.Authorization = signatureObj.authorization_header;
    }

    return {
        // 4
        initialize: function() {
            var deferred = $q.defer();
            var token = getStoredToken();

            if (token !== null) {
                deferred.resolve(true);
            } else {
                $cordovaOauth.twitter(clientId, clientSecret).then(function(result) {
                    storeUserToken(result);
                    deferred.resolve(true);
                }, function(error) {
                    deferred.reject(false);
                });
            }
            return deferred.promise;
        },
        // 5
        isAuthenticated: function() {
            return getStoredToken() !== null;
        },
        // 6
        getHomeTimeline: function() {
            var home_tl_url = 'https://api.twitter.com/1.1/statuses/home_timeline.json';
            createTwitterSignature('GET', home_tl_url);
            return $resource(home_tl_url).query();
        },
        storeUserToken: storeUserToken,
        getStoredToken: getStoredToken,
        createTwitterSignature: createTwitterSignature
    };
});
  1. Insert your personal Consumer and Consumer Secret Key from the Twitter app you created in the preparation step. The Storage key is just for your localStorage, so change it to whatever you like.

  2. The first two functions are just for storing and retrieving the OAuth Token once the user is successfully authorized; nothing special here.

  3. createTwitterSignature is one of the most important functions here, because this function takes care of the correct signing of our requests. When called, we give it the HTTP method, like GET or POST, and the URL from which we want to get the data. The function will then read the OAuth Token from localStorage and create an object with some more general stuff the Twitter REST API requires, like the Consumer Key and the OAuth Token. This object is then passed to the $cordovaOauthUtilityof ngCordova to create a correct authorization object, which will be set as the authorization header of our request. For more detailed information about OAuth 1.0a, check out Nic Raboy’s blog post!

  4. After this function, we come to the returned object of our TwitterService. The initialize function will be called on our app startup. This function looks for a stored OAuth token that could be used for signing, but if it is not present, it will try to authorize the user with the help of $cordovaOauth, where we again need the Consumer Key and Consumer Secret.
    This ngCordova wrapper will slide up a Twitter authorization form to the user, where the user must enter his/her credentials. Finally, we return a promise from this function to get informed about a correct/failed authorization in our controller.

  5. The isAuthenticated function is very simple and only checks for a stored token. Keep in mind that users could revoke their permissions for an app, so here you might add a token verification check in a real app.

  6. Finally the getHomeTimeline function can be called to retrieve our home timeline feed. Here, we create our signature for the request for the associated URL and return the request as a resource object. To learn more about this, check out my ngResource blog post.

Accessing the data from our Controller

After we have our service, we need to create the controller for our app, so go ahead and create a controllers.js. Now, open your created file, and insert this:

.controller('AppCtrl', function($scope, $ionicPlatform, TwitterService) {
    // 1
    $scope.correctTimestring = function(string) {
        return new Date(Date.parse(string));
    };
    // 2
    $scope.showHomeTimeline = function() {
        $scope.home_timeline = TwitterService.getHomeTimeline();
    };
    // 3
    $scope.doRefresh = function() {
        $scope.showHomeTimeline();
        $scope.$broadcast('scroll.refreshComplete');
    };
    // 4
    $ionicPlatform.ready(function() {
        if (TwitterService.isAuthenticated()) {
            $scope.showHomeTimeline();
        } else {
            TwitterService.initialize().then(function(result) {
                if(result === true) {
                    $scope.showHomeTimeline();
                }
            });
        }
    });
});

Our controller is rather simple now, as we have all our REST interaction logic inside our service. Anyway, let’s take a closer look at our functions:

  1. As our feed object from Twitter returns a quite unformatted date string, we need to convert the string to a more readable date to display.

  2. The showHomeTimeline function will fill our home_timeline array with the feed data we get from our service.

  3. As we will have a pull-to-refresh inside our view, we need a function to update the feeds array.

  4. When our platform is ready, we check if the user is already authenticated and initially fill the array. If not, we call our initialize from the service to show the login view to the user to perform the OAuth authentication.

That’s pretty much everything we need for a simple Twitter feed!

Showing Feeds Inside Our View

After we have a service to get the data from Twitter and a controller to hold our received data, we need an appropriate view to show the feeds in a Twitter-like style. For this, open the index.html and replace the dummy body with this:

<body ng-app="starter" ng-controller='AppCtrl'>
  <ion-pane>
    <ion-header-bar class="bar-positive">
      <h1 class="title">My Twitter Feed</h1>
    </ion-header-bar>
    <ion-content class="has-header padding">
      <ion-refresher on-refresh="doRefresh()"></ion-refresher>

    <div ng-show="home_timeline.length == 0">Loading tweets...</div>

    <div ng-repeat="entry in home_timeline" class="list card">
      <div class="item item-avatar">
        <img ng-src="{{entry.user.profile_image_url}}"/>
        <h2>{{entry.user.name}}</h2>
        <p>{{correctTimestring(entry.created_at) | date:'medium'}}</p>
      </div>

      <div class="item item-body">
        <p ng-bind-html="entry.text"></p>
        <img ng-if="entry.extended_entities" ng-src="{{ entry.extended_entities.media[0].media_url }}" style="width: 100%;"/>
      </div>

    </div>
  </ion-content>
</ion-pane>
</body>

Inside our view, we first have the refresher, which allows us to use pull-to-refresh. Next, if our feed’s array is empty, we just display a little dummy text.

The main part is the ng-repeat to iterate over the feed objects. Here, we make use of the Ionic cards, where we have the profile image of the user as an item-avatar, the username, our corrected time string in the top area, and inside the body of our card the text of the tweet. Additionally, if some media inside the feed data is set, we display the posted image below the content.

Final Words and Outlook

This tutorial shows a straightforward way to display Twitter feed data in an appropriate way inside your Ionic app. There are many more endpoints in the Twitter REST API, so make use of the newly created TwitterService and get the data you need!
Additionally, you could parse the feed data a bit more through a filter to make links clickable. Check out my blog for an upcoming post about this topic!

If you have any questions, issues, or ideas, please leave a comment below and/or follow me @schlimmson on Twitter.

A video version of this article can be seen below.

  • http://santoshshinde2012.blogspot.com Santosh Shinde

    I have try to your steps for android but its not working , Please share your code on github..Thank you .

  • David Mauricio Jiménez López

    Hi, I follow your steps, but…

    • Luis Fernando Alves

      I have the same error… I wonder if anything changed with the Twitter API recently… Simon, please check if ur code is still working. I see that here in the comment section there are plenty of people getting errors…Maybe upload it to github to see what we are doing wrong…

  • David Mauricio Jiménez López

    Like on the phone run ionic run android

  • http://randomprimate.com Jose Torres

    Thanks for the post, I’ve run into some errors which I hope you can help me with. I’m getting a token null error on the console when reloading and no app authentication either. Testing on the browser with ionic serve, is this the problem?

    • Andrew Sargison

      Hi, i am getting the same ‘null’ through the error handler on $cordovaOauth.twitter(… Did you manage to solve this? I am only testing using the emulator.

  • Satya

    Hi Simon
    I followed the tutorial, and the twitter login screen is not show up for me..
    Can you share the complete code on github please..!!

    • malaise

      have you download the good version of SHA ?
      bower install jsSHA#1.6.0

  • darrenkitlor

    For everyone below, a lot of native functionality involving ngCordova won’t display in your browser. You’ll need to push the tutorial directly to your device or run it in an emulator. ngCordova won’t run in Firefox, etc.

  • MisterJack49

    I’d like to import a feed in my app but without login the user, it would be a public feed, where you can see tweets without login in, like this one https://twitter.com/irigobustram even disconnected I can see tweets

  • http://devdactic.com/ Simon Reimler

    Just wanted to let you know that I created a new version of this post where I simplified the Twitter integration process by using my created AngularJS library ngTwitter: http://blog:http://devdactic.com/twitter-rest-api-angularjs/

  • Tadahiro Okamoto

    Thanks for the post, but how to debug the application using ng-cordova-oauth? Because we can’t use live reload server (it means that we can’t use “console.log”, right?) with ng-cordova-oauth.

  • Prakash

    But still i can not signup using twitter. It returns nothings. I have used ngcordova oauth http://ngcordova.com/docs/plugins/oauth/

  • Sabin Hiworth

    is that possible to share a status without loggin in on twitter?

  • thulani mtetwa

    Please advise me on how to bypass authorisation of the application if I already have Access Tokens.

  • Naveen

    Hi, I am getting below error –

    services.js:26 Uncaught TypeError: Cannot read property ‘oauth_token’ of null

  • Naveen

    How can I fix it?

  • http://www.lifehack.org/523384/6-android-hacks-you-never-knew-existed Carl

    thanks for the marvelous posting! I seriously enjoyed reading it, you happen to be a great author.I will remember to bookmark your blog and will come back in the future. I want to encourage yourself to continue your great posts, have a nice day! lucky patcher for ios