Friday, October 14, 2011

一個Eclipse匯入Android變紅XX的錯誤

案子在匯入後會變成紅色方型XX,
有非常多的理由。
通常我們都要在第1時間去看Console視窗裡寫些什麼錯誤訊息。


今天在匯入案子進筆電時,
發生了一個錯誤︰

[2011-10-15 14:25:00 - JeremyLiu] Dx
trouble processing "java/nio/CharBuffer.class":

Ill-advised or mistaken usage of a core class (java.* or javax.*)
when not building a core library.

This is often due to inadvertently including a core library file
in your application's project, when using an IDE (such as
Eclipse). If you are sure you're not intentionally defining a
core class, then this is the most likely explanation of what's
going on.

However, you might actually be trying to define a class in a core
namespace, the source of which you may have taken, for example,
from a non-Android virtual machine project. This will most
assuredly not work. At a minimum, it jeopardizes the
compatibility of your app with future versions of the platform.
It is also often of questionable legality.

If you really intend to build a core library -- which is only
appropriate as part of creating a full virtual machine
distribution, as opposed to compiling an application -- then use
the "--core-library" option to suppress this error message.

If you go ahead and use "--core-library" but are in fact
building an application, then be forewarned that your application
will still fail to build or run, at some point. Please be
prepared for angry customers who find, for example, that your
application ceases to function once they upgrade their operating
system. You will be to blame for this problem.

If you are legitimately using some code that happens to be in a
core package, then the easiest safe alternative you have is to
repackage that code. That is, move the classes in question into
your own package namespace. This means that they will never be in
conflict with core system classes. JarJar is a tool that may help
you in this endeavor. If you find that you cannot do this, then
that is an indication that the path you are on will ultimately
lead to pain, suffering, grief, and lamentation.

[2011-10-15 14:25:00 - JeremyLiu] Dx 1 error; aborting
[2011-10-15 14:25:00 - JeremyLiu] Conversion to Dalvik format failed with error 1

後來查了一下國外的論壇,才發現是專案在匯入Android的Jar檔時,Library Build錯位置了。

整個關鍵在於︰

 解決方式︰
Library標籤下應該會有一個android.jar(沒有放在Android2.2目錄下) ,
將其刪除,
並再將Android2.2Library匯入即可。





Wednesday, October 12, 2011

作品上新聞了

前一陣子接了一個外部合作案,
是三商美邦的「樂減碳小幫手」。

本來一開始是覺得產品規格不算多,
所以邊做邊重構。

但做到最後一天,
由於資料庫還不太熟,
加上伺服器端的程式又一直在修改,
一直熬夜到早上五點才完成這個案子。

不過看到新聞稿還蠻開心的。(笑)



相關連結︰

三商美邦人壽 綠色保險計劃探訪台灣人碳足跡

全台首創APP 保護地球少碳氣

三商美邦人壽啟動綠色保險計畫

三商美邦人壽推APP碳足跡記錄器

調查/台灣每人每日碳足跡19.6公斤 主管比職員多25%

減少碳排量 從日常生活做起

台灣人每天排碳19.6公斤 超過聯合國標準4倍

 

使用Proguard和Vpon時廣告出不來

今天遇見一個技術問題︰

即使在已匯入Vpon JAR檔的狀況下,
在做Proguard(程式碼模糊混淆)產出程式,
Vpon仍會顯示沒有正確的Adapter接收廣告
造成廣告無法正常顯示的問題。

出錯的LOG如下︰

Caught an exception in adapter:
java.lang.Exception: Invalid adapter
    at com.adwhirl.a.a.a(Unknown Source)
    at com.adwhirl.AdWhirlLayout.d(Unknown Source)
    at com.adwhirl.b.run(Unknown Source)

這個問題後來我發現︰
如果直接使用debug模式輸出程式時,
Vpon廣告是能顯示的。
原來是被Proguard混淆時,
打亂了廣告接收器(Adapter)。

解決方法︰
在Proguard腳本(proguard.cfg)中加入以下程式碼
-dontwarn com.vpon.**
-dontwarn javadoc.**
-dontwarn properties.**
-dontwarn com.adwhirl.**
-keep class com.vpon.** { *; }
-keep class javadoc.** { *; }
-keep class properties.** { *; }
-keep class com.adwhirl.** { *; }
 

上面這些是adOn.jar和adwhirl.jar裡所有的套件名稱,
在劇本裡下這些指令就能跳過混淆這2組jar檔,
讓廣告順利產出。

相關文章︰


Facebook.authroize()認證一片空白的問題

今天在做Facebook.authroize()時,
要驗証時一直出現全空白的畫面,
然後告訴我︰連結的(FB)應用程式出錯,
導致一直無法正常登入FB。

後來發現這是Facebook SSO(Single-Sign-On)單一登入機制的問題,
只要在程式碼中加入強制另外登入機制即可。

facebook.authorize(Activity, new String[] {"publish_stream" },Facebook.FORCE_DIALOG_AUTH,
        new Facebook.DialogListener() {});

這樣子Facebook就不會在你的應用程式被後跑SSO機制,
導制認證出錯了。

Tuesday, October 11, 2011

感謝大家對我第1隻程式︰統一發票愛我的支持

今天蠻感動的,
雖然這是技術論壇,
但我覺得還是可以把一點點心情寫在這裡。
因為布落格是我的。
XD

Android的硬體規格問題,
雖然在開發過程中我罵歸罵,
但是今天又收到使用者寄信來問我為什麼找不到我之前開發的
「統一發票愛我」?
(因為已經陸續收到7封信了。)
這隻程式半年累計1萬下載人次,100人4.5顆星以上好評果真不是蓋的

這隻程式因為版權是前公司所有,
所以我已經不方便更新和維護了。

但當收到大家對這隻程式的關心和詢問,
我想我當初絞盡腦汁的用心,
使用者真的感受到了。

Tuesday, September 27, 2011

Android開發者應有的認知

繼Android開發之氣死人之路I和開發氣死人之路II後,
在這裡跟許多後輩提及一個很重要的觀念。

許多開發者都喜歡拿Android跟iPhone比。
的確,在iPhone上開發APP,
因為手機規格就那麼一隻,
所以在程式開發上,
會遇到的問題不會如Android多。
甚至在畫面的佈局上,
即使用訂死(如︰絕對座標,譬如規定要將按鈕放在x=20,y=30)的方式,
使用滑鼠拖曳,輕鬆就能搞定版面佈局這件事。

但這件事在Android上可就大不相同了。
Android是多種規格、多種解析度、多種cpu運算、
多種記憶體結合起來的產物。
這都歸功於Android平臺的開放性。

Android光是在解析度上,
就分成手機型的
854*480/800*480/480*320/320*240
而平板就更不用説了
又是另一套規格。
詳細規格可以參照官方sdk的規格表。
(但有許多規格還沒有列進來)

像最近開發的一個遊戲︰
挑戰劉子千

在這款遊戲裡,
女主角的眼睛會眨、按了上方的水晶燈蠟蠋會變亮、桌子要在螢幕的正下方。
再回到我剛才提到Android多解析度的問題。
這時候你看一下原本的遊戲畫面,會變成什麼樣子
看出來了嗎?
原本規劃好的位置,
因為各家解析度不同,
通通亂掉了。
也就是説,
遊戲廠商如果要替每一隻不同規格的Android手機做出可以玩的畫面,
那麼他們要替這款遊戲調校非常多的遊戲畫面版本。

剛才我們提到的是解析度的問題,
再來,我們來提硬體問題。
這款挑戰劉子千有一個「比對玩家音準」的功能,
當中使用了Android的錄音功能。
而聲音取漾率和CPU運算效能有關。
也就是説,
如果是機王Samsung SII,
10秒鐘能取漾到30筆玩家的音頻,
那麼在cpu運算效能較慢的機種裡,
可能10秒只能取到15筆音頻。

這樣的硬體差距,
也讓我在攢寫判斷玩家音準這個功能上,
遇到了許多的頻頸。
因為越多取漾率,
在判斷玩家音準這件事,
就會越準。

以上這款遊戲是我自己的案子,
所以能在這邊跟大家解釋Android發生了什麼事。
如果還要提我在公司上班裡開發的案子,
那硬體問題的例子將會不枚盛舉。

有些iPhone開發者當初就體認了這一點詬病,
所以打死不碰Android開發。
但是對Android開發者而言,
為了要能夠開發出多款手機都能正常運行的程式碼,
我學到了要對記憶體的使用更注意,
也學到了如何讓程式開發起來更有「彈性」。
我想這些經驗,
應該是直接去碰iPhone的開發者,
不會遇到的事情。

結論︰

1.如果你現在的身份是使用者,
請珍惜這些開發Android的人,
如果有廣告也請多多幫忙點擊,
因為Android使用者願意付費的比例比iPhone使用者低很多,
有你們的點擊,
我們開發者真的才有進步的動力,
也才會有經費開發出新版本讓你們繼續使用。

2.如果你現在的身份是開發者,
那我想告訴你,
雖然Android初期的開發門檻很低,
但到後來你為了要能讓所有硬體可以順利跑你的程式,
你還是會花上一些錢買不同的手機。
(當然也可以借用社會力量)
而且你會遇到比我文章裡提到的還要更多的問題。

你,準備好當一名倍受挑戰的Android開發人員了嗎?



Monday, September 26, 2011

換個版面,換個心情(更換Eclipse版面)

你是底下這種人嗎?

1.Android開發的那麼久,
許許多多的問題也一天一天的累積了起來。
覺得很「阿雜(臺語)」?

2.長時間工作白底黑字的Eclipse環境讓你的眼睛吃不消?

這時候,
換個版面,
也許更能增加你的工作情趣哦!

在Eclipse Color Themes裡,
提供了許多種的版面主題,
只要你喜歡,
通通可以下載來使用。

首先,
點選你要的主題︰


然後,
將EPF檔下載下來︰


最後,
在Eclipse中匯入該檔
[File]-->[Import]-->[Gerneral]-->[Preferences]




這時候畫面主題就會是你匯入的樣子了。

嗯,
感覺又換了另一種開發心情。
(自我安慰中⋯)

附上一個我習慣用的主題Sunburst - by Viorel Craescu - Website


Wednesday, September 21, 2011

如何安裝Tomcat至Amazon EC2

上一篇教了如何安裝Java JDK6至Amazon EC2後,
這篇繼續説明如何安裝Tomcat至EC2裡。

一、下載Tomcat
1.先到Tomcat官網找最新的版本,目前是7.0版
2.找出目前的下載連結網址並複製至剪貼簿

3.在Terminal打上$wget + 滑鼠右鍵貼上剛剛找到的最新網址
所以這行指令可能就變成︰
wget http://ftp.asia.edu.tw/ftp/Apache/tomcat/tomcat-7/v7.0.21/bin/apache-tomcat-7.0.21.tar.gz


按下Enter,等著下載吧!


這是下載完成後的畫面




二、安裝Tomcat
下載完後,
你可以選擇要安裝的位置,
假設我要將這個tomcat安裝檔移至
/usr/local/tomcat/目錄下,
那麼我就下這行指令︰
$mkdir /usr/local/tomcat/
這樣子就建立了tomcat目錄了

然後,下搬移指令
$mv apache-tomcat-7.0.21.tar.gz /usr/local/tomcat/
將檔案移去那裡,


最後,我們在這個位置安裝tomcat
ubuntu@ip-10-172-155-204:/usr/local/tomcat$ tar xvzf apache-tomcat-7.0.21.tar.gz

這時候就會開始安裝Tomcat了。


記得要將EC2的secutiry group多設一個8080埠出來(目的是將8080排除於防火牆外),
到時候才能連到Tomcat哦!


三、啟動Tomcat
在
ubuntu@ip-10-172-155-204:/usr/local/tomcat/apache-tomcat-7.0.21/bin$
底下,
打上
./startup.sh
這時候Tomcat就啟動了!



ip位址會顯示在這裡︰


只要在瀏覽器上,
打上http://50.18.0.217:8080
Tomcat連上囉!

透過Terminal安裝JDK6至Amazon EC2

在上一篇説明了如何透過Terminal連線至Amazon website(AWS)後,
接下來便要説明如何開始安裝JDK了。

指令相當簡單︰
$sudo add-apt-repository "deb http://archive.canonical.com/ lucid partner"
$sudo apt-get update
$apt-get install sun-java6-jdk
 
然後,就可以下
$java -version
看看安裝是否成功了。
 
如上圖,這樣子就代表成功了。
 
下一篇︰如何安裝Tomcat至Amazon EC2

用Terminal連線到亞馬遜伺服器EC2

以目前的Android應用軟體來説,
已經越來越多的服務使用到後端伺服器來提供更良好的應用程式服務,
但是,小本經營的我們,
一方面又要節省成本,
這時候你會怎麼做呢?
亞馬遜website(AWS)是最近很火紅的網路伺服器,
很多企業為了省成本,
都會在將伺服器掛在上面,
加上AWS很高的資料移動性,
AWS簡直就是中小企業的最佳選擇。

這篇文章即將教你︰
如何連線到Amazon的伺服器,
如果你想要對AWS有一些基本的認識,
可以先參考阿正老師教你免費玩Amazon EC2雲端主機(下篇):主機實戰篇


文章開始︰

今天研究了一下要怎麼使用AWS,
我建立了一個Instances,系統選用Ubuntu 10.4。
然後,


這時候會出現一個新的視窗︰


只要在終端機terminal輸入這一行,
就能連到亞馬遜雲端了。

註︰可能輸入過程中,
會發生pem這個ssh私鑰還處於公開的訊息。
請照著這個視窗的第3點教學,
將私鑰權限改成private。

連線成功後,會出現這個畫面︰
恭喜你,連線成功啦!

下一篇︰如何安裝JDK6至EC2

Monday, September 19, 2011

Admob的另一個選擇︰Vpon

相信很多開發者都知道Admob是做什麼的,
這幾天我一直在研究另一家廣告公司︰Vpon。


Vpon如同Admob,
只不過他們的獲利方式,
不只Admob的點擊賺回饋金。
就算是顯示出廣告,
都還是有一定的分潤機制,
只是比點擊的分潤還低。

Vpon目前做地域性的廣告市場,
也就是説,如果你的客戶在台灣或大陸,
那麼Vpon可能是一個不錯的選擇,
如果你的市場在外國,
那你⋯還是乖乖用Admob吧⋯

Vpon除了做自家的廣告(Vpon_TW、Vpon_CN)外,
他們還引用了Google的Adwhirl工具,
此工具能將各家的廣告,
通通串連起來。
以後不管要播放Vpon、Admob、iAd⋯
等等之類的廣告,
你只要透過Adwhirl後端,
便可以對這些廣告做投放率的控管。

註︰
這個Adwhirl是Vpon的Adwhirl,
而不是Google原本的Adwhirl,
如果你是註冊Google的Adwhirl,
你就會跟我一樣卡在這裡一天,
收到廣告回傳的Log的Jason是空的狀況。

以下是Vpon提供Adwhirl對各大廣告商的關係圖

在這裡我直接以eclipse來説明如何將這些東西做串接。
1.你必須將各家的廣告jar檔放入你的eclipse中。
這樣看下來,如果你要用Admob、Vpon_TW、Vpon_CN、Adsense,
你至少要引入三家廣告商的jar檔
(Adsense因為可以直接在Admob後臺做設定,
所以不用再引入Adsense相關的jar檔了)

2.在你專案的src目錄裡,要加入相對應的Adapter去迎接第3方的廣告。
這些第3方廣告的Adapter在Vpon with Adwhirl sdk檔案裡都能找的到,
他們都已經寫好了︰
Vpon_tw和Vpon_cn的Adapter,他們寫在jar裡了,
但Admob的廣告,要另外將Adapter丟出來做串接(如下圖),
否則從Admob傳來的廣告,Vpon_Adwhirl會不知道如何回應。
註︰這個地方因為不知道要再銜接一個Adapter出來接Admob,
Log因而回傳Invalid Adapter, 
又讓我卡一天。

3.在Androidmenifest.xml裡,你要宣告︰

 
 
 
 
然後再宣告2個Activity進來︰

 

 
註︰AdActivity因為沒有宣告在AndroidMenifest.xml裡,
在這邊我卡了2天。

4.在你的畫面裡留出一個位置準備放廣告,
根據Vpon官方的説法,
這個廣告只適用在320x240(註2)/480x320/800x480/854x480
Android2.2以上版本

註︰
2011-09-19
1.官方説明Vpon能用在Android1.6、2.1、2.2,
但當我在用Proguard編譯時,
卻告訴我需要一個Android2.2的元件才能export成功。
Warning: com.vpon.adon.android.WebInAppWebChromeClient: can't find referenced class android.webkit.ConsoleMessage
這裡我又卡上半天。
也同時告訴我們編譯環境最好設在Android2.2以上。

2011-09-22
如上,雖然要2.2的環境才能export出apk檔,
但如果AndroidMenifest.xml裡的min SDK version設成7(2.1),
然後export,
Vpon廣告仍然是可以顯示出來的。

2.經測試320x240也能顯示Vpon廣告 

5.程式碼中加上︰
/**
  * 添加Vpon with Adwhirl廣告
  */
 private void callAdvertisement() {
  FrameLayout prepareAdvertisement_layout = (FrameLayout)findViewById(R.id.adLayout);//adLayout是你事先預留的廣告位置
  
  AdWhirlLayout adWhirlLayout = new AdWhirlLayout(this, "你跟Adwhirl要到的sdk key");
  
  AdWhirlManager.setConfigExpireTimeout(1000 * 60); 
  AdWhirlTargeting.setAge(23);
         AdWhirlTargeting.setGender(AdWhirlTargeting.Gender.MALE);
         AdWhirlTargeting.setKeywords("online games gaming");
         AdWhirlTargeting.setPostalCode("94123");
         AdWhirlTargeting.setTestMode(false); 
         
     adWhirlLayout.setAdWhirlInterface(new AdWhirlInterface(){

   @Override
   public void adWhirlGeneric() {
    Log.e(AdWhirlUtil.ADWHIRL, "In adWhirlGeneric()");
   } 
     });
      
     prepareAdvertisement_layout.addView(adWhirlLayout);   
    
 }

6.各家的廣告License key,像是Admob、Vpon_TW、Vpon_CN⋯
通通在Vpon的Adwhirl後臺裡去輸入和統一管理

Vpon分出了TW和CN兩個平臺,
如果你同一隻應用程式要做地域性的廣告
(涵蓋臺灣和大陸市場),
那麼在兩個平臺內,
你必須各申請1組Vpon key,
登錄在Vpon Adwhirl後臺裡。
(見上圖)

剩下的廣告如何顯示這件事,通通交給Vpon_Adwhirl吧!

相關文章︰使用Proguard和Vpon時廣告出不來

Wednesday, August 24, 2011

判別使用者的裝置版本

有時候在寫code的時候,
會遇到有些舊的類別在新版已不推薦使用,
因為新版推出了更好的功能。

產品經理(PM)在此時又要求2種功能都存留,
這時候下面這個判斷就變得很好用了。

if (android.os.Build.VERSION.SDK_INT >= 8){
   //在Android 2.2以上要用什麼類別
  }else{
   //在2.2以下又要怎麼處理同一個需求
  )
 

Thursday, August 18, 2011

Test in-app purchase測試你的內部應用程式購買機制

在使用測試in-app purchase時,
有以下幾點需注意︰
1.官方強調︰測試in-app purchase(以下簡稱iap)請勿使用模擬器!
2.如果你要測試的是預保留產品ID(reserved product IDs),那就不需要使用測試帳號。如︰android.test.purchased這組預設ID是讓你拿來測試購買後會發生哪些回傳值。
3.確認你裝置上的Android Market版本是否適合運行iap


真實測試你的iap物品
1.需要在軟體發佈網站裡記錄一組測試帳號

2.上傳的apk不需要被發佈,但是iap內的物品必須被發佈!
注意︰Android Market上面這個未發佈的apk的版本編號以及簽章(Signature)需以裝置上的版本一致
3.購買時帳目會真實被記進tester的Google checkout裡,
之後user跟開發者提出退費請求(可能寄e-mail或什麼的),
開發者就可以在Google Checkout Merchant account使用退費機制(refund)。

此時Google checkout會寄出該user已經退費的訊息給Android Market,
Android Market再寄出訊息給user手上的應用程式。
如果你的應用程式當初有寫收到退費的訊息時要做什麼處置,
那麼程式就會在這個時候開始動作。
譬如︰沒收紅藥水、魔法藥水。


4.請用釋出版本的signature,而非debug的signature
5.將一臺裝置的帳號設成測試帳號

  1. Open Settings on your device.打開裝置裡的設定
  2. Touch Privacy.點擊隱私設定
  3. Touch Factory data reset.點擊重設為原廠設定
  4. Touch Reset phone.點擊重設手機按鈕
Note: The only way to change the primary account on a device is to do a factory reset, making sure you log on with your primary account first.
將測試帳號設為主帳號的唯一方式,就是使用重設為原廠設定。
這樣做才能確保你是用主帳號登入Android Market

========實測結果=========
1.當你真的去買了iap內的東西,測試帳號裡的Google Checkout裡會有消費記錄
2.若馬上移除掉apk,這筆iap消費記錄也會馬上被退款(未免也太迅速了吧⋯)
3.若你要重新購買時,Android Market的iap視窗會回應你︰系統正在處理您的訂單,稍候幾分鐘即可取得您的商品。

4.後來,過了40分鐘,才能又購買這筆iap的產品

Saturday, August 13, 2011

in-app purchase匯入步驟

以下文章從Billing Android- implementing in-app billing取材整理


1.將Billing Sample src裡的com.android.vending.billing複製到你的專案裡
2.在AndroidManifest.xml裡的user-permission添加
com.android.vending.BILLING
註︰如果沒有宣告就請求billing機制時,將會收到
RESULT_DEVELOPER_ERRO反應

3. 建立BroadcastReceiver和Service(見步驟4)

BroadcastReceiver - 用來處理從Android Market傳來的Billing訊息 
Service - 綁剛才從billing sample src複製過來的IMarketBillingService.aidl

哦!對了。AndroidManifest.xml裡的BroadcastReceiver要設 intent filters 

      
        
        
        
      
    
4.攢寫Service
這個Service將要做哪些事?
(1)綁定IMarketBillingService.aidl
(2)向Android Market發佈Billing請求
  • CHECK_BILLING_SUPPORTED requests
  • REQUEST_PURCHASE requests
  • GET_PURCHASE_INFORMATION requests
  • CONFIRM_NOTIFICATIONS requests
  • RESTORE_TRANSACTIONS requests
(3)同步處理以上這些請求的回應


============================
(1)綁定IMarketBillingService.aidl詳細說明
  1. 建立一個Service並實作serviceConnection,然後將底下的Code放進OnCreate()
  2. try {
      boolean bindResult = mContext.bindService(
        new Intent("com.android.vending.billing.MarketBillingService.BIND"), this,
        Context.BIND_AUTO_CREATE);
      if (bindResult) {
        Log.i(TAG, "Service bind successful.");
      } else {
        Log.e(TAG, "Could not bind to the MarketBillingService.");
      }
    } catch (SecurityException e) {
      Log.e(TAG, "Security exception: " + e);
    }
     
  3.  建立callback(將以下程式碼貼進自創的Service裡)
  4. /**
      * The Android system calls this when we are connected to the MarketBillingService.
      */
      public void onServiceConnected(ComponentName name, IBinder service) {
        Log.i(TAG, "MarketBillingService connected.");
        mService = IMarketBillingService.Stub.asInterface(service);
      }
     
  5.  可以開始用mService去 sendBillingRequest()任何需求了!
 記得將developer發佈頁面裡的公開金鑰放進Security.java裡的base64EncodedPublicKey變數中

    Monday, August 8, 2011

    台灣購買Android軟體

    由於臺北市政府跟Google因軟體7天退費乙事正面交鋒中,
    但是還是有很多網友很支持開發者,
    想花錢去購買軟體。

    CJAY部落客有教我們怎麼將自已虛擬成外國用戶來購買Android Market的軟體,
    有興趣的看一看吧!

    步驟應該不會太難才是!

    2011/08/13註︰
    Market Enabler雖然能讓USER購買付費軟體,
    但
    1.裝置需要ROOT
    2.仍然不能支援IN-APP-PURCHASE

    實測後只有依照CJAY教的方式,
    才能實現在台灣使用in-app-purchase付費

    2011/08/25 11:00註︰
    現在又變成Market Enabler可以使用IN-APP-PURCHASE,
    而CJAY的則不行⋯

    2011/08/25 15:50註︰
    現在Market Enalber和CJ的vpn都能用IN-APP-PURCHASE了

    天啊,台北市政府,還我乾淨的測試空間!
    話又說回來,為什麼要在這個時間點要求我做IN-APP-PURCHASE
    (踢)

    Monday, August 1, 2011

    Android proguard issue - Can't read [proguard.ClassPathEntry@1a0c10f] (No such file or directory)

    If you encounter the problem that can't read something when you proguard your program
    as title write:
    java.io.IOException: Can't read [proguard.ClassPathEntry@1a0c10f] (No such file or directory)

    There will be two things you have to do:

    1.Download the newest ProGuard version from official website, unzip all its' file in sub-directory and replace to your-andoird-sdk\tools\proguard\

    It'll appear the exactly path where you got issue.

    2.Export project again,
    Now it'll show the error is:
    java.io.IOException: Can't read [/Users/simon/Android/?q?HSDK/FET_SMarket_SDK/FET_APP_Store_SDK_2.3.0.jar] (No such file or directory)

    3.When I back to that directory, ?q?HSDK isn't my directory's name, the name actually is "電信SDK".
    Now, I got the answer that I can't use Chinese in my path, Otherwise I will get this problem.

    原來讓我卡住一天,不能發佈並混淆程式的原因是︰
    我用了中文目錄成為路徑,
    ProGuard不能辨認中文!

    上一篇︰

    關於程式碼混淆proguard

    相關文章︰

    Sunday, July 31, 2011

    Android反組譯 - Reverse engineer

    以下文章轉載自此部落格

    先前聽說許多關於 Android 程式很容易被逆向工程,我也抱持這樣的觀點去戳 Android 開發者 XDD 直到今天開完會,前輩跟我說 Android 產生出的 dex file 很難閱讀,因此我就去找一下相關資料,找到一篇 2007/11/28 How to decompile .dex file on Android 文章,上頭也是敘述要去解讀 dex 有點不好讀,但隨後找到 2009/08/08 decompiling DEX into Java sourcecode 這篇文章,細看一下原來還有 dex2jar 的方式!這下可好了...
    所以,咱們來試試吧!我在 Ubuntu 10.04 的環境下測試
    準備工具:
    • dex2jar
      • A tool for converting Android's .dex format to Java's .class format
    • JD-GUI
      • JD-GUI is a standalone graphical utility that displays Java source codes of “.class” files. 
    • 一份編譯好的 apk 檔案
    接著就把 dex2jar 解壓縮出來,並執行
    $ cd dex2jar-0.0.7.7-SNAPSHOT
    $ sh dex2jar.sh MyWidget.apk
    然後就會看到一個對應的 jar 檔:MyWidget.apk.dex2jar.jar
    解壓縮 JD-GUI 去開啟 MyWidget.apk.dex2jar.jar 檔案,不囉唆,程式碼就可以看了!整個過程不用 30 秒吧!打快一點可能 3 秒喔 XD

    這...還真的叫我難以投入 Android 開發啊 *誤* 不過仔細一看,之前在 MyWidget 寫的程式,有些地方式用 R.layout.main 的地方,已經直接被換成數值了,但我想這樣也不會太難閱讀,畢竟整個 source code 都丟在你眼前了!更別提 dex2jar 仍然很活躍地進行維護及開發,真的開感謝一下對岸,第一次看到簡體中文有那種莫名的感動 XD 太多東西都嘛是英文先衝啦
    至於 dex2jar 的原理,可以參考這邊:介绍dex2jar的核心思想,有原理才會有相對應的解法喔!
    順便筆記一下 iPhone 的:
    arm-elf-objcopy -I binary -O elf32-littlearm iPhoneApp out.elf && arm-elf-objdump -marm9 -D out.elf
    但組語嘛,雖然學過,但我想我應該看不下去 XD
    最後,關於逆向工程的事情,如果程式碼非常冗長,那一樣不好啃啊!所以,玩玩就好。

    以上文章轉載自此部落格

    關於程式碼混淆proguard

    在了解程式碼混淆前(官方翻譯成模糊程式碼),
    建議可以先去觀看漁郎的教學。


    在了解程式碼混淆前,
    也許你會問我︰「為什麼我要學程式碼混淆?」
    很簡單,答案如下︰
    1.讓使用反編譯工具想看你程式碼的人,閱讀你的程式碼更困難
    2.優化你的程式,節省空間

    如果你的開發版本在Android2.3以前
    那麼Proguard的使用方式是”手動”混亂你的程式碼
    請在你的專案目錄底下,打上︰
    android update project -p E:\_Eclipse-3.5.2\workspace\Wallpaper -t 8
    或在那個專案目錄下鍵入android update project -p ./ -t android-8
    其中-t 8指的是即將編譯的Android版本編號
    8代表要編譯成Goole Map + Android2.2以上用的Application
    android-8 代表要編譯成Android2.2以上用的Application
    灰色字體取決於你是否在當下目錄,
    若在當下目錄使用proguard,那麼灰色字體就是打上「./」
    當完這行指令後,
    你的螢幕會變成以下︰
    意思是説,己經在這個專案底下加入build.xml檔和proguard.cfg檔了

    回到Eclipse環境中,對你的專案按下F5重整,
    你就會看到這2個檔案。

    在Eclipse專案下default.properties裡面
    應該要有這2行︰
    target=android-8(代表在2.2執行)
    proguard.config=proguard.cfg(指定混淆腳本是被放在這個專案的根目錄)

    如果build.xml出錯,
    回報我找不到help文檔,
    那麼把xml標籤的defualt="help"刪了吧。

    此時將application export出來,
    應該會多一個proguard目錄才對。
    如果做完apk後,
    按了F5這個目錄都沒出來,
    代表你並沒有混淆成功。

    註︰
    -t 8 不可能打成 -t 9,
    為什麼呢?
    Android在2.3後(版本代號9),
    正式將ProGuard納入了SDK,
    所以如果你是在2.3環境開發時,
    不用再打上面那行指令。
    現在這行指令只會在2.2(含)以下需要了。

    更詳細的內容,
    請參閱於Android2.3推出的Proguard文檔

    下一篇︰

    無法混淆的相關問題

    相關文章︰

    作品 - 管理學決策模式

    花了3個星期,
    這隻程式終於在蹺課數次,
    下班後熬夜數天,
    沒日沒夜的趕出來了。

    謝謝Camangi Janis當初在公司時,
    不藏私的教同仁管理學的決策模式。

    這讓我在人生的幾個重要決策中,
    因為這些管理學者的技術,
    我的每一個決定,
    都不再是隨便的做出來,
    而是經過條理分析。

    話不多說,
    請參考教學影片

    請至Android Market下載︰
    管理學決策模式

    或使用QRCode搜尋

    Saturday, July 30, 2011

    分享才是王道︰從你的APK發佈Facebook訊息!

    這個部落格的存在,
    主要是因為小鰻本人記憶力非常不好,
    我必須要有一個工具記住我以前學過的東西,
    哈,離題。
    今天要講如何讓你的APK
    擁有發佈Facebook訊息的功能。


    底下列了大概要做哪些事的步驟︰

    一、Facebook網站端
    1.在Facebook註冊開發者身份
    2.在Facebook開發者頁面新增應用程式
    3.輸入Key Hash


    二、Eclipse端
    1.下載Facebook源碼
    2.創建Facebook的基本SDK


    三、Code端
    1.將Facebook Library套入到自己的專案
    2.將manifest.xml加上Internet permission
    3.攢寫並使用Facebook Code




    ==========正文開始===============


    一、Facebook網站端


    1.在Facebook註冊開發者身份
    我們必須跟 Facebook註冊成為開發者的身份,
    之後才有權利跟Facebook伺服器做溝通。


    2.在Facebook開發者頁面新增應用程式
    要利用Facebook API跟Facebook伺服器溝通前,
    我們必須先創立專屬的應用程式,
    因為等等我們寫Code呼叫API時,
    會需要我們這裡申請到的應用程式ID。




    3.輸入Key Hash
    官方文件這麼說明︰
    We now need to export the signature for your app so that Facebook can use to ensure users are only communicating with your app on the Android. This is done by running the keytool.
    原來Key Hash是Facebook和我們的應用程式做溝通的橋樑。



    怎麼生成這個Key Hash呢?
    首先,我們必須搞懂Android Signature這個東西,
    由於篇幅問題,這裡跳過,
    你可以去參考Android Guide裡的資料。
    但我可以跟你說,
    一般我們的開發過程,
    會有2種Signature,
    一種是Debug用的Signature,
    另一種是真正要發佈程式至Android Market用的正式Signature。

    在這裡,我先示範抓出Debug Signature的方法,
    如果之後要用發佈的Signature,
    記得底下這步要做啊!


    (1)開啟Terminal終端機,輸入


    註︰如果你是用Windows,請在Mysgit產生的Git Bash視窗裡輸入上面這行指令

    要怎麼查你的debug.keystore在哪裡呢?
    在Eclipse中,點選[Windows]-->[Preferences]
    出現底下的視窗
    沒有Keytool指令?
    Keytools在C:\Program Files\Java\jdk1.6.0_26\bin\裡
    拜託環境變數設好再來。


    沒有openssl?
    我在Ubuntu和Mac下,因為是Linux環境,
    只要apt install openssl就好了,很快
    但Windows下openssl要怎麼匯入,
     請知道的人提供一下,謝謝
    註︰Android真的不適合在Windows環境開發,
    你會發現很多東西都要用到Linux


    總之,剛才那段keytool指令,
    在terminal裡應該要能生成出Key Hash。
    示意圖如下︰




    (2)將生成的值複製並貼入Facebook的Key Hash



    二、Eclipse端

    1.下載Facebook源碼
    請使用Git的方式,將Facebook源碼下載下來
    Windows用msygit
    指令為
    git clone http://github.com/facebook/facebook-android-sdk.git


    2.創建Facebook的基本SDK
    我們現在要將剛才git clone下來的源碼新增進Eclipse裡。

    在Eclipse工具列[File]-->[New]-->[Android Project]裡,
    從一個已存在的目錄去新建專案,
    而路徑請導到剛才clone下來的目錄底下的facebook目錄


     此外,你可以按照官方文件的教學,
    同樣方式導入另一個資料夾的Sample Application,
    去看看官方教你的API使用方式。
    當然,我接下來的教學裡也會說明。
    This library includes two sample applications to guide you in development.
    • simple: A bare-bones app that demonstrates authorization, making API calls, and invoking a dialog.
    • stream: This slightly beefier application lets you view your news feed.
    To install a sample application into Eclipse (3.5):
    • Create the sample application in your workspace:
    • Select File -> New -> Project, choose Android Project, and then click Next.
      1. Select "Create project from existing source".
      2. Choose either examples/simple or examples/stream. You should see the project properties populated.
      3. Click Finish to continue.
    • Build the project: from the Project menu, select "Build Project".    

    三、Code端
      1. 將Facebook Library套入到自己的專案
      (1)點擊[Project]-->[Propertites]


      底下那裡應該有打勾

      (2)看一下Package Explore,Facebook是不是順利匯進來了呢?




      2.將manifest.xml加上Internet permission


      耶!可以開始寫Code了


      3.攢寫並使用Facebook Code
      將FB專案成功的匯入我們的正在開發的專案夾後,
      剩下的就是如何攢寫Code去呼叫Facebook API了。
      Facebook的API有新(Graph API )舊(Legacy REST API:)兩種版本,
      官方已經不建議我們用舊的了。


      底下會以Graph API做示範。


      因為Facebok支援Single-Sign-On(SSO),
      所以如果使用者在用我們APK的當下有登入Facebok的話,
      基本上就不需要重複登入了。


      在攢寫程式碼的一開始,
      還記得我們教學一開始要求在Facebook Developer裡新增應用程式裡的應用程式ID嗎?
      這裡就要開始用到了。
      package com.greatap;
      
      import android.app.Activity;
      import android.content.Intent;
      import android.os.Bundle;
      import com.facebook.android.*;
      import com.facebook.android.Facebook.*;
      
      public class MyGreatActivity extends Activity {
      
          Facebook facebook = new Facebook("你的應用程式ID");
      
          @Override
          public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.main);
                 //跟Facebook伺服器要求User可以透過我們的程式跟Facebook做
                 //發文的動作。
              facebook.authorize(this, new String[] { "email", "publish_stream" },
                 //跟伺服器申請我們要能發文和用e-mail,
                 //這裡可以任我們新增修改
              new DialogListener() {
                   @Override
                    public void onComplete(Bundle values) {
               //當認證成功後我們當然是要發文,
               //發文有2種模式,
               //一種用post或get,
               //另一種用Dialog的模式,
               //Dialog模式會呼叫"即將會發什麼文章至Facebook"的視窗給使用者預覽
                try {     
                     Bundle parameters = new Bundle();
      
                    //使用者想說的話 
                     parameters.putString("message", "可以預寫使用者要發的黑體文字");
                     //連結所想呈現的文字
                     parameters.putString("name", "連結裡所以呈現的文字");
                     //連結網址
                     parameters.putString("link","https://market.android.com/details?id=com.hardworking.managingdecision_lite&feature=search_result");
                    //灰色註解
                     parameters.putString("description","在灰色註解區塊想寫些什麼?");
                  //使用Dialog的方式發文
                 facebook.dialog(Result.this, "feed", parameters, new DialogListener(){
      
             @Override
             public void onComplete(Bundle values) {
              // TODO Auto-generated method stub
              
             }
      
             @Override
             public void onFacebookError(FacebookError e) {
              // TODO Auto-generated method stub
              
             }
      
             @Override
             public void onError(DialogError e) {
              // TODO Auto-generated method stub
              
             }
      
             @Override
             public void onCancel() {
              // TODO Auto-generated method stub
              
             }
                      
                     });
                    
      }
      
                 @Override
                 public void onFacebookError(FacebookError error) {}
      
                 @Override
                 public void onError(DialogError e) {}
      
                 @Override
                 public void onCancel() {}
            }
      );
            
      
          @Override
          public void onActivityResult(int requestCode, int resultCode, Intent data) {
              super.onActivityResult(requestCode, resultCode, data);
      
              facebook.authorizeCallback(requestCode, resultCode, data);
          }
      }
       


      認證那段的程式碼facebook.authorize會讓使用者出現底下的畫面


      寫到這裡,這樣子你會了嗎?
      對了,更多的Facebook API指令,
      都可以在這裡查到哦!

      Thursday, July 21, 2011

      ListView滑動時背景變黑

      當我們將ListView背景設定成一個我們想要的圖案時,
      在上下滑動時,往往背景會變成黑色,
      顯然這不是我們想要的畫面。 

      解決的方法︰
      在Layout的ListView標籤裡加入
      android:cacheColorHint="#00000000" 
      的屬性。

      Wednesday, July 20, 2011

      Android in-app Purchase 應用程式內結帳(筆記暫停更新)

      2011-08
      本然想既然台灣目前不能上架付費版apk,
      那麼就來改走in-app purchase路線,
      結果⋯

      Before you get started with in-app billing, be sure to review the following requirements and limitations.
      在你開始使用內部app金流時,請確定已經看過以下的限制和需求
      • In-app billing can be implemented only in applications that you publish through Android Market.內部app金流只能透過Android Market實作並且發佈
      • You must have a Google Checkout Merchant account to use Android Market In-app Billing.你必須有一組Google Checkout帳號
      • If your device is running Android 3.0, in-app billing requires version 5.0.12 (or higher) of the MyApps application. If your device is running any other version of Android, in-app billing requires version 2.3.4 (or higher) of the Android Market application.如果你的裝置是運行Android 3.0的話,內部app金流需要MyApps這隻程式版本5.0.12(或更高)。如果你的裝置是運行其它版本,那麼需要Android Market版本在2.3.4(或更高)
      • An application can use in-app billing only if the device is running Android 1.6 (API level 4) or higher.能使用內部app金流機制的程式必須是在Android1.6(或更高)。
      • You can use in-app billing to sell only digital content. You cannot use in-app billing to sell physical goods, personal services, or anything that requires physical delivery.
      • Android Market does not provide any form of content delivery. You are responsible for delivering the digital content that you sell in your applications.
      • You cannot implement in-app billing on a device that never connects to the network. To complete in-app purchase requests, a device must be able to access the Android Market server over the network. 
      研究了一下手上幾臺測試機的Android Market版本號︰
      手機型號 系統版本 Android Market版本
      Motorola X720 2.1 2002306
      Nexus One 2.3.4 2.3.6
      Nexus S 2.3.4 2.3.6
      HTC Hero 2.1 2002306
      HTC Incredible 2.3.3 2.3.4
      HTC Legend 2.1 2002306

      有發現什麼事嗎?XD

      =====稍微做一下筆記(底下會持續更新)======
      1.必須在permission加入com.android.vending.BILLING
      如果沒加入,publish頁面會無法新增in app product

      2.需要申請測試帳號
      3. 應用程式不需要被發佈,但in app product一定要發佈才能測
      4. 發佈時請用Release版的signature
      5. 測試程式的版本號需與market這個測試apk版本一致
      6.一定要用實機測試billing,不能用模擬器
      7.實機的帳戶請設成測試帳戶
      設定方法︰
      1. Open Settings on your device.
      2. Touch Privacy.
      3. Touch Factory data reset.
      4. Touch Reset phone.
      5. After the phone resets, be sure to sign in with one of your test accounts during the device setup process.
      8.確認實機的Android Market版本編號是否在2.3.4以上;
      如果是平板Android 3.0以上請確認是否有MyApps這隻程式且版本在5.0.12以上。
      =========================
      In-app Billing Overview頁面重點︰
      1. In-app purchase使用asynchronous message loop
      2. 我們的應用程式不會和Android Market直接互動,而是透過發送請求的方式。


      一個典型的in-app purchase仰賴以下三大元件︰
      1. Service - (範例程式裡的BillingService),負責處理從程式裡發送出來到Android Market in-app billing Service的購買訊息、
      2. BroadcastReceiver - (範例程式裡的為BillingReceiver),負責接收從Android Market來的所有非同步(asynchronous)交易回應。
      3. Security - (範例程式裡的為Security),負責執行安全相關的工作任務。像是數位簽章驗證(signature verification)以及nonce generation(?)

      也許你還會併入另外兩個元件來處理in-app purchase︰
      1. Handler - (範例程式裡的為ResponseHandler),處理購買通買通知訊息、錯誤、或其它的狀態訊息
      2. observer - (範例程式裡的為PurchaseObserver),負責發送callback到我們的應用程式,因此我們能夠更新我們的程式內的購買資訊畫面。
      商品型態分為二種︰
      1. 經由使用者帳戶管理 - 若商品選擇該方式,那麼購買資訊等⋯,將會被儲存於Android Market後臺。這種性質的商品,若使用者換裝置,並重新安裝你的軟體,該購買都會保存。
      2. 不管理 - 不會將購買資訊儲存於Android Market後臺。舉例來說︰遊戲裡的魔法藥水。

      處理複雜的in-app pruchase交易流程
       上圖由上至下是整個應用程式內結帳的流程順序。
      一旦你使用到了該機制,
      整體的程式碼互動性就和這個架構開始息息相關。
      官方文件提到,即使你沒有呼叫REQUEST PURCHASE去呼叫出購買視窗,
      我們都一定要處理IN_APP_NOTIFY這個broadcast receiver(參閱In-app Billing Overview下方文章)。
      為什麼呢?
      1. 因為Android Market可能會傳來讓程式內部交易的記錄,我們必須要處理
      2. 使用者可能多機一帳號,我們要將該資訊連結至新裝置的程式裡

      Android Market也會藉由IN_APP_NOTIFY通知程式該in-app purchase已退費的事情。
      退費狀態會尾隨著PURCHASE_STATE_CHANGED這個BroadCast Receiver以JSON的方式傳進來︰purchaseState值回傳2(表示已退費)


      JASON資料被綁在PURCHASE_STATE_CHANGED裡傳進來

      詳細內文請看Android Document

      Thursday, June 30, 2011

      無法讀到指定解析度的目錄的問題

      今天在開發時遇到當我希望程式去依手機規格︰hdpi去跑drawable-hdpi的目錄時,
      程式卻不理我們而老是讀取drawable-mdpi目錄圖檔的問題。

      其實這個問題發生在這裡︰
      請參閱Android SDK文件<supports-screens>
      android:anyDensity
      Indicates whether the application includes resources to accommodate any screen density. Older applications (before API Level 4) are assumed unable to accomodate all densities and this is "false" by default. If the application has set either minSdkVersion or targetSdkVersion to "4" or higher, the default value for this is "true". Otherwise, it is "false". You can explicitly supply your abilities here. Based on the "standard" device screen density (medium dpi), the Android framework will scale down application assets by a factor of 0.75 (low dpi screens) or scale them up by a factor of 1.5 (high dpi screens), when you don't provide alternative resources for a specifc screen density. The screen density is expressed as dots-per-inch (dpi). Android在新開一個專案時, Manifest裡的minSdkVersion預設為2, 難怪我當時一直無法讓程式去跑drawable-hdpi解析度的drawable目錄