隨著OTA技術的持續成熟,一個新的市場對軟件開發者開放了。目前,機智的蜂窩電話用戶會購買一個來自Handango.com 的J2ME MIDP應用並在數秒內下載到他們的手機上。在剛剛過去的幾年裡,無線軟件產業從鈴聲跳躍到了成熟(羽毛豐滿)的游戲應用。
許多消費者更加認識到他們可以為他們的手機承受多少錢;他們經常聯想帶有無意義游戲的J2ME應用。然而,隨著用戶升級到新一代的手機,一種帶有實際使用價值的基於MIDP應用的新知識受到關注。在Handango的最佳J2ME軟件出售名單上都是基於應用的知識,如多語詞典,詞匯訓練,聖經,記事本,甚至有雞尾酒配方。名單上的一個字典程序在不到一年的時間裡已經有將近26,000次下載!考慮到數千的無線訂戶願意花費3美圓在一個鈴聲上,實際J2ME應用的市場潛力是巨大的。
不像游戲程序,基於知識的應用程序的價值在於數據。由於MIDP應用硬件利用的簡單性,如果數據文件被折衷的話,可以很容易就提出一個與之競爭的應用。盡管將數據放在後台服務器的客戶端-服務器模式可以闡釋這種關系,這樣的模式對大多數無線應用來講被證明是不切實際的。除非等到無線數據傳播費用降低,同時無線連接變得更加可靠和普遍,目前來說將數據文件嵌入MIDP JAR 是唯一的選擇。因此,保護數據文件不受版權侵犯變得勢在必行。
該問題的一個普遍解決辦法是加密數據文件。實際上,幾個JSRs正在籌備提供一套加密解密的標准API。但是,密碼系統即使對於桌面J2SE應用來說也是CPU密集的。而且,如果要等到新的手機都會支持這樣的API,至少還有很多年時間。此外,基於新API的代碼不向後兼容目前的手機。這導致了一個灰色時代,某個應用可以在一些手機上運行但在另外一些上不可以。一個可選擇的方法是使用第三方的支持J2ME的密碼庫。一個流行的開源工具是Bouncy Castle的輕量級密碼支持API。但是,注意:這個庫超過400KB。考慮到市場上大多數的Nokia Java手機有64KB JAR的大小限制,這個方法又是不可行的。
我提出一個簡單的解決該問題的方法。增加一行額外的代碼,忽略JAR的大小限制。它有兩個狀態。首先,整理並壓縮數據文件。然後,混淆壓縮文件讓它不能輕易被解壓縮。
整理數據文件:許多Windows編輯器用\n\r避開了新行。特別是在你從Excel導出數據的情況下。"\r"是多余的,既然"\n"是足夠來顯示新一行的。在換行前消除"\r"和不用的空白可以節省很多字節。
注意不是所有的文本編輯器都可以探測到"\r";UltraEdit是有效的編輯器之一。如果數據文件很大,把它拆成幾個小的文件以便快速的搜尋。但謹記小的文本文件不像大的壓縮得那麼高效。
• 壓縮數據文件:壓縮算法的選擇受到J2ME壓縮執行的可用性限制。盡管壓縮API已經與J2ME CDC(其目標是至少有2MB內存的設備)綁定,大部分目前的蜂窩電話設備僅僅支持CLDC和建立在其之上的MIDP標准。CLDC的最小內存要求是128KB。因此,開發者必須尋找第三方的庫或者寫自己的代碼。我發現了三個:
o 利用zlib壓縮算法的JCraft壓縮庫。它是開源的,文檔良好,並且有大量跟隨者;但是,庫有點大。
o Java4Ever有一個gzip (GNU zip)執行(3.27 KB)。它在LGPL的許可下,也是開源的。
o 我喜歡TinyLine的GZIPInputStream,因為它擴展了java.io.InputStream並且追隨了同樣的裝飾模式,作為另一個Java流類。它支持skip(), mark(),和其他基本I/O函數。工具的作者對問題的響應很迅速,並且庫的使用方法很直接:
InputStream in = getClass().getResourceAsStream(db);
in = new GZIPInputStream (in, 256);
有一個使用壓縮的弱點:解壓縮不可避免的增加了應用程序的內存覆蓋區。TinyLine沒有發布該庫需要的額外堆的大小,但是按我的測試,我必須增加我的堆大小35到40KB。一個MIDP應用最初運行在Palm Zire(2 MB)上,現在需要4MB的RAM(隨機存儲寄存器)來運行。這在輕微地增加所需地內存覆蓋區,對於大部分的應用程序和設備來說,不會讓人擔憂,但是還是推薦你們進行回朔測試。
壓縮只是防御的第一線;軟件盜賊仍可以輕易取得MIDP的JAR並利用正確的算法解壓縮數據文件。我門可以混淆一下已壓縮的數據文件。首先,我重命名數據文件為.res(或其他偽文件擴展名,如.xls或.mdb),如此一來壓縮算法便不能輕易被發覺。然後,用UltraEdit在HEX模式下打開壓縮數據文件(或任何HEX編輯器),在壓縮文件開頭插入(不是覆蓋)N字節數(如#!wx)。
最後,我改變了I/O代碼,在讀GZIPInputStream之前跳過N個字節:
InputStream in = getClass().getResourceAsStream(db);
in.skip(N);
in = new GZIPInputStream (in, 256);
我們跳過的N個字節變成了應用程序和數據文件之間的秘密代碼,修正過的壓縮數據文件是除了你的代碼之外的任何解壓縮軟件都無法識別的。當然了,一個意志堅定的電腦黑客可以反編譯類文件並通過混淆代碼費力的去尋找跳過的字節樹。但這種安全措施應該足夠阻止大部分的竊賊了。
移動設備能夠支持所有的J2SE API棧的日子也不遠了。但是那天到來之前,開發者們開發獨立的MIDP應用仍必須堅持不懈的與JAR的大小限制和數據文件安全性進行戰斗。本文的解決方法試圖改進這個問題。我承認它有點笨拙並費事;將來,我希望有一個工具可以利用來自動進行數據壓縮和混淆處理。