Titanium MobileアプリとMongoDBをSleepy.Mongooseを経由で接続させてみた
MongoDBにSleepy.Mongoose経由で、Titanium Mobileで作ったiPhoneアプリから接続する簡単なアプリを作ってみました。
Sleepy.Mongooseを経由したのは、MongoDBのRESTインターフェースは読み取り専用で外部ツールを使うことが推奨されていたからです。*1
The mongod process includes a simple read-only REST interface for convenience. For full REST capabilities we recommend using an external tool such as Sleepy.Mongoose.
MongoDB、Sleepy.MongooseそしてTitanium Mobileのインストールや設定などにつきましては、それぞれの公式サイトに書いてありますので、割愛させていただきます。あえて注意する事と言えば、MongoDB起動時「--rest」オプションを間違って付けないことでしょうか。
Todoアプリ
タスクの一覧(query)を表示・追加(insert)をするだけのアプリです。あくまでも勉強用なので、実用性は全くありません。また、Titanium Mobileを使ってHello World以外を作ったのもこれが初めてなので、変なコードを書いていたらどうかご勘弁を。
ソース
Titanium Developerを起動し、New ProjectでTodoプロジェクトを作成。Titanium SDKは1.5.1、iPhone SDKは4.2を選択しました。MongoDB、Sleepy.Mongoosそして本アプリは、すべてローカルで動かすことを前提にしています。
APP_ROOT/Resources/app.js
Ti.UI.setBackgroundColor('#000'); var win1 = Ti.UI.createWindow({ url: 'table_view.js', title:'List', backgroundColor:'#fff' }); var tab1 = Ti.UI.createTab({ window:win1 }); win1.hideTabBar(); var tabGroup = Ti.UI.createTabGroup({}); tabGroup.addTab(tab1); tabGroup.open();
タスクを追加するウィンドウ「taskWindow」に「done」というカスタムイベントを追加しているのは、「close」イベントを追加すると、「Back」ボタンをタップしたのか「Done」ボタンをタップしたのかわからないからです。
「Done」ボタンをタップしてタスクを追加したら、MongoDBからオブジェクトIDが戻りますので、doneイベントを発動する際、引数にこのIDを渡して、一覧を更新する方がいいんですが、面倒なんで全部再取得してtableViewに詰め込んでます。
APP_ROOT/Resources/table_view.js
var win = Ti.UI.currentWindow; var xhr = Ti.Network.createHTTPClient(); var tableView = null; function updateTable() { var find = 'http://localhost:27080/todo/tasks/_find?sort=' + encodeURIComponent('{"_id": -1}'); xhr.open('GET', find); xhr.onload = function() { var todo = JSON.parse(this.responseText); var tasks = todo.results; var data = []; for(var i = 0; i < tasks.length; i++) { var row = Ti.UI.createTableViewRow(); var label = Ti.UI.createLabel({ text: tasks[i].text }); row.add(label); data.push(row); } if(tableView == null) { tableView = Ti.UI.createTableView({ data: data }); win.add(tableView); } else { tableView.data = data; } }; xhr.send(); } var taskButton = Ti.UI.createButton({ systemButton: Ti.UI.iPhone.SystemButton.ADD }); taskButton.addEventListener( 'click', function() { var taskWindow = Ti.UI.createWindow({ url: 'task_window.js', title: 'Add Task', backgroundColor: '#fff' }); taskWindow.addEventListener( 'done', function() { updateTable(); } ); Ti.UI.currentTab.open(taskWindow); } ); win.rightNavButton = taskButton; var conn = 'http://localhost:27080/_connect'; xhr.open('POST', conn); xhr.onload = function() { updateTable(); }; xhr.send({"data":"localhost:27017"});
APP_ROOT/Resoruces/task_window.js
var win = Ti.UI.currentWindow; var textArea = Ti.UI.createTextArea({ height: 180, width: 300, top: 10, font:{ fontSize:20 }, borderWidth: 1, borderColor: '#bbb', borderRadius: 5, autocapitalization: Ti.UI.TEXT_AUTOCAPITALIZATION_NONE, suppressReturn: false }); win.addEventListener('open', function(e) { textArea.focus(); }); win.add(textArea); var doneButton = Ti.UI.createButton({ systemButton: Ti.UI.iPhone.SystemButton.DONE }); doneButton.addEventListener( 'click', function() { if(textArea.value) { var url = 'http://localhost:27080/todo/tasks/_insert'; var xhr = Ti.Network.createHTTPClient(); xhr.open('POST', url); xhr.send({"docs": '[{"text": "' + textArea.value + '"}]'}); xhr.onload = function() { win.fireEvent('done'); win.close(); }; } } ); win.rightNavButton = doneButton;
動作確認
Titanium Developer経由でiPhoneシミュレータを起動し、タスクを追加。MongoDBのシェルでinsertされているか確認。試しに、日本語の文章をテキストエリアに貼付けて追加してみましたが、文字化けはしませんでした。なお、Androidのemulatorでは動きません。
$ mongo todo MongoDB shell version: 1.6.5 connecting to: todo > db.tasks.find().sort({id:-1}) { "_id" : ObjectId("4d5b3b3a5a7a992baf000005"), "text" : "Go to Ginza." } { "_id" : ObjectId("4d5b3b4d5a7a992baf000006"), "text" : "Visit my girl friend." } { "_id" : ObjectId("4d5b50045a7a993380000000"), "text" : "日本語のテスト" }
余談
JavaScriptでiPhone/Androidアプリが作れちゃうってすごいですね。
このアプリもそうですが、やはりプラットフォーム固有の設定・動作があり、Googleでドキュメントを検索していた時、if文で分岐させているソースを見ました。でも、例えばretainCountを気にしなくてよいとか、Objective-Cでを書いてた時と比べたら格段に楽かなぁ...
MongoDBのスケーラビリティについては、また後日、時間をとって勉強してみたいと思っています。セキュリティまわりは、MongoDBにユーザ認証がありますし、Sleepy.MongooseはSSLに対応してますから大丈夫なんじゃないかと。ただ、Titanium.Network.HTTPClientがHTTPSに対応しているのかは未確認です。