The main reason I picked CouchDB is because I want the application can be operated offline and can be easily replicated with others servers/clients, I do have over 10 years experience with Lotus Notes, therefore, it won't be too difficult for me to pick up CouchDB since they are all document-based databases.
Following are the resources for this project, all FREE! Thank you open-source communities!
- Android 2.2 - Android Developer site
- CouchDB 1.0.1 - you need to download both for PC and Android
- Sencha Touch 1.0 - Get your green tea here
- PhoneGap 0.9.2 - download page
The goal of this project was to display the Sencha list view on Android device with user names, user's icons and pop out the game the user paying on facebook if the arrow button pushed. All the users information will be stored on CouchDB and retrieve by JavaScript codes through Ajax.
Since I just wanted to build a very simple CouchDB database the only tool I used was "Futon" which came with the database itself. It is really not a very handy tool since any carriage return will cause an error, I just need to squeeze all codes together. I started with the database named "facebook" and create documents with fields - firstname, lastname and game (array)
To test the attachment function, each document I attached a 48x48 icon (png format) file.
A view named "all" was created under design document "_design/facebook" which was prepared for using under "foo" list.
A list named "foo" was created under design document "_design/acdc", the purpose of this list is to respond the Ajax call from our main program index.html makeJSONPRequest function. It will respond back as a JavaScript code with all necessary data in JSON format.
The URL of this list is http://127.0.0.1:5894/facebook/_design/acdc/_list/foo/facebook/all which will be called by our Ajax routine under index.html with a proper callback parameter, on this screen "undefine" is displayed in the beginning since it was just a test dump without assigning callback parameter.
Again! I did all my updates on CouchOne server first, then replicated with the database on my Android devices.
When running the Android application the data retrieving from CouchDB is from localhost(127.0.0.1) port 5894 which deems as the cross domain activity, therefore, we will need to implement JSONP (JSON Padding) to make our Ajax tasks work. For a detail Sencha JSONP solution you can reference here. However, the cross-domain security policy does not affect PhoneGap applications. Since the html files are called by webkit with the file:// protocol, the security policy does not apply. You still can use the Schena Ext.Ajax.request to get the same result. For the sample codes of Ajax call you can see here.
When running the Android application the data retrieving from CouchDB is from localhost(127.0.0.1) port 5894 which deems as the cross domain activity, therefore, we will need to implement JSONP (JSON Padding) to make our Ajax tasks work. For a detail Sencha JSONP solution you can reference here. However, the cross-domain security policy does not affect PhoneGap applications. Since the html files are called by webkit with the file:// protocol, the security policy does not apply. You still can use the Schena Ext.Ajax.request to get the same result. For the sample codes of Ajax call you can see here.
After finishing the database part, let's create a new Android project under Eclipse and name it "turkey" -
from the PhoneGap download earlier, find the following two files:
Android/phonegap-0.9.2.jar
Android/phonegap-0.9.2.js
In the root directory of the project you created in Eclipse, create two new directories:
/libs
/assets /www
Now copy
Android/phonegap-0.9.2.jar to /libs
Android/phonegap-0.9.2.js to /assets/www
add phonegap-0.9.2.jar to build path
Modify the main java file and AndroidMainifest.xml as specified here.
From the unzipped download Sencha files, copy the sencha-touch-1.0/resource/css/sencha-touch.css and sencha-touch-1.0/sencha-touch.js to 'www" folder, (use sencha-touch-debug-w-comments.js if you need to debug under Sencha codes)
Sencha Touch sample codes have very detail examples, especially the kitchensink example. My goal is to create a nice looking List view, therefore I went for the code under sencha-touch-1.0/examples/list/ folder, to make easy to explain I moved the index.js codes into index.html and did necessary modifications.
Following is the source code of index.html, the function "makeJSONPRequest" is the codes I added to retrieve CouchDB facebook database data.
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Turkey Trouble</title> <link rel="stylesheet" href="sencha-touch.css" type="text/css"> <script type="text/javascript" src="sencha-touch.js"></script> </head> <body> <div id='acdc'></div> <script type="text/javascript"> var arr=[]; function layout(ar) { Ext.setup({ tabletStartupScreen: 'tablet_startup.png', phoneStartupScreen: 'phone_startup.png', icon: 'icon.png', glossOnIcon: false, onReady : function() { Ext.regModel('Contact', { fields: ['firstName', 'lastName', 'game', 'id', 'img', 'game'] }); var groupingBase = { itemTpl: '<div class="contact2">{firstName} {lastName}</div><div><img src="http://127.0.0.1:5984/facebook/{id}/{img}"></div>', selModel: { mode: 'SINGLE', allowDeselect: true }, grouped: true, indexBar: true, onItemDisclosure: { scope: 'test', handler: function(record, btn, index) { alert( record.get('firstName') + ' play '+ record.get('game') ); } }, store: new Ext.data.Store({ model: 'Contact', sorters: 'firstName', getGroupString : function(record) { return record.get('firstName')[0]; }, data: ar }) }; if (!Ext.is.Phone) { new Ext.List(Ext.apply(groupingBase, { floating: true, width: 350, height: 370, centered: true, modal: true, hideOnMaskTap: false })).show(); } else { new Ext.List(Ext.apply(groupingBase, { fullscreen: true })); } } }); } function makeJSONPRequest() { Ext.util.JSONP.request({ url: 'http://127.0.0.1:5984/facebook/_design/acdc/_list/foo/facebook/all', params: {}, callbackKey: 'callback', callback: function(result) { if (result) { arr = []; for (i=0; i< result.rows.length; i++){ arr.push({id: result.rows[i].id, img: result.rows[i].img, game: result.rows[i].game, lastName: result.rows[i].lastName, firstName: result.rows[i].firstName}); } layout(arr); } else { alert('There was an error retrieving the data.'); } } }); } Ext.onReady(function() { makeJSONPRequest(); }); </script> </body> </html>
The CouchDB _design/acdc file -
{ "_id": "_design/acdc", "_rev": "47-c4692b5daf6ffa5b74461ea0591c1e5d", "language": "javascript", "lists": { "bar": "function(head, req) { var row; var firstrow=1; start({ 'headers': { 'Content-Type': 'application/javascript'} }); send(req.query.callback+'({\"rows\":['); while(row=getRow()){ if(firstrow==1){firstrow=0;} else {send(',');} send('{\"id\":\"' + row.id + '\",\"firstName\":\"' + row.value.firstName + '\",\"lastName\":\"' + row.value.lastName + '\"}');} send(']});');}", "foo": "function(head, req) { var row; var img=''; var game=''; var firstrow=1; start({ 'headers': { 'Content-Type': 'application/javascript'} }); send(req.query.callback+'({\"rows\":['); while(row=getRow()){ if(firstrow==1){firstrow=0;} else {send(',');} if(row.value.game){game=row.value.game[0];} if(row.value._attachments){for (n in row.value._attachments) { img=n;} } send('{\"id\":\"' + row.id + '\",\"firstName\":\"' + row.value.firstName + '\",\"lastName\":\"' + row.value.lastName + '\",\"game\":\"' + game + '\",\"img\":\"' + img + '\"}');} send(']});');}" } }I installed the CouchDB on Mac and used Google Chrome to debug the JavaScript codes first, then ported the code to Eclipse, since I haven't figured out a way to install CouchDB on Android emulator, I had to run the program directly on devices to test. The following screenshot is the program running on EVO 4G -
When click at arrow it shows what game the person play -
Cross Domain Issues on CouchDB and Sencha Touch
Cool post. Thanks! Keep in mind that if you ever want to distribute a closed-source Android app with Sencha Touch, you'll need a commercial license for it, since the free/open-source license is GPL. I find that a bit disappointing, but I realize they need to make a living.
ReplyDelete--Matt
Awesome post.Will definitely try out sencha for my mobile applications.
ReplyDeleteI've got a lot of sencha code waiting to be ported :D
Sephiroth