2011年9月3日 星期六

Android 開發筆記 - 使用 PhoneGap、jQuery Mobile 與台北市政府開放資料(Open Data)

我本身是 Native App Development 崇尚者(雖然沒啥開發經驗),理由很簡單,我樂於學習新的開發環境,想要 app 的效能最快,過去也曾探問過一些人的意見,有些大老闆就是力推 Native App ,理由就是要給使用者最好的使用經驗。然而,我的強者同事一直推薦 PhoneGap 的架構,他的理念是希望可以用一套固定且可延續性的學習經驗,應用在任何 mobile app 開發情境,這時就完全屬於 PhoneGap/HTML 的絕對領域!我也能體會在某個情境下並不太需要高效能的追求,這時候就可以好好善用 PhoneGap 所提供的便利性,只要是 Web Programmer 背景,會 HTML + JS + CSS 即可,剩下的只是安裝 app develpment 環境並看著 PhoneGap 使用手冊,也就行啦!


由於沒啥動力,就找了台北市政府九月才提供的公開資料(Open Data)當作範例,剛好可以透過 Javascript API 取得資料,再加上這類屬於查詢及資料呈列功能,不會有多嚴重的效率,所以,衝一發!


首先不厭其煩還是要裝一下 Android 開發環境,需要的可以逛一下 :Android & Eclipse 開發環境 - 第一次安裝筆記


接著從 Eclipse 建立一個 Project ,在此命名為 MyOpenData:


Application name: MyOpenData
Package name: tw.taipei.opendata
Create Activity: MyOpenDataActivity
Min SDK Version: 10 


接著從 PhoneGap 官網下載相關檔案,並依照使用手冊安裝:



  1. 建立 /libs、/assets/www 目錄,將 phonegap-1.0.0.js 複製到 /assets/www,將 phonegap-1.0.0.jar 複製到 /libs,將 xml 複製到 /res 目錄中。

  2. 更新 MyOpenDataActivity.java


    • package tw.taipei.opendata;

      import com.phonegap.*;
      //import android.app.Activity;

      import android.os.Bundle;

      public class MyOpenDataActivity extends DroidGap {
          /** Called when the activity is first created. */
          @Override
          public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              //setContentView(R.layout.main);
              super.loadUrl("file:///android_asset/www/index.html");

          }
      }



  3. 在 /libs 目錄按右鍵> Build Path > Configure Build Path > Libraries > Add JARs > 選 phonegap-1.0.0.jar 。

    • add_libs_phonegap



  4. 更新 AndroidManifes.xml:

    • <supports-screens
      android:largeScreens="true"
      android:normalScreens="true"
      android:smallScreens="true"
      android:resizeable="true"
      android:anyDensity="true"
      />
      <uses-permission android:name="android.permission.CAMERA" />
      <uses-permission android:name="android.permission.VIBRATE" />
      <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
      <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
      <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
      <uses-permission android:name="android.permission.READ_PHONE_STATE" />
      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.RECEIVE_SMS" />
      <uses-permission android:name="android.permission.RECORD_AUDIO" />
      <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
      <uses-permission android:name="android.permission.READ_CONTACTS" />
      <uses-permission android:name="android.permission.WRITE_CONTACTS" />
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
      <uses-permission android:name="android.permission.GET_ACCOUNTS" />

    • <activity android:name="com.phonegap.DroidGap" android:label="@string/app_name" android:configChanges="orientation|keyboardHidden">
      <intent-filter> </intent-filter> 
      </activity>

    • 如此圖:
      androidmanifest_phonegap



  5. 在 /assets/www 目錄中,新增想要的資料即可,如 index.html 


    • <!DOCTYPE HTML>
      <html>
      <head>
      <title>PhoneGap</title>
      <script type="text/javascript" charset="utf-8" src="phonegap-1.0.0.js"></script>
      </head>
      <body>
      <h1>changyy.pixnet.net</h1>
      </body>
      </html>



  6. 目錄結構

    • project_phonegap



  7. 成果:

    • phonegap result




接著來使用 jQuery Mobile ,透過這可以很便利地製作 Mobile App UI 及其事件操作,例如仿 iOS UITableViewController 等:



  1. 下載 Javascript 函式庫和 CSS,加入 /assets/www 裡 (此例沒用到,改用外部資源)



  2. 更改 HTML 檔案,此例為 index.html

    • <link href="http://code.jquery.com/mobile/latest/jquery.mobile.min.css" rel="stylesheet" type="text/css" />
      <script src="http://code.jquery.com/jquery-1.6.2.min.js"></script>
      <script src="http://code.jquery.com/mobile/latest/jquery.mobile.min.js"></script>



  3. 新增 header、table 和 footer 效果

    • <!DOCTYPE HTML>
      <html>
      <head>
      <meta name="viewport" content="width=device-width, initial-scale=1"> 
      <title>changyy.pixnet.net</title>
      <script type="text/javascript" charset="utf-8" src="phonegap-1.0.0.js"></script>
      <link href="http://code.jquery.com/mobile/latest/jquery.mobile.min.css" rel="stylesheet" type="text/css" />
      <script src="http://code.jquery.com/jquery-1.6.2.min.js"></script>
      <script src="http://code.jquery.com/mobile/latest/jquery.mobile.min.js"></script>
      </head>
      <body>
      <div data-role="page">
      <div data-role="header">
      <h1>Page Title</h1>
      </div><!-- /header -->
      <div data-role="content">
      <p>Page content goes here.</p>
      </div><!-- /content -->
      <ul data-role="listview" data-theme="g">
      <li data-role="list-divider">changyy.pixnet.net</li>
      <li><a href="ios.html">iOS</a></li>
      <li><a href="android.html">Android</a></li>
      </ul>
      <ul data-role="listview" data-theme="g">
      <li data-role="list-divider">MyOpenData</li>
      <li><a href="1.html">PhoneGap</a></li>
      <li><a href="2.html">jQuery Mobile</a></li>
      <li><a href="3.html">Data.Taipei</a></li>
      </ul>
      <div data-role="footer">
      <h4>Page Footer</h4>
      </div><!-- /footer -->
      </div><!-- /page -->
      </body>
      </html>



  4. 成果圖:

    • phonegap_result2




接著使用 台北市政府開放資料 所提供的 Open Data API:



  1. 目前 2011-09-03 共有 131 項資料可使用,在此挑選 "臺北市健保特約藥局"


  2. 成果:

    • 健保特約藥局_1
      健保特約藥局_2



  3. HTML 程式碼:

    • <!DOCTYPE HTML>
      <html>
      <head>
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <meta http-equiv="Content-Type" content="text/html; Charset=UTF-8" />
      <title>changyy.pixnet.net</title>
      <script type="text/javascript" charset="utf-8" src="phonegap-1.0.0.js"></script>
      <link href="http://code.jquery.com/mobile/latest/jquery.mobile.min.css" rel="stylesheet" type="text/css" />
      <script src="http://code.jquery.com/jquery-1.6.2.min.js"></script>
      <script src="http://code.jquery.com/mobile/latest/jquery.mobile.min.js"></script>
      <script language="Javascript">
      $(document).ready(function(){
      $.ajax({
      type: "POST",
      url: "http://taipeicityopendata.cloudapp.net/v1/TaipeiOGDI/G67AHAMEDICATION10007/",
      data: "format=json&callback=yourCallback",
      dataType: 'jsonp' ,
      });
      });
      var regionTitle = new Array();
      var regionData = new Array();
      var regionHash = [];
      function yourCallback(data)
      {
      //console.log(data);
      var container = $('#output');
      regionTitle = new Array();
      regionData = new Array();
      regionHash = [];
      for( var i=0 ,cnt=data['d'].length ; i<cnt ; ++i )
      {
      var getRegion = data['d'][i]['地址'].substring(0,data['d'][i]['地址'].indexOf('區',0)+1);
      if( regionHash[getRegion] == undefined )
      {
      regionHash[getRegion] = regionData.length;
      regionData.push(new Array());
      regionTitle[regionHash[getRegion]] = getRegion;
      }
      regionData[regionHash[getRegion]].push(data['d'][i]);
      }
      container.empty();
      for( var i=0 ,cnt=regionData.length ; i<cnt ; ++i )
      {
      //console.log( '@'+i+',Title:'+regionTitle[i]+',Cnt:'+regionData[i].length );
      container.append( '<li><a href="#'+regionTitle[i]+'">'+regionTitle[i]+'藥局資料<span>'+regionData[i].length+'</span></a></li>' );

      var subpage = '';
      for( var j=0,subCnt=regionData[i].length ; j<subCnt ; ++j )
      {
      //container.append( '<li><h3>'+regionData[i][j]['機構名稱']+'</h3><p>'+regionData[i][j]['地址']+'</p></li>' );
      subpage += '<li><h3>'+regionData[i][j]['機構名稱']+'</h3><p>'+regionData[i][j]['地址']+'</p></li>';
      }
      $('body').append(
      '<div data-role="page" data-url="'+regionTitle[i]+'">'+
      '<div data-role="header" data-position="fixed">'+
      '<h1>'+regionTitle[i]+'</h1>'+
      '</div>' +
      '<ul data-role="listview" data-theme="g">'+
      subpage +
      '</ul>' +
      '<div data-role="footer" data-position="fixed">' + 
      '<h4><a href="#home">Back</a></h4>' +
      '</div>' +
      '</div>'
      );
      }
      $('ul').listview('refresh');
      }
      </script>
      </head>
      <body>
      <div data-role="page" id="home">
      <div data-role="header" data-position="fixed">
      <h1>健保特約藥局</h1>
      </div><!-- /header -->
      <ul id="output" data-role="listview" data-theme="g"><center><h3>Loading...</h3></center></ul>
      </div><!-- /page -->
      </body>
      </html>




心得:


PhoneGap 的原理就是把開發者寫的 HTML + JS + CSS 用 Web 元件跑起來,在 Android 稱作 WebView ,在 iOS 稱作 UIWebView,因此,你也可以不需要 PhoneGap ,自行學樣包起來也沒問題。


使用 HTML 最大的優點是 UI 方面可以由 jQuery Mobile 包辦,這樣就算沒有像 iOS 漂亮的開發介面,也可以輕輕鬆鬆在 Android 或其他 mobile 平台達成。並且 UI 刻制對熟悉 CSS 的人來說,更是如魚得水啊。


最大缺點:


由於程式操作狀態從 Native app 移至 Web 元件上頭,當 native app 狀態改變時,不見得能對應到 Web 元件的狀態,例如偵測網路狀態或切換程式的動作等,有時希望每次一啟用程式,無論是從背景運作或是暫停模式中起來,都想要恢復至到一個畫面時,這時候 Web 元件就不見得會聽話。解法應該也是有的,只是解來解去會變成寫 native app 了。


2011年8月31日 星期三

Building Chromium Windows @ Windows 7 64Bit

為啥會需要編 Chromium 呢?一開始是工作需求,後來漸漸變成一種想把玩 Open Source 的心態去進行,即使下了班還是播出點時間研究研究。實在是 Web Browser 佔據的場景越來越多囉,如果手邊有一套自己可以亂改的 Browser 不亦樂乎?例如去年就有人拿 chromium 改成專門用於 facebook 的瀏覽器。雖然 Open Source 界不少人反微軟,但反過來看看 OS 市佔率,還是有太多太多人都在 Windows 上玩耍,如果想服務大眾或是做出合適於大眾把玩的東西,仍舊不能放棄 Windows 平台。


整個流程請參考:Build Instructions (Windows) 即可。在此使用 Windows 7 CHT 64Bit + VS2010 Express CHT 版,官方的簡介都是以 VS2008 Express 為基準或是 VS2008、VS2010 為主,所以參考官方的流程已足矣。另外一提的,連 Webkit 還都是以 VS2005 系列來說。


環境:


CPU:AMD 945 x4
RAM:DDR3-1333 2G x4
OS:Windows 7 CHT 64Bit


安裝軟體:


VISUAL C++ 2010 EXPRESS (VS2010ExpressCHT.iso)


Microsoft Visual Studio 2010 Service Pack 1 (VS2010SP1dvd1.iso)


DirectX SDK (June 2010 DirectX SDK)


Windows Driver Kit Version 7.1.0


cygwin


Chromium depot_tools


設定:



  1. 先取得程式碼,在此使用打包好的 http://chromium-browser-source.commondatastorage.googleapis.com/chromium_tarball.html ,此為 chromium.r96198.tgz 版本

  2. 接著打開 cgywin 並且把 chromium.r96198.tgz 擺在家目錄,用 tar -xvf chromium.r96198.tgz 解開,大概要 1x 分鐘,最後把 chromium 移到家目錄

  3. 切換至 ~/chromium/src 執行

    • $ set GYP_MSVS_VERSION=2010e

    • $ gclient sync --force

    • $ GYP_DEFINES='disable_nacl=1' gclient runhooks



  4. 打開 ~/chromium/src/chrome/chrome.sln 並將 chrome 設成起始專案

  5. 設定額外 include 與 lib 資訊

    • 開啟 chrome.sln 並點選 chrome project 後,[檢視] -> [屬性管理員] -> 點選 Microsoft.Cpp.Win32.user 後,去 [VC++ 目錄] 新增 [include 目錄] 和 [程式庫目錄]的資訊



  6. 可以點 chrome project 後,按 F7 編譯了。在我這台電腦大概一開始要跑快兩小時,修一修後再跑一小時,最後才編出 chrome.exe


microsoft.Cpp.Win32.user 


chrome_vc2010_express_lib chrome_vc2010_express_include


錯誤訊息及解決方式:


問題一:


官方說可以用 C:\trunk\src\chrome> devenv.exe /build Debug chrome.sln /project chrome.vcproj 這種 cmd line 編法,但一直找不到 devenv.exe 擺在哪


解法:


對 VS2008 Express 改用 vcbuild.exe ,位置在 C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcpackages\vcbuild.exe ,且使用時得改成 vcbuild.exe /upgrade ,這樣也會開始編譯。但我還是不知道 VC++ 2010 Express 該用哪支,最後還是用開始 chrome.sln 用介面編吧


問題二:


------ 已開始建置: 專案: ppapi_cpp_objects_nacl, 組態: Debug Win32 ------
2>  graphics_3d_dev.cc
2>  video_capture_client_dev.cc
2>  file_chooser_dev.cc
2>  scrollbar_dev.cc
2>..\..\..\..\ppapi\cpp\dev\video_capture_client_dev.cc(30): error C2440: '<function-style-cast>' : 無法由 'const PP_Resource' 轉換為 'pp::Buffer_Dev'
2>          沒有可以取得來源型別的建構函式,或建構函式多載解析模稜兩可
2>  video_decoder_dev.cc
2>..\..\..\..\ppapi\cpp\dev\graphics_3d_dev.cc(28): error C2511: 'pp::Graphics3D_Dev::Graphics3D_Dev(const pp::Instance &,const pp::Graphics3D_Dev &,const int32_t *)' : 在 'pp::Graphics3D_Dev' 找不到多載成員函式
2>          C:\cygwin\home\changyy\chromium\src\native_client\src\third_party\ppapi/cpp/dev/graphics_3d_dev.h(17) : 請參閱 'pp::Graphics3D_Dev' 的宣告
2>..\..\..\..\ppapi\cpp\dev\graphics_3d_dev.cc(58): error C2039: 'ResizeBuffers' : 不是 'pp::Graphics3D_Dev' 的成員
2>          C:\cygwin\home\changyy\chromium\src\native_client\src\third_party\ppapi/cpp/dev/graphics_3d_dev.h(17) : 請參閱 'pp::Graphics3D_Dev' 的宣告
2>..\..\..\..\ppapi\cpp\dev\graphics_3d_dev.cc(62): error C2039: 'ResizeBuffers' : 不是 'PPB_Graphics3D_Dev' 的成員
2>          C:\cygwin\home\changyy\chromium\src\native_client\src\third_party\ppapi/c/dev/ppb_graphics_3d_dev.h(37) : 請參閱 'PPB_Graphics3D_Dev' 的宣告
2>..\..\..\..\ppapi\cpp\dev\graphics_3d_dev.cc(63): error C3861: 'pp_resource': 找不到識別項
... 


解法:


把這東西給關掉 XD 在 cygwin 底下,切換到 ~/chromium/src 後,執行 $ GYP_DEFINES='disable_nacl=1' gclient runhooks 後,再去重編即可。


問題三:


108>C:\WinDDK\7600.16385.1\inc\mfc42\atldef.h(4) : fatal error C1083: Cannot open include file: '..\atl30\atldef.h': No such file or directory


解法:


安裝的 WDD 中,只有 atl71 目錄而沒有 atl30,所以就是直接把 atl71 複製一份並更名為 atl30。


問題四:


fatal error: 90>libGLESv2\libGLESv2.rc(10): fatal error RC1015: cannot open include file 'afxres.h'.


解法:


將 include 資訊多加個 WDD/path/inc/mfc42 吧


其他: 


編完沒過怎辦?繼續編 XD 重複幾次會發現沒過的會減少 :P


其他參考資料:



2011年8月30日 星期二

[Unix] .screenrc 與 .cshrc 筆記

在一台共用的工作站中,很不巧地使用共用帳號來操作時,這時候常常會碰到一些軟體設定的問題,最常見的就是自己用 tarball 偷裝的軟體 XD 這時候會想透過 source my.cshrc 來更新 PATH 環境變數,來使用這些 tools,然而使用 screen 時,卻變成每開一個視窗就得手動跑一次 source my.cshrc ,有點麻煩 :P 原先這種是應該寫在 ~/.cshrc 中就好,但因為是共用帳號,所以就設法避開了。


暫時還沒找到 .screenrc 的設定法?感覺應該有辦法每次新建一個視窗後,就跑某些指令吧?總之現在先偷改 ~/.cshrc 的部分,用的方式就是看工作目錄在哪,在指定工作目錄下就跑 source my.cshrc 來解決。至少簡單地可以 work 了 Orz


~/.screenrc:


caption always "%{bw}%M/%d %c %{wb} %-w%{c}%n %t%{w}%+w%{k} %=%{G}[%H] %l%"


~/.cshrc:


...
...

set checkdir='/data/MyWorkDir'
set currdir=`pwd`
set currcheck=`echo $currdir|cut -c1-15`
if( $currcheck == $checkdir ) then
        source /data/MyWorkDir/dev.cshrc
endif


/data/MyWorkDir/dev.cshrc:


setenv PATH     ${PATH}:/data/MyWorkDir/tarball/bin
setenv EDITOR   vim
if ( ! $?WINDOW ) then
        set prompt="%n@%m[%t] %~\n> "
else
        set prompt="%n@%m[%t]($WINDOW) %~\n> "
endif


如此一來,只要一開始切換到 /data/MyWorkDir 後,每次用 screen 開啟視窗時,都會跑 /data/MyWorkDir/dev.cshrc 來更新環境變數囉。先這樣撐著用吧 XD


2011年8月29日 星期一

資源


工作之後,越來越覺得資源是很重要的議題,例如最容易忽略的時間,一天也只有 24 小時,這讓我想起大一時的計概教授總是提醒大家 BBS 一天不要玩超過 30 分鐘!可惜做到的應該不多吧?我大學之後的學生生活,幾乎天天手洗洗衣服,時間加一加也挺可觀的,說真的不如其他同學一周花 20~30 元洗烘一次。


前陣子參加義工跟小我快十歲的資訊熱愛者聊天,聽到他很徬徨要學哪種程式語言,大概是擔心走錯路,這會讓我想到同事以前學習 Java 的路程,直接在書店看哪種程式語言最多,就挑它了來學,那時候就是 Java 了,事實證明,的確也沒挑錯,到現在 Java 還是很常出現在周邊的 open source 中。這些,也是青春的資源啊。


最近也常跟另一位同事去找主管 PK ,讓我體會計劃的推行也是需要資源的,這是更強烈的。假設方向是 spinoff 的話,那就需要設法去找錢來支援自己的想法,這時候絕對不是喊喊口號或是裝傻過日子,必須在組織可行的範圍內,提出洽當的計畫方向,可能是你想做得事中的十分之一,當計畫方向已經無法跟組織相輔相成時,那就該另尋一條路,向外找投資者,這些不是別人酸葡萄眼光中可以瞧見的。除此之外,對於職場上那些見人說人話的模式,有時真的不要太認真,認真就真的輸了,一不小心就將自己的資源揮霍掉了。


聊聊休閒活動,周末跑去一間漫畫店看書,這是我第二次在漫畫店看漫畫,這次的計價方式是以一本為單位(原價 x 10% - 2),這樣看一本 One Piece 就只要 8 元,看兩集就 16 元。上一次去清大水木則是四分鐘 1 元,一小時 15 元的算法,其實兩種都不差,或許在清大水木可以一直衝刺,但在時間的追趕下會不會損失了看漫畫的樂趣呢?我覺得到漫畫店看漫畫是一種資源善用的方式呢,有些東西真的只需曾經擁有就夠了。


我覺得資源這個議題,等到了成家立業還是會碰到,如同看著周邊已有家室的好友,偶時必須拒絕聚餐邀約,但我覺得這也不是什麼損失呢。資源,在每個人的心中都有一把尺,不需人云亦云,卻也該好好珍惜啊。可以挑些自己覺得有意義的事來闖闖,用旅行來增廣見聞也好,不見得是市面上火紅的東西,但不要只想著做大事,那樣的下場不是空轉二字可以道盡,有時順著命運緣分,小量也足矣。


2011年8月22日 星期一

我來減肥的

2011/08/20 06:57:00


終於,三天兩夜的行程撐了過去了。十分難得,連續三天都早起,今年的夏天有熱血到!


這個起源是去年與失散多年的高中學長相認,而後又閒聊台灣大型的資訊活動,總之就這樣加入了工作人員陣營。細想起來,碩班的大神就曾跟我說過,一生至少去參加一次吧!看來機會就差不多來了,再加上我本身不太可能因為想聽某堂而跑去台北,那用工作人員的身分,應該動力會多一點吧?!


經過三天的相處,我發現台灣其實有許多能力不錯或是默默耕耘的資訊能力者,有的高中就寫出 apt-get 這種相似功能的套件,有的則是不小心踏入資訊圈,正徬徨著未來的生活規畫,這些都足以令人振奮的!過去我在大學資訊系中,看到大部分的都比較顧成績而已,僅有少數人把資訊能力練得很好,如今在會場瞧見許多資訊強者,有單純愛玩某款遊戲,因此架論壇管理機器踏上了資訊這條路,無論哪種切入點,至少學了許多學校沒教的事,我覺得這才是大學該學會的技能啊!


Open source 是一種熱於分享精神,隨著生活的改變,或許不再有那空閒的時間寫 code 或置身於活動中,但我想,還是存在合適自己的付出模式,找到他!並好好地繼續熱血下去吧!