[翻訳] android best practice

  • 595
    いいね
  • 0
    コメント

githubで★を集めてるandroid best practiceが勉強になるなぁと感心しておりまして、
思い切って翻訳していいかどうか問い合わせてみると快諾いただけたので翻訳してみました。
(Eclipse + ADTの話もでてますがそのまま訳してます。)

原文 : https://github.com/futurice/android-best-practices

(Qiitaに投稿するついでに本家のリポジトリにもプルリクしてくれって言われてるので少し待てばそちらでも見れると思います。)

この場を借りて、@askaさん、添削ありがとうございましたm_ _m 大変助かりました。

Summary

  • Gradleで推奨されるプロジェクト構成で開発しよう
  • パスワードや注意を要するデータはgradle.propertiesに書こう
  • 自分でHTTP Clientは作らず、VolleyやOkHttpを使おう
  • JSONをパースするならJacksonを使おう
  • メソッド数に65kの制限があるので、Guavaは避けて、かつライブラリは最小限に抑えよう
  • UIの描画はFragmentを使おう
  • ActivityはFragmentをただ管理するために使おう
  • Layout xmlをうまく整理しよう
  • Layout xmlの属性が重複するのを避けるためStyleを使おう
  • 大きなStyleを定義するよりも複数のStyleを定義しよう
  • colors.xmlは短くDRY(「Don't Repeat Yourself」意味が重複しないよう)にして、パレットで定義しよう
  • dimens.xmlもDRYにして、一般の定数を定義しよう
  • ViewGroupのネストは深くせずに浅くしよう
  • WebViewはメモリリークするため、クライアント側での処理は避けよう
  • ユニットテストにはRobolectricを、結合テストにはRobotiumを使おう
  • emulatorはGenymotionで決まり
  • 必ずProGuardもしくはDexGuardを使おう

Android SDK

Android SDKはホームディレクトリか他のアプリから独立した場所に置こう。いくつかのIDEはSDKを含んでいて、インストール時にSDKをIDEと同じディレクトリに置く事がある。このままではIDEをアップグレードや再インストールする場合、またIDEを変更する場合に面倒になる。
また、IDEがrootでないアカウントで動いている場合に、sudoが必要な他のシステムレベルのディレクトリにSDKを置く事も避けよう。

Build system

デフォルトオプションにGradleを使おう。Antは制限が多く、コストが大きい。しかし、Gradleなら下記のことがシンプルに可能だ。

  • あなたのアプリの異なるFlavorやVariantをビルドできる
  • スクリプトのようにタスクを作る事ができる
  • 依存関係を管理しつつダウンロードできる
  • keystoreをカスタマイズできる
  • その他諸々

そして、Googleは、AndroidのGradleプラグインを標準のビルドシステムとして盛んに開発している。

プロジェクト構成

プロジェクト構成については、これまでのAnt & Eclipse ADTのプロジェクト構成と 新しいGradle & Android Studioのプロジェク構成の二つが有名であるが、後者の新しいプロジェクト構成を選ぶべきだ。もし前者の古いプロジェクト構成をつかっているなら、それは遺産だと考えて、新しいプロジェクト構成に変える事を考えた方がいい。

old-structure
├─ assets
├─ libs
├─ res
├─ src
│  └─ com/futurice/project
├─ AndroidManifest.xml
├─ build.gradle
├─ project.properties
└─ proguard-rules.pro
new-structure
├─ library-foobar
├─ app
│  ├─ libs
│  ├─ src
│  │  ├─ androidTest
│  │  │  └─ java
│  │  │     └─ com/futurice/project
│  │  └─ main
│  │     ├─ java
│  │     │  └─ com/futurice/project
│  │     ├─ res
│  │     └─ AndroidManifest.xml
│  ├─ build.gradle
│  └─ proguard-rules.pro
├─ build.gradle
└─ settings.gradle

一番の違いは新しいプロジェクト構成では'Source sets'(main, androidTest)が明確に分けられている事だ。これはGradleのコンセプトでもある。
これによって例えばpaidfreeというSource setをsrcの中に追加すると、'paid'と'free'というFlavorができる。

さらにappがtop-levelにあると、アプリで参照されるlibrary-foobarなどの他のライブラリプロジェクトを区別するのに役立つ。setting.gradleが各ライブラリへの参照をもち、app/build.gradleから参照する事ができる。

Gradleの設定

一般的な構成

Google's guide on Gradle for Androidを参照の事。

小さなタスク

shell, Python, Perlなどのスクリプトの代わりに、Gradleの中にタスクをつくることができる。詳細はGradle's documentationを参照の事。

パスワード

リリースビルドのためにbuild.gradleの中でsigningConfigsを定義しなければならないときがある。

下記はダメなケース。これではバージョン管理システムで管理されてしまう。

signingConfigs {
    release {
        storeFile file("myapp.keystore")
        storePassword "password123"
        keyAlias "thekey"
        keyPassword "password789"
    }
}

その代わりに、gradle.propertiesに下記のように書いて、このファイルをバージョン管理の管理外としよう。

KEYSTORE_PASSWORD=password123
KEY_PASSWORD=password789

このファイルはgradleによって自動でimportされるので、このときのbuild.gradleは下記のように書くとよい。

signingConfigs {
    release {
        try {
            storeFile file("myapp.keystore")
            storePassword KEYSTORE_PASSWORD
            keyAlias "thekey"
            keyPassword KEY_PASSWORD
        }
        catch (ex) {
            throw new InvalidUserDataException("You should define KEYSTORE_PASSWORD and KEY_PASSWORD in gradle.properties.")
        }
    }
}
jarファイルを直接importするよりMavenを使う方が良い

jarファイルをプロジェクトに直接includeしている場合、version2.1.1のようにversionが固定されてしまう。さらに、jarファイルをダウンロードして、手動でアップデートするはめになり効率が悪い。Mavenならこれを解決できるし、Android StudioもMevenの使用をすすめている。2.1.+というようにversionの範囲を指定することもでき、指定した範囲の中での最新にアップデートしてくれる。
たとえば下記のように書く。

dependencies {
    compile 'com.netflix.rxjava:rxjava-core:0.19.+'
    compile 'com.netflix.rxjava:rxjava-android:0.19.+'
    compile 'com.fasterxml.jackson.core:jackson-databind:2.4.+'
    compile 'com.fasterxml.jackson.core:jackson-core:2.4.+'
    compile 'com.fasterxml.jackson.core:jackson-annotations:2.4.+'
    compile 'com.squareup.okhttp:okhttp:2.0.+'
    compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.+'
}

IDEとテキストエディタ

エディターは何を使っても良いが、例のプロジェクト構成のまま扱えるものが良い

エディターはプロジェクト構成、ビルドシステムにあったものを選べば良い。

一番推奨されるIDEはAndroid Studioである。Google が開発しており、Gradleと親和性が高いうえ、プロジェクト構成もデフォルトで推奨されているものを採用しているからだ。

もしお望みならEclipse ADTをつかってもいいが、デフォルトで古いプロジェクト構成でかつAntを採用しているので設定が必要である。EclipseのGradleプラグインが動かない場合はコマンドラインでやるか、Android Studioに移行するかしかない。
またVim、Sublime TextやEmacsといった純粋なテキストエディタを使用することさえできる。その場合は、コマンドラインからGradleとadbを使えるよう準備する必要がある。

何を使っても良いが、Gradleを使う事と新しいプロジェクト構成で開発する事がオフィシャルな方法である事を頭に入れておかねばならない。またAntのbuild.xmlなどのエディタ特有の設定ファイルなどはバージョン管理外とすることもお忘れなく。特に、Antのビルド設定を変更した際はbuild.gradleが最新であり機能する事を確認することを怠ってはならない。また他の開発者が使っているツールの設定を強要することがないようにしよう。

Libraries

JacksonはObjectをJSONに変換、またその逆を行うライブラリである。GSONもJsonのライブラリとして有名だが、streaming、in-memory tree model, Json data binding等をサポートしている点でJacksonの方がいくらか優れていると判断した。ただ覚えておいてほしいのはJacksonがGsonよりボリュームの大きなライブラリである事だ。65k制限を避ける為にGSONの方が有効なケースもあり得る。また他にはjson-smartBoon JSONという選択肢もある。

ネットワーク、キャッシュ、画像処理

バックエンドへのリクエスト処理の実装についていろいろ試した結果言えるのは、自分でクライアントを実装しない方がいいということだ。VolleyRetrofitを使おう。Volleyはまた画像のロード、キャッシュのヘルパーを提供してくれている。Retrofitを選ぶ人は、Picassoという画像ライブラリ、またHttpリクエストに有効なOkHttpの導入も考えると良い。この三つのRetrofit、Picasso、OkHttpは一つの会社で作られている。そのため、これらのライブラリは互いをよく補っている。現にOkHttpはVolleyと共に使われることがよくある。

RxJava

RxJavaはリアクティブプログラミングを行う、つまり非同期イベントを扱う為のライブラリだ。これは強力で有望なものだが、通常のプログラミングと異なりすぎる為に困惑をもたらす事がある。私たちはこのライブラリをアプリ全体のアーキテクチャに使う前に注意して扱うことをお勧めする。RxJavaを用いて作った我々のプロジェクトがいくつかあった。もし助力が必要なら次のメンバに話してみると良いかもしれない: Timo Tuominen, Olli Salonen, Andre Medeiros, Mark Voit, Antti Lammi, Vera Izrailit, Juha Ristolainen
またいくつかブログの記事も書いている。[1] [2] [3] [4]

もしRxを使った経験が以前にないのなら、まずはAPIのレスポンスのみ、もしくはクリックイベントや検索フィールドのテキスト変更イベントなどのUIのイベントハンドリングのみに適用するところから始めると良い。
逆にRxに自信があってプロジェクト全体で使いたい場合は、トリッキーな場所にJavadocを書くと良い。RxJavaのようなよく知られていない他のプログラミング手法を使用する場合はメンテナンスが大変であることを忘れてはいけない。あなたのRxで書かれたコードが他の人も理解できるようにベストを尽くそう。

RetrolambdaはAndroidやJDK8以前のプラットフォームでlambda記法を使う事ができるようになるライブラリである。特にRxJavaなど関数型スタイルを採用する場合において、これはコードを短く、見やすくする。
JDK8をインストールして、SDKのときと同じようにAndroid Studioに設定する必要がある。JAVA8_HOMEJAVA7_HOMEを設定後、ルートのbuild.gradleを下記のように書き

dependencies {
    classpath 'me.tatarka:gradle-retrolambda:2.4.+'
}

そしてそれぞれのモジュールをbuild.gradleに追加する

apply plugin: 'retrolambda'

android {
    compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

retrolambda {
    jdk System.getenv("JAVA8_HOME")
    oldJdk System.getenv("JAVA7_HOME")
    javaVersion JavaVersion.VERSION_1_7
}

Android StudioはJava8のlambda記法のためのコードアシストをサポートしている。もし、あなたがlambdaのビギナーであれば、下記にならって使ってみよう

  • 一つだけメソッドがあるインターフェイスはどれも“lambdaに親和性あり“で、構文をより短くできる

  • もしパラメータなどに迷ったときは、普通のインナークラスを書いて、Android Studioでそれをlambdaに盛り込ませてみよう

65k制限に注意して、たくさんのライブラリを使うのを避けよう

Androidアプリはdexファイルにパッケージングする際に関数の参照は65536個までという厳格な制限がある。[1] [2] [3]。制限を超えた場合はFatal Errorが起きる、そのため、ライブラリは最小限とし、制限内に収まるようdex-method-countsツールを使って使用するライブラリを決めよう。特にGuavaは13kも関数があるので避けた方がいい。

Activities and Fragments

AndroidにおいてはUIの実装はFragmentで行うべきである。Fragmentは、アプリ内で構成出来る再利用可能なUIである。ActiivtyではUIの実装をせずにFragmentで行うことをすすめる。理由は下記である。

・ multi-pane layoutの解決

Fragmentは元はphoneアプリケーションをTableアプリケーションへ拡張するためのものとして紹介された。phoneアプリでAもしくはBというpaneが占めている場合に、TabletではAとBを表示することができる。はじめからfragmentを使っているなら、あとであとで異なるフォームファクタへ変更する事が簡単になる。

・ スクリーン間のコミニケーション

AndroidはActivity間の通信として複雑なデータ(たとえばJava Object)を送るAPIを提供していない。Fragmentであれば、その子Fragment間の通信経路としてActivityのインスタンスを使う事ができる。とはいえ、Ottogreenrobot-EventBusを使ってEventBusを使いたいと思うだろう。他のライブラリの追加を避けたい場合はRxJavaを用いてEventBusを実装する事も可能である。

・ FragmentはUIだけじゃなくても十分につかえる

ActivityのbackgroundワーカとしてfragmentをUIなしでもつこともできる。Activityにロジックを持たせる代わりに、複数のfragmentを変更するロジックを持ったfragmentを作ることも可能である

・ FragmentからActionBarを管理できる

ActionBarを管理するだけのUIを持っていないFragmentをもっても良いし、また現在表示されているFragmentにActionBarの振る舞いをまかせても良い。詳しくはこちらを参考にしてほしい。

matryoshka bugsが起きるので、Fragmentを大規模にネストすべきではない。例えば、横スライドするViewPagerをもったfragmentのなかに表示するfragmentといった理にかなったケースもしくは十分に考えられている場合のみ使用すべきである。

設計レベルの話をすると、アプリは一つのトップレベルのActivityを持つべきである。他のActivityはIntent.setData()Intent.setAction()などで簡単に遷移でき、メインのActivityをサポートするくらいにすると良い。

Java packages architecture

Androidにおける設計はおおよそModel-View-controllerである。Androidにおいては、FragmentとActivityがControllerに相当するが、一方で、一方で、これらは明らかにユーザインターフェイスであり、Viewでもある。

以上のことから、FragmentまたはActivityを厳格にControllerかViewかに分類する事は難しい。そのため分類せずにfragmentはfragmentsというパッケージに納めると良い。Activityはトップレベルのパッケージに置いても良いが、もし2つ3つ以上あるならactivitiesというパッケージを作ると良い。

その他は典型的なMVCだ。modelsパッケージはAPIレスポンスをJSON parseを通した結果のPOJOを入れ、viewsにはカスタムView,Notifications,ActionBar View, ウィジェットなどを配置する。Adapterはviewとデータの間にいるので微妙だが、getView()メソッドからViewを生成する必要がよくあるので、viewsパッケージのサブパッケージとしてadaptersを作りそこに配置すると良い。

アプリ内で多様に使われAndroidシステムに密接なコントローラクラスはmanagersパッケージへ、各Dataを混ぜこぜにつかうDataUtilのようなクラスはutilsへ、バックエンドとインタラクティブに反応するクラスはnetworkパッケージに配置しよう。

バックエンドに最も近いところからユーザに最も近いところへという順で並べると下記のような構成になる。

com.futurice.project
├─ network
├─ models
├─ managers
├─ utils
├─ fragments
└─ views
   ├─ adapters
   ├─ actionbar
   ├─ widgets
   └─ notifications

Resources

命名規則

たとえば、fragment_contact_details.xml, view_primary_button.xml, activity_main.xmlといったように、type_foo_bar.xmlというタイプを接頭辞とする慣習に従おう。

Layout xmlを整理しよう

もしLayout xmlのフォーマット方法が不明確なら下記の慣習が役立つと思われる。

  • 1 attribute につき 1 lineでインデントは4スペース
  • android:idは常に一番始めに
  • android:layout_****は上に
  • styleは一番下
  • attributeを追加しやすいように/>のみで1 line
  • android:textをハードコーディングするよりは、Designtime attributesを使う事を考えた方が良い
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <TextView
        android:id="@+id/name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:text="@string/name"
        style="@style/FancyText"
        />

    <include layout="@layout/reusable_part" />

</LinearLayout>

大雑把に言うと、android:layout_****はLayout xmlで定義して、それ以外のandroid:****はStyle xmlの中で定義すると良い。下記を除くと大抵この方法でうまく収まる。

  • android:idは確実にLayout xml内に
  • LinearLayoutの'android:orientation`はLayout xml内に
  • android:textはLayout xmlに
  • 時々Style xmlにandroid:layout_widthandroid:layout_heightを定義してうまく行く事がある。(しかし、デフォルトではこれらはlayout filesの中にある)
Styleを使おう

Viewに統一感を持たせる為にStyleを適切に使う必要がある。Viewが繰り返し出ることはよくあることだからだ。少なくとも下記のようにText用のStyleは持っておいた方が良い。

<style name="ContentText">
    <item name="android:textSize">@dimen/font_normal</item>
    <item name="android:textColor">@color/basic_black</item>
</style>

このスタイルはTextViewでは下記の用に使う事ができる。

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/price"
    style="@style/ContentText"
    />

同じことをボタンにもする必要があるが、そこで終わりにせず、関連性のあるまたは繰り返されたグループを移動して、android:****を共通のStyleに書き出そう。

大きなStyle Fileを避け、複数に分けよう

1つのstyles.xmlだけを持つ事は止めた方が良い。styleファイルはstyle_home.xmlstyle_item_details.xmlstyles_forms.xmlと言ったように複数持つ事ができる。res/valuesの中のファイル名は任意である。

color.xmlはカラーパレットである。

colors.xmlは色の名前で定義しよう。下記のように各ボタンによって定義するといったようなことはすべきじゃない。

<resources>
    <color name="button_foreground">#FFFFFF</color>
    <color name="button_background">#2A91BD</color>
    <color name="comment_background_inactive">#5F5F5F</color>
    <color name="comment_background_active">#939393</color>
    <color name="comment_foreground">#FFFFFF</color>
    <color name="comment_foreground_important">#FF9D2F</color>
    ...
    <color name="comment_shadow">#323232</color>

こういう書き方をしてしまうと基本色を変更する場合などに対応しづらい。"button"や"comment"といった内容はbutton styleで定義すればよく、colors.xmlの中に定義すべきではない。

colors.xmlは下記のように定義しよう。

<resources>

    <!-- grayscale -->
    <color name="white"     >#FFFFFF</color>
    <color name="gray_light">#DBDBDB</color>
    <color name="gray"      >#939393</color>
    <color name="gray_dark" >#5F5F5F</color>
    <color name="black"     >#323232</color>

    <!-- basic colors -->
    <color name="green">#27D34D</color>
    <color name="blue">#2A91BD</color>
    <color name="orange">#FF9D2F</color>
    <color name="red">#FF432F</color>

</resources>

nameは色の名前でなく"brand_primary", "brand_secondary", "brand_negative"などとしても良い。そうする事で色の変更がしやすくなり、またどれだけの色が使われているかがわかりやすい。通常、きれいなUIの為には使用する色を減らす事も重要だ。

dimens.xmlもcolors.xmlのように扱おう

典型的なスペースやフォントサイズをcolors.xmlのパレットのように定義しよう。下記は良い例である。

<resources>

    <!-- font sizes -->
    <dimen name="font_larger">22sp</dimen>
    <dimen name="font_large">18sp</dimen>
    <dimen name="font_normal">15sp</dimen>
    <dimen name="font_small">12sp</dimen>

    <!-- typical spacing between two views -->
    <dimen name="spacing_huge">40dp</dimen>
    <dimen name="spacing_large">24dp</dimen>
    <dimen name="spacing_normal">14dp</dimen>
    <dimen name="spacing_small">10dp</dimen>
    <dimen name="spacing_tiny">4dp</dimen>

    <!-- typical sizes of views -->
    <dimen name="button_height_tall">60dp</dimen>
    <dimen name="button_height_normal">40dp</dimen>
    <dimen name="button_height_short">32dp</dimen>

</resources>

marginやpaddingをハードコードするのではなく、spacing_****を使用するようにしよう。そうする事で簡単に全体に統一感を持たす事ができ、また整理も簡単にできる。

Viewの深いネストは止めよう

下記のようにLinearLayoutを組み合わせてViewを作ろうとすることがある。
そうするとLayout xmlは下記のようになる。

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <RelativeLayout
        ...
        >

        <LinearLayout
            ...
            >

            <LinearLayout
                ...
                >

                <LinearLayout
                    ...
                    >
                </LinearLayout>

            </LinearLayout>

        </LinearLayout>

    </RelativeLayout>

</LinearLayout>

もし、一つのLayout ファイルに書いていなくてもJava側でinflateした際に同じ状況になる事もあり得る。

これはいくつかの問題起こす。まずはきっとあなたも経験しただろう、UIの煩雑さによるパフォーマンス低下の問題である。他にも深刻なStackOverFlowを起こす可能性もある。

以上の理由から、Viewの階層はなるべくフラットにするべきである。そのためにRelativeLayoutの使い方、Layoutの最適化の方法、<merge>タグの使い方を知っておこう。

WebViewの参照問題に気をつけよう

例えばNewsの記事などのweb pageを表示する必要がある場合、クライアントサイドでHTMLを整形する事は止めた方が良い。HTMLはバックグラウンドプログラマに用意してもらおう。またWebViewはActivityの参照を持つときにメモリリークしうる。Activityの代わりにApplicationContextを使用しよう。単純なテキストやボタンを表示するのにTextViewやButtonではなくWebViewを使用する事も避けた方がいい。

テストフレームワーク

Android SDKのテストフレームワークは特にUIテストにおいてまだまだ未熟なところがある。
Android Gradleに、あなたがAndroidのJUnitのヘルパーを使って書いたJUnitのテストを走らせるconnectedAndroidTestがある。これはdeviceもしくはemulatorをつなぐ必要がある。次のテストガイドを見ておこう。[1] [2]

viewを使わないUnitテストにはRobolectricを使おう

このテストフレームワークはデバイスにつなぐ必要がないため開発効率があがる。UIのテストには向いていないがモデルとViewモデルのテストに適している。

Robotiumは簡単にUIテストを作る事ができる

このテストフレームワークにはViewの取得、解析する為のヘルパーメソッド、スクリーンをコントロールする為のヘルパーメソッドが多く用意されている。テストケースも下記のようにシンプルに書く事ができる。

solo.sendKey(Solo.MENU);
solo.clickOnText("More"); // searches for the first occurence of "More" and clicks on it
solo.clickOnText("Preferences");
solo.clickOnText("Edit File Extensions");
Assert.assertTrue(solo.searchText("rtf"));
Emulator

Androidアプリを専門で開発していくならGenymotion emulatorのライセンスは買っておいた方が良い。Genymotionは通常のAVD Emulatorよりも早い。またアプリのデモ、ネットワーク接続品質のエミュレート、GPS、などなどを行う為のツールがそろっている。
テストはたくさんの端末で行わなければならないが、実際にたくさんの端末を買うよりはGenymotionのライセンスの方がコスパが良い。

注: GenymotionはGoogle Play StoreやMapなどがインストールされていない。またSumsungの特定のAPIをテストしたい場合は、実際のSumsungの端末を使う必要がある。

Proguardの設定

ProguardはAndroid Projectでコードを圧縮、難読化するために使われる。

Proguardを使用するか否かはプロジェクトの設定に依る。通常リリースapkをビルドする際にProguardを使う場合gradleを下記のように設定する。

buildTypes {
    debug {
        runProguard false
    }
    release {
        signingConfig signingConfigs.release
        runProguard true
        proguardFiles 'proguard-rules.pro'
    }
}

どのコードを保存し、どのコードを捨て難読化するかをを明確に示さなければならない。デフォルトの設定ではSDK_HOME/tools/proguard/proguard-android.txtを使用する。またmy-project/app/proguard-rules.proに定義する事でデフォルトのものに追加することができる。

ProGuard関連のよくある問題でビルドが成功したにもかかわらず、アプリの起動でClassNotFoundExceptionNoSuchFieldExceptionなどのExceptionを発生してアプリがクラッシュすることがある。これは以下の二つのどちらかを意味する。

  1. ProGuardが必要なクラス、enum、関数、フィールド、アノテーションを削除してしまった。
  2. リフレクションなどを使っており難読化によってリネームされたクラスへの参照ができない。

もしあるオブジェクトが削除されている疑いがあるならapp/build/outputs/proguard/release/usage.txtを確認しよう。オブジェクトの難読化結果を見るならapp/build/outputs/proguard/release/mapping.txtを確認しよう。

必要なクラスや関数の削除を防ぐにはkeepオプションをproguard configに追加しよう。

-keep class com.futurice.project.MyClass { *; }

難読化を防ぐにはkeepnamesを使う。

-keepnames class com.futurice.project.MyClass { *; }

サンプルとしてこちらを確認しよう。またProguardも読んでおくと良い。

Tip

リリースするたびにmapping.txtを保存しておこう。ユーザがバグを踏み、難読化されたスタックとレースを送ってきた際にデバッグする事ができる。

DexGuard

さらに最適化され、さらに難読化されたものを考えるならDexGuardの採用を考えよう。DexGuardはProGuardを作った同じチームが開発している商用のものである。さらにDexGuardなら簡単にDexファイルを分割し65k制限を解決する。

License

Futurice Oy Creative Commons Attribution 4.0 International (CC BY 4.0)