Archive for the ‘SQLite’ Category

8月
13

flashcast:フリーで働くITエンジニア集団のブログ: Strayed ChildをAndroid対応(gears編)でAndroidでも現在地の住所を表示できるようにしました。今回は、Androidでも住所の保存・閲覧・削除ができるようにします。

住所の保存は、iPhone同様、SQLiteを利用します。
また、前回同様、Gears API – Google Codeを利用します。

Database2API – gears – A proposal to add native HTML5 SQL API to Gears – Project Hosting on Google Codeが利用できれば、データを処理する部分はほとんど修正する必要はなかったのですが、試してみたところ、うまくいかず、まだサポートされていないようでしたので、Database API – Gears API – Google Codeで実装しました。

データベースをオープンする処理です。

function checkGearsDbConnect() {
 var isDbConnect = true;

 try {
  db = google.gears.factory.create('beta.database');
  db.open('StrayedChild');
 }
 catch (error) {
  isDbConnect = false;
 }
 finally {
  return isDbConnect;
 }
}

iPhoneの時は、データベース名にスペースが含まれていても大丈夫だったのですが、

db = openDatabase('Strayed Child', '1.0', 'Strayed Child');

Gearsの場合はダメみたいなので、「StrayedChild」というデータベース名にしました。

SQLを実行する部分は、今後、各種ブラウザのHTML5 ローカルデータベース機能の対応動向を意識して、ユーザエージェントで処理を切り替えるような実装はあえてやめました。

function executeSql(sql, params, callback, date) {
 var result = true;

 try {
  if (db.transaction != null) {
   db.transaction(
    function(transaction) {
     transaction.executeSql(sql, params,
      function(transaction, resultSet) {
       if (callback) {
        callback(resultSet, date);
       }
      }
     );
    },
    function(error) {
     result = false;
    }
   );
  }
  else {
   var resultSet = db.execute(sql, params);

   if (callback) {
    callback(resultSet, date);
   }
  }
 }
 catch (error) {
  result = false;
 }
 finally {
  return result;
 }
}

コールバック関数は、SQLの実行結果を画面に反映させたいようなときに指定します。例えば、保存した住所情報を一覧表示するような場合です。後処理が必要なければ、コールバック関数には何も指定しません。

保存した住所情報を閲覧する画面です。

Androidをもっている方、是非試してみてください!
Strayed Child

7月
23

flashcast:フリーで働くITエンジニア集団のブログ: iPhone OS 3.0のSafariでGPS機能を使ったWeb Applicationを作る!(sqlite保存編)の続きです。

前回は表示されている住所の吹き出しの中に、「save」リンクを設け、その住所をSQLiteに保存するようにしましたので、その住所を見るための履歴画面を作ります。

htmlの見た目は極めて単純なものにします。この時点ではかっこよさとかは気にしません。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=320px, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<title>iPhone GPS Sample</title>
</head>
<body>
<div id="header">
<div id="title">Histories</div>
<a href="../sqlite/">back</a>
</div>
<div id="main"></div>
</body>
</html>

データを検索して、1件以上あれば、画面上に表示します。

 function initialize() {
  try {
   db.transaction(
    function(transaction) {
     transaction.executeSql("SELECT dat FROM location ORDER BY id DESC", [],
      setLocations,
      function(error) {
       alert("initialize:" + error.message);
      }
     );
    },
    function(error) {
     alert("initialize:" + error.message);
    }
   );
  }
  catch (error) {
   alert("initialize:" + error.message);
  }
 }

 function setLocations(transaction, resultSet) {
  var html = "";

  for (i = 0; i < resultSet.rows.length; i++) {
   var address = tonosamart.evalJson(resultSet.rows.item(i).dat);

   if (address) {
    html += "<div><p>" + address.Placemark[0].address + "<\/p><\/div>";
   }
  }

  $("#main").html(html);
 }

あれ?うまくいきません。
よく見ると、JSONからオブジェクトに変換するところの正規表現でエラーになってます。

var address = tonosamart.evalJson(resultSet.rows.item(i).dat);

JSONの最後の部分に、ナゾのフィールドがあります。

\”__shared\”:undefined}”

これが正規表現に引っかかってました。何に使うんでしょう・・・
ナゾですが、値が入ってきた時のことも考慮して、SQLiteに保存する前に、

   if (address.__shared == undefined) {
    address.__shared = "";
   }

このような処理を入れることにしました。
やっと、うまくいきました。画面はこんな感じす。

次に、地図の画面から履歴画面に遷移できるようにします。
Google Mapsのカスタムマップコントロールを使います。
コントロール – Google Maps API – Google Code

履歴画面にリンクするだけのものなので、単純なものにします。

 function LocationControl() {
 }

 LocationControl.prototype = new GControl();

 LocationControl.prototype.initialize = function(map) {
  var container = document.createElement("div");
  var control = document.createElement("a");
  control.href = "../history/";
  this.setButtonStyle_(control);
  container.appendChild(control);
  control.appendChild(document.createTextNode("histories"));

  map.getContainer().appendChild(container);
  return container;
 };

 LocationControl.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_TOP_LEFT , new GSize(5, 5));
 };

 LocationControl.prototype.setButtonStyle_ = function(button) {
  button.style.color = "#000000";
  button.style.backgroundColor = "#FFFFFF";
  button.style.cursor = "pointer";
 };

画面はこんな感じです。

ここまでで、こんなのができました。もし良かったら、試してみてください!
iPhone GPS Sample

7月
23

flashcast:フリーで働くITエンジニア集団のブログ: iPhone OS 3.0のSafariでGPS機能を使ったWeb Applicationを作る!(iPhoneでテスト編)の続きです。

いままでのサンプルアプリは住所を表示するだけなので、もう一工夫して、その住所を保存できるようにしたいと思います。
保存先は、tonomemoと同じように組み込みデータベースのSQLiteにします。

まず、テーブル構造を考えます。

緯度と経度と・・・
ん。よく考えるとGoogle Maps APIの戻り値は、JSONオブジェクトなので、とのさまのflashcast:フリーで働くITエンジニア集団のブログ: ipod touch用のWeb Applicationを作成してみる(JSONについて)のアイデアが使えそうです。

JSONを、まんま1カラムにぶち込みます。

これは非常にいいアイデアです。
今までのサンプルでは、JSONオブジェクトの一部の情報しか使用していませんが、今後、機能拡張した場合にもテーブル設計を見直す必要はありません。また、Google Maps APIの仕様が変わっても、柔軟に対応できるはずです。

 $(document).ready(function() {
  var isDbConnect = true;

  try {
   db = openDatabase('iPhone GPS Sample', '0.9', 'iPhone GPS Sample');

   db.transaction(
    function(transaction) {
     transaction.executeSql('CREATE TABLE IF NOT EXISTS location (id INTEGER PRIMARY KEY, dat TEXT, locale TEXT)');
    },
    function(error){
     isDbConnect = false;
    }
   );
  }
  catch (error) {
   isDbConnect = false;
  }
  finally {
   $("body").attr("onload", initialize(isDbConnect));
  }
 });

画面の方は、住所が表示されている吹き出しの中に、「save」リンクを作ります。

 function showAddress(response, latlng, isDbConnect) {
  if (response != null && response.Status.code == 200) {
   map.clearOverlays();
   place = response.Placemark[0];
   marker = new GMarker(latlng);
   map.addOverlay(marker);
   marker.openInfoWindowHtml('<b>Address:<¥/b>' + place.address +
    ((isDbConnect) ? "<br ¥/><a href='javascript:saveLocation();'>save<¥/a>" : ""));
   address = response;
  }
  else {
   alert("Not found.");
  }
 }

ここでは、SQLiteが利用できないブラウザも考慮して、DB接続できない場合は「save」リンクを出さないようにしています。

「save」リンククリック時の処理は、以下のようになります。

 function saveLocation() {
  try {
   db.transaction(
    function(transaction) {
     transaction.executeSql('INSERT INTO location(dat, locale) VALUES(?, ?)', [tonosamart.obj2Json(address), (new Date()).toLocaleString()]);
    },
    function(error){
     alert("saveLocation:" + error.message);
    },
    function(){
     map.clearOverlays();
     alert("saveLocation complete!");
    }
   );
  }
  catch (error) {
   alert("saveLocation:" + error.message);
  }
 }

画面はこんな感じです。

これで、住所をメモる必要はなくなりました。
次は、保存した住所を見る仕組みを作りたいと思います!

1月
15

flashcast:フリーで働くITエンジニア集団のブログ: AIRアプリから作成したSQLiteのファイルがアンインストール時に削除されない!?の記事でAIRアプリから出力したSQLiteのファイルがAIRアプリのアンインストール時に削除されないということを書きましたが、それ以外にも、SQLiteのファイルに限らずAIRアプリから出力されたものは削除されません。

例えば、flashcast:フリーで働くITエンジニア集団のブログ: AIRアプリをログイン時に起動させる方法で書いたログイン時に自動起動させるためのロジックで出力されたスタートアップメニューのショートカット(Windowsの場合)も同様に削除されません。

同じ課題を抱えている人は結構いるようです。
フォーラム – Flex User Group

Flex User Groupの方々が、米Adobeサイトの[#SDK-16260] [External] Execute Function before Uninstalling AIR Application – Adobe Bug Systemに要望として投稿されていました。残念ながらインシデントとしてはクロージングされています。AIRのバグシステムにエスカレーションしているとは書かれていますが。

2009年1月15日時点では、AIRに特化した要望を投稿するフォームはありません。その代わり、Adobe – 製品への要望 / 不具合報告 フォーム
にAIRに関する要望をあげることはOKのようです。投稿しておきました。

同様の問題を抱えている方、改善を望まれている方、どんどん投稿しましょう!

「AIRアプリケーションのインストール、アンインストール時に任意のファイルを削除、任意の処理を実行できるようにして欲しい。あるいは、自作したスクリプトを実行できるようにして欲しい。」

■関連サイト
Adobe Bug System

※投稿用にアカウントが必要になりますが、事例等の閲覧はアカウントがなくてもできます。

12月
02

SQLiteに接続する際に、テーブルが存在していなかったらファイルをcreateするAIRアプリを作成する場合、以下のコードのようなコードを書いてしまうと、アンインストールしてもファイルは削除されません。

package
{
 import flash.data.SQLResult;
 import flash.data.SQLStatement;
 import flash.events.SQLEvent;
 import flash.filesystem.File;

 public class TestManager
 {
  private var _connection:ConnectionManager;
  private var arr:Object;

  public function TestManager()
  {
  }

  public function initTest():void {
   var file:File = File.applicationStorageDirectory.resolvePath("test.db");
   var str:String = "CREATE TABLE IF NOT EXISTS test (" +
    "id INTEGER PRIMARY KEY, " +
    "original VARCHAR(10));"

   _connection = new ConnectionManager();
   _connection.initConnection(file);
   _connection.execute(str, initTestHandler)
  }

  private function initTestHandler(event:SQLEvent):void {
   _connection.execute(
    "SELECT * FROM test " +
    "ORDER BY id desc;",
    selectHandler);
  }

  private function selectHandler(event:SQLEvent):void {
   var stmt:SQLStatement = event.currentTarget as SQLStatement;
   stmt.removeEventListener(SQLEvent.RESULT, arguments.callee);

   var result:SQLResult = stmt.getResult();

   if (result.data != null) {
    arr = result.data;
   }
  }

  public function load():Object {
   return arr;
  }
 }
}

この例では、FileクラスのapplicationStorageDirectoryプロパティを利用しています。VistaではC:\Users\ユーザ名\AppData\Roaming\アプリケーション名\Local Store、XPではC:\Documents and Settings\ユーザ名\Application Data\アプリケーション名\Local Storeに出力されます。なら、AIRアプリのカレントディレクトリに出力すればいいのでは?よーし、applicationDirectoryプロパティを試してみよう。

AIR-only applicationDirectory プロパティ
applicationDirectory:File  [読み取り-専用]

インストールされたアプリケーションファイルが格納されているフォルダです。

このオブジェクトの url プロパティは、app URL スキーム (file URL スキームではない) を使用します。したがって、url ストリングの指定は “app:” (file: ではない) で始めます。また、File.applicationDirectory ディレクトリを基準とする相対位置に (resolvePath() メソッドを使用して) File オブジェクトを作成すると、その File オブジェクトの url でも app URL スキームが使用されます。

メモ : app URL スキームを使用するパスを持つファイルまたはディレクトリに書き込むことはできません。また、app URL スキームを使用するパスを持つファイルやフォルダの削除または作成を行うこともできません。セキュリティ上の理由から、アプリケーションディレクトリの内容は変更しないでください。アプリケーション固有のデータを格納する必要がある場合は、アプリケーションの記憶領域ディレクトリ (File.applicationStorageDirectory) を使用することを検討してください。アプリケーションの記憶領域ディレクトリ内のコンテンツがアプリケーション特権機能 (AIR API) にアクセスできるようにする必要がある場合は、サンドボックスブリッジを使用してその機能を公開します。

File – ActionScript 3.0 言語およびコンポーネントリファレンスガイドより引用。

あれ?だめじゃん。ファイル出力できないじゃん。実はこれには抜け道があって、”app:”で始まるパスではなく、ローカルのフルパスにすればいいんです(c:\Dcouments and Settings\・・・)。nativePathプロパティを使います。

   var file:File = File.applicationDirectory.resolvePath("test.db");
   file = new File(file.nativePath);

   var str:String = "CREATE TABLE IF NOT EXISTS test (" +
    "id INTEGER PRIMARY KEY, " +
    "original VARCHAR(10));"

   _connection = new ConnectionManager();
   _connection.initConnection(file);
   _connection.execute(str, initHistoryHandler)

早速試してみよう!XPでは、起動は特に問題なし。アンインストールしてみる。あれ。だめだ。test.dbファイルが削除されない。ディレクトリも残ってる。う~ん。

AIR アプリケーションのアンインストール

ユーザは AIR アプリケーションを次の方法でアンインストールできます。

* Windows :「プログラムの追加と削除」パネルを使用してアプリケーションを削除します。
* Macintosh:インストール場所から app ファイルを削除します。

AIR アプリケーションを削除すると、アプリケーションディレクトリ内のすべてのファイルが削除されます。ただし、アプリケーションがアプリケーションディレクトリ以外のディレクトリに書き込みを行ったファイルは削除されません。AIR アプリケーションを削除すると、AIR アプリケーションがアプリケーションディレクトリ以外のディレクトリに行った変更は元に戻りません。

Adobe AIR * インストールとアップデートより引用。

ん!ちょっと待てよ。test.dbファイル自体をairにパッケージングしたらどうなるんだろう?アンインストールはうまくいくような気がするな。試してみよう!とりあえず、assetsに突っ込んで、、、

リリースビルドしてみよう。

パッケージングできた。インストールしてみよう。

インストールできた。実行してみよう!

実行できた!アンインストールしてみよう。おおお、test.dbもディレクトリーもきれいさっぱりなくなってる!!!んん?ちょっとまてよ。Vista。よくよくみるとSQLiteへの出力ができてないじゃん!?サンプルだと「set」ボタンを押すと、新たなレコードが作られるはずなんだけど、再読込(「load」ボタンクリック)しても、追加されていない。TkSQLiteでレコード追加して再実行すると、、、あれ?読み込めた。あー、読込だけならできるのね。

Problem

Working with File.applicationDirectory in Windows Vista fails silently and
stops code execution

Solution

Avoid to copy or write data in File.applicationDirectory; use other folder
to work with files.

Detailed description

If you have an application that works with files (copy or write) and they
are in the File.application folder, you can’t manipulate them in Windows
Vista and your code fails silenty. Also, all code after file manipulation,
doesn’t execute. Use another folder when working with files.

Adobe AIR cookbook beta – File.applicationDirectory issue in Windows Vistaより引用。

Vistaではカレントディレクトリにはファイル出力できない上に、アプリケーションが(静かに)停止してしまいます。Exceptionも発生しないんです。。。

ちなみに、flashcast:フリーで働くITエンジニア集団のブログ: ActionScript3.0でJSONを読み込む方法で掲載しているgoogle翻訳APIの翻訳結果JSONを読み込むswfで翻訳するとこんな感じになります。

問題

作業File.applicationDirectory Windows Vistaでのサイレントモードで失敗すると、コードが実行を停止

ソリューション

コピーまたはFile.applicationDirectoryのデータの書き込みを避ける;ファイルで動作するように、他のフォルダを使用します

詳細な説明

場合は、アプリケーションがファイルで動作(コピーまたは書き込み)があるが、これはFile.applicationフォルダ内には、 Windows Vistaで、それらを操作することはできませんsilentyあなたのコードは失敗します。また、すべてのコードファイルを操作した後、実行されません。別のフォルダにファイルと一緒に仕事を使用します。

XPのみ対象であれば.dbファイルをairにパッケージングするやりかたで、アンインストール後にゴミが残ることもないですが、Vistaはちょっと厄介ですね。初期設定等を読み込むような使い方であればパッケージングする意味はあります。インストーラでインストール/アンインストール時にカスタムスクリプトが組めれば一番良いのですけど。もうちょっと調べてみますっ!

※ 後でnativePathを使用しないで試したところ、XPではtest.dbはちゃんと出力されてました。なんでだろ??

  • Search:
  • flashcastとは?

    東京を中心に、現在フリーランスとして活動しているITエンジニア、および、かつてフリーランスとして活動していた起業家達が立ち上げたコミュニティーです。

    みんなで集まって面白いことをやろう!形に残そう!ということで、ブログをはじめました。

    技術情報や、フリーエンジニアに役立つ情報などを、ご紹介できたらと思っています。

    お問い合わせ:
    info@flashcast.jp
  • カレンダー

    2010年7月
    日曜日 月曜日 火曜日 水曜日 木曜日 金曜日 土曜日
    « 6月    
     123
    45678910
    11121314151617
    18192021222324
    25262728293031
  • メンバー紹介

    もじゃもじゃ
    flashcastのリーダー

    3年ほどフリーのITエンジニアとして活動。現在は、社員2名の株式会社を経営しています。

    一攫千金を夢見る野心家です。

    ライブキャスト

    yasu
    ダイバー

    自宅サーバーでホームページを作り始めました。

    少しずつ記事を増やしていきますので足を運んでください。

    よろしくお願いします。

    sa-sa-ki.jp

    のら
    たびびと

    ねこ好きに悪人はいなーいっ!!

    バイクや車も好きです。

    めぐ
    デザイナーのたまご

    音楽とデザインとお酒をこよなく愛する永遠のダイエッター。

    現在ペンタブレットでイラストを勉強中。

    Hiro
    コンサル

    PMやSEの案件を業務委託で請けることが多いですが、小規模案件も受託でやっています。

    得意な分野はマイクロソフト製品や関連技術によるシステム構築です。

    KEI
    取締役の風格

    最年少なのに、メンバーで1番の貫禄の持ち主!?

    C#や.netなどサーバ側の開発が得意。

    ろっきー
    美食家★パパ

    自分にとっての息抜きは、ドライブして温泉に入って、美味しいご飯を食べる事。

    ココロとカラダのリフレッシュを大切にし、日々の仕事に励む一児の父親です。

    郵便番号検索

    my-hobby

    とのさま
    げーむのおうさま

    大人なのに好きなことしかやらない駄目人間。

    Web系が得意、アクセスは苦手><

    tonosamart.com

    セクレタリアト
    ギャンブラー

    フリーランス時代は仲間の現場を探すことが多く、それをきっかけに会社を設立。

    現在はSI業に特化せず、他の業種にも興味を持ち始めています。

    メドレー株式会社

  • 広告