+5

Android best practice

Nguồn : https://github.com/futurice/android-best-practices

Tổng hợp

  • ####Phát triển theo project structure được Gradle khuyến khích
  • ####Viết password và data cần chú ý vào gradle.properties
  • ####Không sử dụng HTTP Client, thay vào đó là Volley hay OkHttp
  • ####Nếu muốn parse JSON dùng Jackson
  • ####Do lượng method tối đa là 65000 cho nên tránh sử dụng Guava và giảm dùng library tối đa.
  • ####Sử dụng Fragment để vẽ UI
  • ####Activity chỉ sử dụng để quản lý Fragment
  • ####Quản lý tốt Layout xml
  • ####Sử dụng style để tránh chồng chéo thuộc tính của Layout xml
  • ####Thay vì định nghĩa một Style lớn, hãy định nghĩa thành nhiều Style
  • ####colors.xml hãy để ngắn và DRY(「Don't Repeat Yourself」)、định nghĩa bằng pallete
  • ####dimens.xml hãy để DRY và định nghĩa những constant phổ biến
  • ####ViewGroup Nest không được để quá sâu
  • ####WebView dễ làm memory leak cho nên tránh xử lý tại client
  • ####Unit Test sử dụng Robolectric, integration test sử dụng Robotium
  • ####emulator tuỳ vào Genymotion
  • ####Nhất định sử dụng ProGuard hoặc DexGuard

Android SDK

Android SDK đặt ở home directory hoặc nơi độc lập với các app khác. Có một vài IDE có bao gồm SDK, khi cài vào thì sẽ đặt SDK cùng nơi với thư mục IDE luôn. Nếu cứ để thế này thì khi có upgrade hay cài lại IDE sẽ rất phiền. Thêm nữa, khi chạy IDE với account không phải root, tránh việc đặt sdk vào những thư mục system level khác cần có sudo.

Build system

Sử dụng Gradle tại default option. Ant có nhiều hạn chế và đắt.Tuy nhiên với Gradle có thể làm những điều dưới đây một cách đơn giản.

  • Có thể build được các Flavor hay Variant khác nhau của app
  • Có thể tạo được các task như script.
  • Có thể vừa download vừa bảo toàn quan hệ dependency
  • Có thể customize keystore
  • Và nhiều thứ khác

Google phát triển rất nhiều dựa trên việc coi Gradle của Android như build system tiêu chuẩn.

Project Structure

Về project structure, có 2 loại nổi tiếng là Ant & Eclipse ADT và kiểu mới Gradle & Android Studio, tuy nhiên từ nay về sau phải chọn kiểu thứ 2. Nếu bạn đang làm 1 project có cấu trúc như kiểu 1, hãy coi nó như di sản cuối cùng và phải nghĩ cách chuyển sang kiểu thứ 2.

  • 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

Điểm khác biệt lớn nhất chính là project structure mới tách rõ ràng 'Source sets'(main, androidTest). Đây chính là tư tưởng của Gradle. Dựa theo điều đó, ví dụ như thêm paid và free Source set vào src, sẽ có Flavor 'paid' và 'free'. Thêm nữa, nếu app ở top-level, nó sẽ giúp ích phân tách library project như library-foobar được tham chiếu trong app. setting.gradle có tham chiếu tới từng library và có thể tham chiếu từ app/build.gradle.

Cài đặt Gradle

Cấu trúc phổ biến

Tham khảo Google's guide on Gradle for Android.

Một task nhỏ

Thay thế cho script của shell, Python, Perl, có thể tạo task trong Gradle. Hãy xem Gradle's documentation để biết thêm chi tiết.

Password

Có thời điểm phải định nghĩa signingConfigs trong build.gradle cho release build. Phía dưới là ví dụ về trường hợp không tốt, bị quản lý bởi hệ thống quản lý version.

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

Cách làm tốt là viết vào gradle.properties rồi bỏ file này khỏi quản lý version.

KEYSTORE_PASSWORD=password123
KEY_PASSWORD=password789

File này sẽ được tự động import dựa theo gradle cho nên hãy viết build.gradle như sau ở thời điểm này:

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.")
        }
    }
}

Thay vì import trực tiếp file jar, nên sử dụng Maven.

Khi trực tiếp include file jar vào project, giống như version2.1.1, version sẽ bị cố định lại. Ngoài ra, download file jar, do phải update thủ công nên hiệu suất thấp. Có thể giải quyết được vấn đề này với Maven, Android Studio cũng khuyến khích sử dụng Maven. Có thể chỉ định được phạm vi version như 2.1.+, sau đó update bản mới nhất trong vùng chỉ định cho mình.

Ví dụ ta sẽ viết như dưới đây:

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 và text editor

Ta có thể sử dụng editor bất kỳ tuy nhiên nên sử dụng cái có thể làm luôn với project structure như ví dụ.

Editor nên chọn cái hợp với project structure và build system.

IDE được khuyên dùng nhất là Android Studio. IDE này được Google phát triển, tương thích tốt với Gradle, thêm nữa sử dụng default project structure được khyên dùng.

Nếu muốn bạn cũng có thể sử dụng Eclipse ADT, tuy nhiên default của nó là project structure cũ và sử dụng Ant cho nên cài đặt lại. Nếu plugin Gradle của Eclipse không hoạt động chỉ có cách dùng command line hay chuyển sang Android Studio.

Ngoài ra, có thể sử dụng các text editor thuần như Vim, Sublime Text hay Emacs. Trong trường hợp này, cần chuẩn bị để có thể sử dụng được Gradle hay adb từ command line.

Bạn có thể sử dụng tuỳ thích tuy nhiên hãy luôn nhớ chuyện cần sử dụng Gradle và project structure mới. Thêm nữa hãy nhớ bỏ những file setting của editor như build.xml của Ant ra khỏi sự quản lý của version control. Đặc biệt, sau khi thay đổi cài đặt build của Ant, cần kiểm tra chức năng mới nhất của build.gradle. Ngoài ra, không cần bắt buộc cài đặt tool mà các developer khác sử dụng.

Libraries

Jackson là thư viện chuyển JSON thành Object và ngược lại. GSON cũng là thư viện Json nổi tiếng, truy nhiên xét về mặt hỗ trợ streaming、in-memory tree model, Json data binding.. thì Jackson đã được chứng minh là tốt hơn. Tuy nhiên nen nhớ rằng Jackson nặng hơn Gson rất nhiều. Do có hạn chế 65000 method nên có trường hợp dùng GSON sẽ tốt hơn. Ngoài ra có các lựa chọn như json-smartBoon JSON.

Network, Queue, Xử lý ảnh

Tôi đã thử nghiệm rất nhiều implement xử lý request tới backend và từ kết quả cho ra kết luận rằng không nên tự mình implement client. Hãy sử dụng Volley hay Retrofit. Volley còn giúp load ảnh, cung cấp helper cho queue. Người sử dụng Retrofit nên sử dụng thư viện ảnh PicassoOkHttp có ích với Http request. Retrofit, Picasso, OkHttp được cùng 1 công ty tạo ra, vì thế độ tương thích giữa các library lớn. Hiện nay mọi người cũng hay sử dụng OkHttp cùng với Volley.

RxJava

RxJava thực hiện reactive programming, tóm lại là library nhằm đối phó với event async. Đây là một tham vọng rất tốt nhưng quá khác với programming thông thường cho nên hay bị loạn. Chúng tôi khuyên các bạn nên chú ý trước khi sử dụng library này vào architecture toàn bộ app. Nếu các bạn cần sự trợ giúp nên nói chuyện thử với các member sau: Timo Tuominen, Olli Salonen, Andre Medeiros, Mark Voit, Antti Lammi, Vera Izrailit, Juha Ristolainen

Họ cũng có viết một vài bài blog.1 2 3 4

Nếu chưa có kinh nghiệm sử dụng Rx trước đây, đầu tiên hãy thử áp dụng vào API Response hay là event handling của UI như click event, event thay đổi text của field tìm kiếm. Ngược lại, nếu bạn có tự tin với Rx và muốn sử dụng trên toàn thể dự án, chỉ cần viết Javadoc tại một chỗ khéo léo là được. Không nên quên rằng việc maintain những phương pháp programming không phổ biến như RxJava là rất vất vả. Hãy cố gắng để những dòng code bằng Rx của bạn có thể dễ hiểu với người khác.

Retrolambda là library giúp có thể sử dụng ký hiệu lambda tại platform tại Android và JDK trước bản 8. Đặc biệt, trong trường hợp sử dụng style dạng function như RxJava, nó sẽ giúp code ngắn và dễ nhìn hơn. Cài JDK8, cần cài đặt Android Studio giống như với SDK. Sau khi cài đặt JAVA8_HOMEJAVA7_HOME, hãy viết build.gradle của route như phía dưới

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

Rồi thêm từng module vào 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 hỗ trợ code assist kí hiệu lambda của Java8. Nếu bạn mới làm quen với lambda, hãy học nhiều điều dưới đây và sử dụng nào.

  • Với bất kì interface nào chỉ có 1 method đều rất thích hợp với lambda, cú pháp có thể ngắn hơn nữa.
  • Nếu bị loạn về parameter, hãy viết 1 inner class thông thường rồi kết hợp cái đó vào lambda trong Android Studio thử xem.

Chú ý đến hạn chế 65000 method, tránh sử dụng nhiều library.

Android app khi packaging thành dex file, có hạn chế rất chặt chẽ về số lượng function tham chiếu là 65536.1 2 3.Nếu vượt quá hạn chế sẽ xảy ra Fatal Error. Chính vì vậy hãy tối thiểu hoá library, sử dụng dex-method-counts tool để tính toán quyết định library sử dụng nằm trong vòng hạn chế. Đặc biệt Guava có tới 13000 function, nên cần tránh sử dụng.

Activities and Fragments

Trong Android, implementation của UI cần thực hiện bằng Fragment. Fragment là UI có khả năng sử dụng lại có thể cấu trúc trong app. Tại Activity không implement UI, lời khuyên là thực hiện tại Fragment. Lý do như ở dưới đây:

  • Giải quyết multi-pane layout: Fragment vốn được giới thiệu như là thứ dùng để extend phone app tới table app. Tại phone app, nếu pane A hoặc B đang chiếm, tại Tablet sẽ có thể hiển thị A và B. Nếu sử dụng fragment từ đầu, việc thay đổi các form factor khác nhau về sau sẽ dễ dàng.
  • Communication giữa các screen: Android không cung cấp API gửi data phức tạp khi truyền tin giữa các Activity(ví dụ Java Object). Với Fragment, có thể sử dụng instance của Activity như đường truyền tin giữa các Fragmnent con đó. Tuy vậy, sử dụng Otto hay greenrobot-EventBus, mọi người muốn sử dụng EventBus. Nếu muốn tránh việc thêm các library khác, việc dùng RxJava và implement EventBus là hoàn toàn có thể.
  • Fragment không chỉ dùng với UI: Có thể có fragment không UI như Background worker của Activity. Thay vì để Activity chứa logic, có thể tạo fragment chứa logic thay đổi các fragment.
  • Có thể quản lý ActionBar từ Fragment: Có thể có fragment không có UI chỉ để quản lý ActionBar, ngoài ra giao việc chỉ đạo ActionBar cho Fragment đang hiển thị cũng được. Chi tiết hãy xem tại đây.

Sẽ xảy ra matryoshka bugs cho nên không cần thiết phải nest Fragment ở quy mô lớn. Ví dụ: trong fragment chứa ViewPager slide ngang, chỉ hiển thị fragment hiển thị khi đã suy nghĩ cân nhắc rõ ràng hay nó thực sự hợp lý.

Về chuyện liên quan đến thiết kế, app cần chỉ có một top level Activity. Các Activity khác có thể dễ dàng di chuyển bằng Intent.setData() hay Intent.setAction(), chỉ cần support Activity chính là được.

Java packages architecture

Thiết kế trong Android đa số theo Model-View-controller. Trong Android, Fragment và Activity tương đương với Controller, tuy nhiên nó cũng rõ ràng là UI và View. Từ những điều trên, rất khỏ để có thể tách Fragment, Activity là Controller hay View. Vì vậy không cần tách mà để fragment trong package fragments là được. Activity để trong top level packge cũng được, nhưng nếu có trên 2,3 cái thì nên tạo package activities.

Những thứ khác tuân theo nguyên mẫu MVC. models package có POJO kết quả đã thông qua JSON Parse các API response, views sẽ chứa custom View, Notifications, ActionBar View, Widget.. Adapter hơi mập mờ giữa view và data, tuy nhiên hay cần tạo view bằng method getView() cho nên tạo 1 subpackage adapters của package views là hợp lý.

Tại trong app, các controller class mật thiết được sử dụng đa dạng bởi Android system cho vào managers package, các class như DataUtil sử dụng nhiều các Data cho vào utils, class phản ứng tương tác với backend cho vào network package.

Cấu trúc sẽ như dưới đây từ điểm gần nhất với Backend đến điểm gần nhất với User.

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

Resources

Quy tắc đặt tên

Ví dụ: Giống như fragment_contact_details.xml, view_primary_button.xml, activity_main.xml, ta có thói quen theo loại tiền tố dạng type_foo_bar.xml.

Hãy chỉnh sửa Layout xml nào

Nếu phương thức format của Layout xml vẫn chưa rõ ràng, thói quen dưới đây có thể giúp ích:

  • Ứng với 1 attribute, 1 dòng có indent là 4 space
  • android:id luôn là thứ đầu tiên
  • android:layout_**** ở phía trên
  • style ở dưới cùng
  • Để thêm attribute dễ dàng, chỉ /> trong 1 dòng
  • Hơn việc hardcoding android:text, nên suy nghĩ sử dụng 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>

Nói chung, định nghĩa android:layout_**** tại Layout xml, những thứ khác như android:**** định nghĩa trong Style xml là ổn. Trừ những thứ phía dưới thì đại khái đều có thể sử dụng cách này:

  • android:id phải trong Layout xml
  • android:orientation của LinearLayout phải trong Layout xml
  • android:text trong Layout xml
  • Thỉnh thoảng định nghĩa android:layout_widthandroid:layout_height trong Style xml vẫn chạy tốt(tuy nhiên theo default thì những cái này sẽ nằm trong layout files)

Sử dụng Style nào

Để thống nhất ở View, cần sử dụng Style hợp lý vì View hay xuất hiện lặp đi lặp lại. Ít nhất hãy dùng Style cho Text như dưới đây:

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

Style này sử dụng như dưới đây với TextView:

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

Những thứ giống nhau cũng cần làm thành button tuy nhiên không kết thúc ở đó, di chuyển những group có mối liên quan hay lặp đi lặp lại và viết android:**** ra file Style dùng chung.

Tránh sử dụng file Style lớn mà chia thành nhiều file.

Cần thôi việc chỉ có 1 file styles.xml. File style có khả năng chứa nhiều file như style_home.xml, style_item_details.xml, styles_forms.xml. Tên file là tùy chọn trong res/values.

color.xml là color pallete.

colors.xml hãy định nghĩa tên màu. Không cần giống như phía dưới dựa vào từng button để định nghĩa.

<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>

Nếu viết theo cách này, sẽ rất khó để đối phó với trường hợp thay đổi màu cơ bản. Nội dung buttoncomment định nghĩa trong button style là được, không cần viết trong colors.xml.

colors.xmlhãy định nghĩa như phía dưới:

<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 không cần phải là tên màu mà là "brand_primary", "brand_secondary", "brand_negative" cũng được. Làm được như vậy khi thay đổi màu sẽ dễ dàng hơn, thêm nữa màu nào đang được sử dụng cũng dễ hiểu hơn. Thông thường, việc giảm lượng màu là rất quan trọng để UI được đẹp.

Làm dimens.xml giống với colors.xml

Định nghĩa space và font size điển hình theo pallete của colors.xml. Dưới đây là ví dụ:

<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>

Không hardcode margin và padding, hãy sử dụng dạng spacing_****. Nhờ vào việc này có thể thống nhất được toàn thể và việc chỉnh sửa cũng dễ dàng hơn.

Ngừng nest sâu với View

Giống như dưới đây có lúc muốn tạo View kết hợp với LinearLayout.

Khi đó Layout xml sẽ như sau:

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

    <RelativeLayout
        ...
        >

        <LinearLayout
            ...
            >

            <LinearLayout
                ...
                >

                <LinearLayout
                    ...
                    >
                </LinearLayout>
            </LinearLayout>
        </LinearLayout>
    </RelativeLayout>
</LinearLayout>

Nếu không viết vào trong 1 file Layout, sau khi inflate phía Java thì cũng có khả năng xảy ra tình trạng tương tự.

Điều này sẽ làm xảy ra một vài vấn đề. Điều đầu tiên chắc các bạn cũng đã trải nghiệm rồi, chính là giảm performance khi Ui quá phức tạp. Ngoài ra cũng có những vấn đề trầm trọng như StackOverFlow.

Từ những ví dụ trên, cần làm phẳng các tầng của View. Để làm được việc đó cần biết cách dùng RelativeLayout, cách tối ưu hóa Layout và cách sử dụng tag <merge>.

Cẩn thận vấn đề tham chiếu WebView.

Ví dụ như khi cần hiển thị webpage trong một bài News, nên ngừng việc chỉnh HTML ở clientside. HTML sẽ được chuẩn bị bởi background program. Ngoài ra, khi WebView có tham chiếu Activity dễ dẫn đến memory leak. Thay vì Activity, hãy sử dụng ApplicationContext. Không cần tránh sử dụng TextView hay Button để hiển thị text đơn thuần mà là WebView.

Test Framework

Test Framework của Android SDK vẫn chưa tương thích tốt đặc biệt với test UI.

Tại Android Gradle, bạn sử dụng helper JUnit của Android, có connectedAndroidTest để chạy test JUnit đã viết. Cái này cần liên kết với device hay emulator. Hãy cùng xem test guide sau đây1 2

Hãy sử dụng Robolectric tại Unit test không sử dụng view.

Do không cần kết nối device với test framework này giúp cải thiện được hiệu suất phát triển. Cái này không hướng tới UI test tuy nhiên hữu dụng với test model và view model.

Robotium có thể tạo UI test đơn giản.

Trong test framework này có trong bị rất nhiều helper method nhằm quản lý màn hình, helper phân tích và lấy view. Testcase có thể viết đơn giản như dưới đây:

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

Nếu chuyên biệt phát triển Android app, nên mua license cho Genymotion emulator. Genymotion nhanh hơn AVD Emulator thông thường. Thêm nữa có đầy đủ tool để thực hiện GPS, emulator chất lượng kết nối network, demo app..

Cần phải test trên nhiều device, tuy nhiên thay vì mua nhiều device thực thì license Genymotion rẻ hơn nhiều.

Chú ý: Genymotion không cài Google Play Store và Map.. Ngoài ra nếu muốn test API đặc biệt của Samsung, cần sử dụng thiết bị thực của Samsung.

Cài đặt Proguard

Proguard được dùng để làm khó đọc và nén code Android Project.

Sử dụng Proguard hay không tùy thộc vào cài đặt của project. Thông thường khi build apk release, nếu sử dụng Proguard sẽ cài đặt gradle như dưới đây:

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

Giữ hay bỏ code nào để làm khó đọc đi cần chỉ định rõ ràng. Default setting là sử dụng SDK_HOME/tools/proguard/proguard-android.txt, thêm nữa bằng việc định nghĩa tại my-project/app/proguard-rules.pro có thể thêm được những thứ default.

Có một câu hỏi rất hay gặp liên quan đến ProGuard, dù build thành công hay không, khi khởi động app sẽ xuất hiện lỗi Exception như ClassNotFoundException hay NoSuchFieldException.. và bị crash. Nó có 1 trong 2 ý nghĩa như dưới đây:

  1. Xóa mất annotation, field, function, enum, class cần cho ProGuard.
  2. Sử dụng reference, do đã bị làm khó đọc nên không thể tham chiếu class đã bị rename.

Nếu bạn nghi ngờ có object nào đã bị xóa mất hãy xác nhận với app/build/outputs/proguard/release/usage.txt. Nếu xem kết quả đã bị làm cho khó đọc của object thì hãy xác nhận với app/build/outputs/proguard/release/mapping.txt.

Để tránh xóa function hay class cần thiết, hãy thêm keep option vào proguard config.

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

Để ngăn việc làm cho khó đọc hãy sử dụng keepnames.

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

Hãy xác nhận với sample tại đây. Thêm nữa cũng nên đọc về Proguard.

Tip

Mỗi lần release, hãy lưu mapping.txt. Khi người dùng gặp bug, có thể debug từ từ stack trace đã bị làm khó đọc được gửi tới.

DexGuard

Nếu cần tới những thứ được làm cho khó đọc và tối ưu hóa hơn nữa hãy sử dụng DexGuard. DexGuard là sản phẩm của đội cũng phát triển ProGuard. Hơn nữa với DexGuard, có thể phân chia file Dex giúp giải quyết hạn chế 65000 method chain.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.