Parsing Rss With Javascript And Phonegap
I just released an RSS news reader app built with HTML5 and Phonegap. During the development of the app I encountered the following three problems when loading RSS feeds using the Javascript XMLHttpRequest object:
Certain RSS feeds were being sent out without an XML MIME type, causing Javascript to interpret them as text.
Some servers were detecting the AJAX RSS requests as coming from a mobile browser and redirecting to a mobile friendly HTML page.
When testing outside of PhoneGap I needed a proxy script to fetch the feeds to overcome the browser's cross-domain restrictions.
Overriding Incorrect MIME Types
The XMLHttpRequest object has an overrideMimeType
function that can be used to override a requested documents MIME type. Here's an example of a simple AJAX call where the MIME type is being forced to text/xml.
var xhr = new XMLHttpRequest(),
feed_url = 'http://some.madeupdomain.ca/feed.xml';
xhr.onerror = function() {
alert('Error loading the RSS document.');
};
xhr.onload = function() {
var xml = xhr.responseXML.documentElement,
items = xml.getElementsByTagName('item'),
title = items[0].querySelector('title').firstChild.data;
alert('The first item title: ' + title);
};
xhr.open('GET', feed_url);
xhr.responseType = 'document';
xhr.overrideMimeType('text/xml');
xhr.send();
Fooling Mobile Browser Redirections
Certain web-servers will perform a blanket mobile-device redirect, no matter what document you are trying to load. I found a few news sites that redirected me to a mobile landing page when I tried to use XMLHttpRequest to load their RSS feed. Most mobile redirects of this nature are triggered by User Agent sniffing, so I needed some way to have my application self-identify as a non-mobile browser.
PhoneGap doesn't allow us to spoof the User-Agent using Javascript. Instead I had to modify the wrapper application. Here are the required modifications to the main .java file for an Android PhoneGap application. I imagine that the WebView of an iOS PhoneGap Objective-C wrapper app could be similarily modified.
package com.yourdomain.feedtest;
import org.apache.cordova.DroidGap;
import android.os.Bundle;
import android.webkit.WebSettings; // Added.
public class FeedTestActivity extends DroidGap {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.loadUrl("file:///android_asset/www/index.html");
// Added the following two lines to spoof the user-agent to self-identify as a non-mobile browser.
WebSettings w = this.appView.getSettings();
w.setUserAgentString("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1");
}
}
Testing in the Browser Using a Proxy
When I was working on my app I did most of the initial testing using my desktop browser. The only problem is that unlike PhoneGap, browsers do not let you make cross-domain AJAX request. To overcome this I built a simple PHP proxy script that I placed on the same server as my HTML5 mobile app. I then routed all my AJAX calls through this script.
<?php
header('Content-type: application/xml');
$file = file_get_contents($_GET['url']);
$file = preg_replace('/\s+/',' ', $file); // Replace repeated whitespace with single spaces.
echo $file;
?>
With this script present in the same folder as my HTML5 web app, I could make cross-domain AJAX request like this:
var xhr = new XMLHttpRequest(),
feed_url = 'http://some.madeupdomain.ca/feed.xml',
proxy_url = 'proxy.php?url=';
/* Omitting the xhr.onerror and xhr.onload callbacks. */
xhr.open('GET', proxy_url + feed_url);
xhr.responseType = 'document';
xhr.send();
P.S. Part two of my HTML5 Mobile Tumblr App post is coming soon.