2010年3月8日 星期一

【分享】- 如何整合 Eclipse、Ant、Android SDK、Proguard、Zipalign,以輸出有程式保護且可上載與發佈到 Android Market 的 APK 檔?

註:如您使用 Android SDK 2.2,請在看完此篇文章後再續看另一篇 (PART2)的說明

要將 APK 上載與發佈到 Android Market,除了 Android Market 的規定,需要開發者在 APK 上加上開發者本身的電子憑證簽章,以示對程式品質的負責外,還需要使用 Google Android SDK 1.6 版以後才有的工具 zipalign 來最佳化 APK 後才能上載 Google Android Market。

問題是如何在 Eclipse 上更便利的一次呵成編譯與輸出可上載符合 Android Market 規範的 APK 檔?

再者,如何將 Proguard (亂碼器) 也整合到 Eclipse 中,以便利一次呵成編譯與輸出可上載符合 Android Market 規範且俱有初步保護力的 APK 檔?

答案是使用 Ant (天阿‧‧以前沒用過)。

漁郎在摸索了一段時日後,終於試驗出整合 Eclipse、Android SDK、Proguard、Ant 的方法,雖然不是非常理想,但已足夠讓漁郎這種懶人可輕鬆的套用到所有的專案上使用,且只要設定一次,文中如有謬誤或夥伴們有更佳的解法,拜託拜託,請指正一下漁郎‧‧





[實作環境]
1. Windows XP SP3
2. Eclipse 3.4.1 (GANYMEDE)
3. Android SDK 1.5 (線上更新後已下載並安裝了 SDK 1.5 1.6 2.0 2.1)
4. Proguard 4.4
5. Ant (內含在 Eclipse 中)
6. 專案名稱 : GDPW

在此僅針對 Eclipse、Android SDK、Proguard、Ant 的整合設定,其它諸如 J2SDK、Eclipse、Android SDK、Proguard 的下載安裝請先膜拜 Google 大神求得解答。

[實作步驟]

Step 1. 使用 JDK 的工具 keytool (keytool 在 J2SDK 安裝目錄的 bin 中) 產生屬於自己且效期為 100 年 (36500 天) 的金鑰庫,100 年夠用了吧!?

keytool -genkey -v -keystore D:\Android\keystores\android.keystore -alias android.keystore -keyalg RSA -validity 36500


Step 2. 使用 Eclipse 與 Ant 自動產生並俱程式初步保護力,且合法可上載 Android Market 的 APK 檔:

1. Ant 之 build.xml 製作 (1.5 版後的作法):
(1) 開啟 Command 視窗,並 CD 到 D:\Android\AndroidSDK\tools 目錄中。

(2) 下達更新專案命令:例如:D:\Android\AndroidSDK\tools\android update project --path D:\Android\Project\GDPW,也就是說命令為 android update project --path 專案目錄名稱。(PS: 1.5 版改成用 android update project 產生 build.xml 囉,還會自動在專案根目錄下增加一個叫 local.properties 的檔。當使用 Ant 時,它會自動匯入 <$SDK>/platforms/android-1.5/templates/android_rules.xml,也可以把 android_rules.xml 的內容 copy 到 build.xml 裡面再修改)。

(3) 開啟 Eclipse:以滑鼠右鍵點選該專案根目錄下的 build.xml 上面 (如沒看到就 Refresh 一下該專案),執行 Run As ...=> Ant Build... ==> 按下 Run 即可。(此時其 buildfile 參數已內定為 ${workspace_loc:/GDPW/build.xml} 也就是該專案下的 build.xml 檔)

(4) 注意:要在 Eclipse 中執行 Ant 前,請再確定你是否有設定 JAVA_HOME 這個環境變數,和將 %JAVA_HOME%\bin 加入到 PATH 環境變數中。PS:你可以透過 Windows 上的 控制台→系統→進階→環境變數 來修改這些環境變數。

(5) 那個紅標記可以在開啟 build.xml 後,在內容空白的地方,按滑鼠右鍵,點選 Preferencs,然後點選 Editor-->Problems 標籤頁,勾選 Ignore all buildfile problems,然後按 OK 即可消除。
   
SDK 1.6 後,只要使用 Ant,會自動執行 Zipzlign,但 SDK 1.5 之前的需自行加入,以下是建立可合法發佈到 Android Market 的 APK 之範例:

[0] 將 proguard.jar 複製到 ${android-tools}/lib 下。也就是 D:\Android\AndroidSDK\tools\lib 下

D:\Android\AndroidSDK\platforms\android-1.5\templates\android_rules.xml 中,修改以下內容 (新版 Android 1.5 Revision 6 已改為引入 D:\Android\AndroidSDK\platforms\android-1.5\ant\ant_rules_r2.xml , 20100521)
   
[1] 將 編碼 ascii 改為 utf-8 (如程式是用 UTF-8 的話),將 debug="ture" 改為 debug="false",並加入 optimize="true" 參數:
       
<!-- 如果編譯後的執行檔有問題, 試著將 optimize 改為 false 看看 -->
<target name="compile" depends="resource-src, aidl">
    <javac encoding="utf-8" target="1.5" debug="false" extdirs=""
        destdir="${out-classes}"
        optimize="true"
        bootclasspathref="android.target.classpath">
        <src path="${source-folder}" />
        <src path="${gen-folder}" />
        <classpath>
            <fileset dir="${external-libs-folder}" includes="*.jar"/>
            <pathelement path="${main-out-classes}"/>
        </classpath>
    </javac>
</target>
   
[2] 將 dex 的 depends 由 compile 改為 proguard:

(注意:如改為 proguard 後,編譯出來的 apk 一直無法執行,除了檢視以下的 proguard 參數外亦可保留原來的 compile 設定方式,不使用 proguard,一般來說就不會有一些怪怪的執行期例外錯誤產生)

<target name="dex" depends="proguard">
    ……. 略 …….
    <apply executable="${dx}" failonerror="true" parallel="true">
    …….. 略 ………
    </apply>
</target>
   
並最尾端加入以下內容:


(注意:紅色的部份,也就是 -keep 參數,得視個別專案的需要而增加項目,例如:在 AndroidManifest.xml 中出現的類別,以及在 layout/*.xml 中出現的自定 Widgets,不然,Andoird 系統可能會找不到你的類別,經測試 proguard 有時會將編譯後的類別名稱簡化 ,例如 com.e68club.android.gdpw 會變成 com.e68club.android.a,以致 Android 找不到AndroidManifest.xml 配置的類別名稱,而出現執行期例外錯誤綠色部份是個別專案的範例參數)
       
<!-- Add a Target "proguard" -->
<target name="proguard" depends="compile">
    <taskdef resource="proguard/ant/task.properties"
            classpath="${android-tools}/lib/proguard.jar" />
    <proguard>
        -injars ${out-folder}/classes
        -outjars ${out-folder}/classes/obfuscate.jar
        -libraryjars ${android-jar}


        <!-- 在使用 Proguard 4.5.1 時, -->
        <!-- 以下這些 android.* 沒 keep 也可運作, 怪怪...-->
        -keep public class * extends android.app.Activity
        -keep public class * extends android.app.Service
        -keep public class * extends android.content.BroadcastReceiver
        -keep public class * extends android.content.ContentProvider
        -keep public class * extends android.view.View

        <!-- 經測試, 將 src 下的 class name 全列進去就沒問題了 -->
        <!-- 但是, 是使用 Proguard 4.5.1 , 20100918 修正 -->
        -keep public class com.e68club.android.Gdpw
        -keep public class com.e68club.android.GoGo

        -dontwarn
        -dontpreverify
        -optimizationpasses 7
        -dontusemixedcaseclassnames
        -dontskipnonpubliclibraryclasses
    </proguard>
    <unzip src="${out-folder}/classes/obfuscate.jar" dest="${out-classes-location}"/>
    <delete file="${out-folder}/classes/obfuscate.jar"/>
    <echo>Obfuscated classes are put to "${out-classes-location}".</echo>
</target>
       
<!-- Add a Target "jarsigner" -->
<target name="jarsigner" depends="release">
    <echo>Jarsignning to ${out-folder}/${ant.project.name}-signed.apk ...</echo>
    <exec executable="jarsigner${exe}" failonerror="true">
        <arg value="-verbose" />
        <arg value="-keystore" />
        <arg path="D:/Android/keystores/android.keystore" />
        <arg value="-storepass" />
        <arg value="輸入你的 keystore 密碼" />
        <arg value="-signedjar" />
        <arg path="${out-folder}/${ant.project.name}-signed.apk" />
        <arg path="${out-folder}/${ant.project.name}-unsigned.apk" />
        <arg value="android.keystore" />
    </exec>
</target>

<!-- Add a Target "zipalign" -->
<target name="zipalign" depends="jarsigner">
    <echo>Zipalignning to ${out-folder}/${ant.project.name}-zipalign.apk ...</echo>
    <exec executable="${android-tools}/zipalign${exe}" failonerror="true">
        <arg value="-f" />
        <arg value="4" />
        <arg path="${out-folder}/${ant.project.name}-signed.apk" />
        <arg path="${out-folder}/${ant.project.name}-zipalign.apk" />
    </exec>
</target>
   
並且將個別專案下的 build.xml 內將
<project name="gdpw" default="debug">
改為
<project name="gdpw" default="zipalign">

以滑鼠右鍵點選該專案根目錄下的 build.xml 上面,執行 Run As ...=> Ant Build... ==> 按下 Run 後,在 GDPW/bin/ 下產生的 gdpw-zipalign.apk 即是已亂碼化且已簽章並優化後可上載 Android Market 的 APK 檔。

2 則留言:

  1. 版主 您好 :
    依照您的步驟用到最後一步時
    在 build.xml 內將
    project name="gdpw" default="debug"
    改為
    project name="gdpw" default="zipalign"

    結果在執行 Run As ...=> Ant Build...後會出現

    BUILD FAILED
    Target "zipalign" does not exist in the project "TEST".

    請版主幫我看一下是什麼問題
    非常感謝

    回覆刪除
  2. 試試以下的說法:
    (1) project name="您的專案名稱TEST" default="zipalign"
    (2) target name="zipalign" 那段有沒複製到您的 build.xml ?
    (3) 試試 PART-2 的說明
    (4) 再不行, 看一下 PART-3 吧 ^__^

    回覆刪除