PhoneGap RSS Reader - Part 4

This post is more than 2 years old.

Edited on August 4, 2012: Readers noted that this version didn't correctly handle trying to load the cache when offline. I confirmed that and posted a fix in the comments.

For whatever reason, my articles on PhoneGap and RSS (see related entries below) have been incredibly popular. The last entry currently has 163 comments. Some of the comments deal with the fact that RSS, while a standard, does have a bit of variation to it. My code made some assumptions that didn't always work for other feeds. I thought this was a great opportunity to look at ways I could make the code more applicable to other types of feeds, especially Atom. Luckily, there is an awesome service for this - the Google Feed API.

As you can probably guess, the Google Feed API allows you to parse RSS feeds into simple to use data. It takes any valid RSS or Atom feed and parses it into a simple, standard data model. While the previous code I used wasn't too difficult, it was also very tied to one particular flavor of RSS. I could have continued to add in support for multiple styles of RSS feeds but this seemed far easier to me.

To begin, I added a script tag to load in the Google Loader. This is service Google provides that allows you to dynamically include in JavaScript support for various Google APIs.

<script type="text/javascript" src="https://www.google.com/jsapi"></script>

To load in support for the Feed API, I modified my mainPage pageinit event handler to ask Google Load to go grab the bits. It is very important that you provide the callback option to this API. If you do not, Google Load will blow away the jQuery Mobile DOM completely.

Now let's look at initialize. Previously, this is the portion that would have done the Ajax call, used XML parsing on the results, and stored the entries. Because Google's Feed API is doing this for me the code is now somewhat simpler. (I also added support for jQuery Mobile's "showPageLoadingMsg" API to make it obvious to the user that something is happening.)

And that's pretty much it. My previous code stored the content of the RSS item in a key named content. Google uses a key named description so I modified my display code.

As a final enhancement, I decided to make use of PhoneGap Build to create my mobile application. This allowed me to define a simple config.xml file to help define how the executables are generated. For example, I was able to provide simple icon support. (The icons I used were provided by Fast Icon.)

You can see my application at the bottom here in the screen shot. And yes - I have a Selena Gomez app. Don't hate me for downloading apps my daughter loves.

Want to download the app yourself? Try the public Build page for every platform but iOS. You can also download all of the bits below.

Download attached file.

Raymond Camden's Picture

About Raymond Camden

Raymond is a developer advocate for HERE Technologies. He focuses on JavaScript, serverless and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by HuabinZhang posted on 7/18/2012 at 1:14 PM

Thanks for the tip Raymond!I ever wrote an RSS Reader with phonegap.I also used google feed api.But I met a lot of problems.Most important of all is 'google.load("feeds", "1",{callback:initialize});'. I just wrote it like 'google.load("feeds", "1")'.In addition to this?I thisk it wastes time to download js from google.It may use google feed api by google URL base addresses,like 'https://ajax.googleapis.com... trying your code, I found app can not show cached version without network,which was not a problem in previous version.

Comment 2 by Raymond Camden posted on 7/18/2012 at 7:36 PM

Did you see where I described why google.load won't work w/o the 3rd option? That hit me too which is why I described it above.

So - you say the cached version isn't working when offline. I'll give that a test. If I forget to ping back, remind me. :)

Comment 3 by DeadTechnology posted on 7/26/2012 at 1:07 AM

Tried building this in Dreamweaver CS6 and getting stuck when building for Android. error is Resource icon already defined. Not sure if this was meant for Dreamweaver, but kinda stuck now. Works in a browser tho.

Comment 4 by Raymond Camden posted on 7/26/2012 at 1:08 AM

Sorry - I don't have DW CS6 here so I can't test. I'd post it to the Adobe forums for DW. Also, you can try using Build yourself. Just login to build.phonegap.com and upload the code.

Comment 5 by DeadTechnology posted on 7/26/2012 at 7:22 AM

Ok, so I guess it was my fault. I redownloaded, and screwed with it less and hey - now it works. How about that?

Comment 6 by Raymond Camden posted on 7/26/2012 at 2:35 PM

Happens to me all the time. :)

Comment 7 by Andy posted on 7/30/2012 at 5:08 AM

Code works well except when offline. Given the index.html header includes src="https://www.google.com/jsapi"

Wouldn't that kill the possibility of using a cached version offline.

Is there any reason why we couldn't just download the source and include it in the app? TOS perhaps :p

Comment 8 by Raymond Camden posted on 7/30/2012 at 5:28 AM

Well, to be clear, even if you had a copy of Google's code in the app, it wouldn't help you parse the remote RSS feed, right?

Comment 9 by Andy posted on 7/30/2012 at 11:39 AM

Yes. After the remote feed has been read at least once in order to be cached to localStorage and with jsapi stored locally, not having much success getting it to display the stored feed while offline.

Comment 10 by Raymond Camden posted on 7/30/2012 at 3:28 PM

Yeah, someone higher mentioned that too. This week I'll look into that bug and fix it. Sorry.

Comment 11 by Raymond Camden posted on 8/4/2012 at 4:26 PM

Ok guys, I created a new version of main.js that handles this. NOTE - this is one way of handling, not necessarily the best way.

I could have used cordova.js and check the connection, but instead, I simply wrap google.load in a try/catch. The nice thing about this is that it is actually 'broader' then just a network connection test.

If it fails, we try to load the cached version:

https://gist.github.com/325...

Comment 12 by soumavo chatterjee posted on 8/6/2012 at 1:48 PM

How can I parse logo using this API

Here is the xml http://www.morningstaradvis...

Comment 13 by Raymond Camden posted on 8/6/2012 at 3:27 PM

From what I can see in the docs, the logo field is not returned. You will need to switch to using XML parsing as demonstrated in the earlier posts in this series.

Comment 14 by Mike Taylor posted on 8/16/2012 at 6:04 PM

Any reason why this would work great on an iphone4 but not load on an ipad3?

Comment 15 by Raymond Camden posted on 8/16/2012 at 6:12 PM

Nope. I don't have an iPhone, just an iPad3. I don't remember testing it there... but it should work fine. You -do- need to whitelist the URL, but that would apply to all iOS devices, not just the iPad3.

Comment 16 by Raymond Camden posted on 8/16/2012 at 6:18 PM

As just an FYI, I'm testing this now. I had not had a chance to get XCode installed on this new Mac so this is a perfect opportunity.

Comment 17 by Raymond Camden posted on 8/16/2012 at 7:32 PM

Finally got stuff up and running... and it works for me on my iPad3.

Comment 18 by Andy posted on 8/24/2012 at 2:27 PM

The new version works brilliantly.

Thanks Raymond for updating it. :)

Comment 19 by Chris posted on 12/4/2012 at 7:22 PM

Thanks for this - it's working really well for me! One question I have is about the "target" attribute on URLs. The links in my blog's posts all use target="_blank" to fire off a new window, but that appears to be getting stripped out and links are replacing the app itself (I want them to open a new browser).

Any idea what would be doing that? Not sure if it's your code, Google, or what...

Thanks.

Comment 20 by Raymond Camden posted on 12/4/2012 at 7:47 PM

I'd add a jQuery event handler that binds to the anchor tag and detects if it has a target. I believe this would do it:

$("a[target]")

That would match anything with a target. This may be more precise:

$("a[target='_blank']")

Anyway - capture that, and you can handle the links as you want, like with the ChildBrowser plugin for example.

Comment 21 by Chris posted on 12/4/2012 at 8:39 PM

Excellent, thank you!

Comment 22 by George posted on 7/8/2013 at 11:24 AM

Hello, i have used your example but i'm having a small problem with the scrolling. if i tested it with the ripple on my computer is working fine and loads 10 posts but if i tried with my mobile device i can scroll only 2 and if i remove my finger from the screen is coming to the first post. how i can fix it?

Comment 23 by Raymond Camden posted on 7/8/2013 at 2:05 PM

What device is this?

Comment 24 by Carla posted on 9/24/2013 at 11:35 AM

First of all, congratulations for your blog, it's really helpful! I have downloaded the code (Part 4) and I'm trying to test it on my devices. On Android works well but I canĀ“t run it on iOs. The problem is that the main screen is freezing (an activity indicator appears) and I can't see the list of rss entries. I think I have set the iOs certificates in the correct way. Any idea? I'm stuck on this for three days... Thanks!

Comment 25 by Raymond Camden posted on 9/24/2013 at 2:19 PM

Are you building it with PhoneGap Build?

Comment 26 by Carla posted on 9/24/2013 at 7:12 PM

Yes, I'm using PhoneGap Build. I've changed the package name in context.xml file, create the zip and set the .mobileprovision and the .p12 certificates. Is necessary some additional step? Thanks in advance.

Comment 27 by Raymond Camden posted on 9/24/2013 at 8:07 PM

Not sure what to recommend. I'd first see if you could run the code locally w/o making a build. You may see an error reported then. Please note that in order to do that, you will want to run deviceready manually. You can also try Safari Remote Debugging and connect to your app that way.

Comment 28 by Ishank posted on 4/10/2014 at 2:50 PM

Raymond, can you help me with it I'm unable to fetch google feed; it's not loading.Here is the code
-
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="format-detection" content="telephone=no" />
<!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/j... -->
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
<link rel="stylesheet" type="text/css" href="css/index.css" />
<title>Testly</title>
</head>
<body>
<div class="app">
<h1>PhoneGap</h1>
<div id="deviceready" class="blink">
<p class="event listening">Connecting to Device</p>
<p class="event received">Device is Ready</p>
<a href="#" onclick="var ref = window.open('http://cnn.com', '_blank', 'location=yes,toolbar=yes');">CNN Link</a>
</div>
<div class="f">loading...</div>
<script type="text/javascript" src="phonegap.js"></script>
<script>
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
document.addEventListener("backbutton", function (e) {
e.preventDefault();
}, false );
} </script>
<script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("feeds", "1", {'nocss' : 1});
function OnLoad() {
var feedControl = new google.feeds.FeedControl();
feedControl.setNumEntries(25);
feedControl.addFeed("http://feeds.feedburner.com...");
feedControl.draw(document.querySelector(".f"));
}
google.setOnLoadCallback(OnLoad);
</script>
<style>
.f{
margin:20px;
overflow:scroll;
width:400px;
height:400px;
}
</style>
<script type="text/javascript">
app.initialize();
</script>
</body>
</html>

Comment 29 by Raymond Camden posted on 4/10/2014 at 3:20 PM

First, please do not post large blocks of code in comments. Use a Pastebin or Gist instead. Secondly, I'd suggest doing some debugging so you can figure out where it isn't working. You can check the network requests to see if it comes through. You can see if there is a JS error. Basically, you need to do a bit more work to determine *where* it is failing.

Comment 30 by max posted on 6/12/2015 at 6:50 PM

HI,

Very good work!

I want to add more ress feeds, from 3 blogs that I'm following.

How I can do it?

Comment 31 (In reply to #30) by Raymond Camden posted on 6/21/2015 at 1:11 PM

You would need to parse all the feeds and then combine them into one array. You could use promises to make this a bit easier.