ทำความรู้จัก Android Gradle Build Tools ตัวใหม่ พร้อม Syntax แบบใหม่ ขับเคลื่อนด้วย Gradle 2.5

Posted on 13 Jul 2015 02:21 | 11554 reads | 0 shares
 

Android Studio 1.3 เข้าใกล้สู่ Stable Release แล้ว เริ่มมีของใหม่ออกมาให้เล่นเรื่อยๆ ไม่ว่าจะเป็นฟีเจอร์ที่เพิ่มขึ้นมาเพียบบน Android Studio การสนับสนุน NDK เต็มรูปแบบ รวมถึง Gradle Build Tools ตัวใหม่ ที่ปรับ DSL (โครงสร้างในไฟล์ build.gradle) ไปหมดเลย

หลังจากเล่นไปได้หน่อยนึงก็ดูน่าสนใจดี เพราะเชื่อน่าจะอีกไม่นานเราคงต้องย้ายไปใช้ Syntax ตัวใหม่นี้กัน วันนี้เราเลยจะมาพูดถึงตัวนี้กันครับ

อะไรคือ Android Gradle Build Tools

สำหรับใครที่ยังไม่ทราบ Android Gradle Build Tools คือ Runtime ที่เอาไว้อ่านไฟล์ build.gradle ของโมดูล แล้วแปลความก่อนจะส่งไปให้ Gradle ไปทำงานต่อ

ในโค้ดเราประกาศเวอร์ชั่นของ Android Gradle Build Tools ไว้ที่ไฟล์ build.gradle ของแอพฯดังนี้

dependencies {
    classpath 'com.android.tools.build:gradle:1.2.3'
}

ซึ่ง Gradle Build Tools เวอร์ชั่นต่างๆ จะทำงานร่วมกับเวอร์ชั่นของ Gradle ที่สนับสนุน ดังนี้

Android Gradle Plugin Gradle
1.0.0 - 1.1.3 2.2.1 - 2.3
1.2+ 2.2.1+

ดังนั้นรูปแบบการเขียน Gradle Script ในไฟล์ build.gradle ที่เราเขียนอยู่ทุกวันนี้ก็เลยเป็นรูปแบบของเจ้า Android Gradle Build Tools นี่เอง ซึ่งภาษาที่เราใช้เขียนไฟล์ build.gradle นี้คือ DSL (Domain-Specific Language)

รู้จัก Android Gradle Build Tools ตัวใหม่

หลังจากคง DSL ให้เหมือนเดิมมาตั้งแต่ Gradle Build Tools 1.0 ล่าสุดตอนนี้ทางทีมพัฒนา Gradle Build Tools ก็ตัดสินใจยกเครื่องใหม่หมด โดยเปลี่ยนฐานการพัฒนาไปใช้ Component ใหม่ที่มาใน Gradle ตัวใหม่แทน ซึ่งจะลดเวลาในการ Configuration ไปได้มากอย่างมีนัยสำคัญ แต่ผลที่ตามมาคือ DSL ก็เลยเปลี่ยนใหม่หมด ทางทีมพัฒนากำลังพยายามเอาความเปลี่ยนแปลงเหล่านี้ออกให้มากที่สุดเท่าที่เป็นไปได้อยู่ เพื่อที่จะได้ไม่ต้อง Migrate โค้ดกันเยอะ อย่างไรก็ตามโครงสร้างใหม่ก็มาพร้อมสิ่งที่ดีกว่า เพราะอ่านแล้วสื่อกว่าเดิมมาก

โดย Gradle Build Tools ตัวใหม่นี้ยังอยู่ในช่วงทดลอง (Experimental) อยู่ ก็เลยยังไม่มีเลขเวอร์ชั่น หากต้องการจะลองใช้ ให้เปลี่ยนไฟล์ build.gradle ของโปรเจคเป็น

dependencies {
    classpath 'com.android.tools.build:gradle-experimental:0.1.0'
}

ข้อจำกัดของ Gradle Build Tools ตัวใหม่นี้คือ ทำงานได้กับ Gradle 2.5 เท่านั้น ดังนั้นเราเลยต้องไปเปลี่ยนส่วนของ distributionUrl ในไฟล์ gradle/gradle-wrapper.properties ให้เป็น

distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-bin.zip

 

เข้าหน้า Settings โดยกดไปที่ File -> Settings สำหรับ Windows หรือ Android Studio -> Preferences บน Mac OS X แล้วเลือก Use default gradle wrapper

defaultwrapper

จากนั้นต้องเปลี่ยนรูปแบบในไฟล์ build.gradle ของโมดูลใหม่หมด จากเดิม

apply plugin: 'com.android.application'

android {
    compileSdkVersion 22
    buildToolsVersion "23.0.0 rc3"

    defaultConfig {
        applicationId "com.inthecheesefactory.hellojni25"
        minSdkVersion 15
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.2.0'
}

ให้เป็น

apply plugin: 'com.android.model.application'

model {
    android {
        compileSdkVersion = 22
        buildToolsVersion = "23.0.0 rc3"

        defaultConfig.with {
            applicationId = "com.inthecheesefactory.hellojni25"
            minSdkVersion.apiLevel = 15
            targetSdkVersion.apiLevel = 22
            versionCode = 1
            versionName = "1.0"
        }
    }
    android.buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles += file('proguard-rules.pro')
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.2.0'
}

ซึ่งจะสังเกตว่ารูปแบบมีการเปลี่ยนไปพอสมควร com.android.application เดิมก็ถูกเปลี่ยนเป็น com.android.model.application ส่วนบรรทัดต่างๆก็เพิ่มเครื่องหมาย = ขึ้นมา และเครื่องหมาย += ก็ถูกเอามาใช้เพื่อเพิ่มค่าอีกด้วย อันไหนที่ชื่อ Key ความหมายไม่ชัด ก็ถูกเพิ่มข้อความมาเช่น minSdkVersion ก็เปลี่ยนเป็น minSdkVersion.apiLevel

แล้วก็ Sync Gradle ถือเป็นอันเรียบร้อย

syncgradle

รันได้เหมือนเดิมแต่ด้วย Syntax ที่สวยขึ้น แถมยังใช้ Gradle ตัวใหม่ล่าสุดอย่าง Gradle 2.5 ด้วย

run

ลองใช้ NDK

Android Studio 1.3 มาพร้อมกับ NDK Support เต็มรูปแบบขนาดนี้แล้ว ไม่ลองเล่นก็คงไม่ได้ เริ่มต้นด้วยการกำหนด Path ของ NDK r10e ที่ดาวน์โหลดมาจาก Android NDK Downloads Page หรือใครโหลด NDK Bundle จาก SDK Manager มาก็ใช้งานได้เช่นกัน โดยใส่ Path ไว้ในไฟล์ local.properties

ndk.dir=PATH_TO_NDK_ROOT

จากนั้นสร้างไฟล์ HelloJni.java ขึ้นมาในโปรเจค ดังนี้

public class HelloJni {
    public native String stringFromJNI();
}

แล้วก็สร้างโฟลเดอร์ jni ไว้ในโฟลเดอร์ main แล้วสร้างไฟล์ hello-jni.c ตามเนื้อหาไฟล์ดังนี้

hello-jni.c

#include <string.h>
#include <jni.h>

jstring
Java_com_inthecheesefactory_hellojni25_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
#if defined(__arm__)
  #if defined(__ARM_ARCH_7A__)
    #if defined(__ARM_NEON__)
      #if defined(__ARM_PCS_VFP)
        #define ABI "armeabi-v7a/NEON (hard-float)"
      #else
        #define ABI "armeabi-v7a/NEON"
      #endif
    #else
      #if defined(__ARM_PCS_VFP)
        #define ABI "armeabi-v7a (hard-float)"
      #else
        #define ABI "armeabi-v7a"
      #endif
    #endif
  #else
   #define ABI "armeabi"
  #endif
#elif defined(__i386__)
   #define ABI "x86"
#elif defined(__x86_64__)
   #define ABI "x86_64"
#elif defined(__mips64)  /* mips64el-* toolchain defines __mips__ too */
   #define ABI "mips64"
#elif defined(__mips__)
   #define ABI "mips"
#elif defined(__aarch64__)
   #define ABI "arm64-v8a"
#else
   #define ABI "unknown"
#endif

    return (*env)->NewStringUTF(env, "Hello from JNI !!  Compiled with ABI " ABI ".");
}

และอย่าลืมเปลี่ยนชื่อฟังก์ชั่นในภาษาซีในส่วน com_inthecheesefactory_hellojni25 ให้ตรงกับชื่อ Package ของไฟล์ HelloJni.java ด้วย มิฉะนั้นจะใช้งานไม่ได้

สำหรับคนที่เคยชินกับ NDK ก็จะเห็นว่าเราไม่ต้องเขียน Android.mk และ Application.mk แล้ว เพราะทุกอย่างถูกรวมไว้ใน Build Tools แล้วนั่นเอง

โครงสร้างไฟล์จะเป็นแบบนี้

files

กำหนดชื่อโมดูลของ Native Code ลงไปใน build.gradle

model {
    ...
    android.ndk {
        moduleName = "hello-jni"
    }
    ...
}

คราวนี้มาแก้ไขไฟล์ MainActivity.java เพื่อทดสอบโค้ดส่วน JNI โดยเพิ่มโค้ดด้านล่างนี้ไว้ด้านล่างสุดของคลาส MainActivity

public class MainActivity extends AppCompatActivity {

    ...

    static {
        System.loadLibrary("hello-jni");
    }
}

และแก้ไขส่วนของ onCreate ดังนี้

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toast.makeText(MainActivity.this,
                        new HelloJni().stringFromJNI(),
                        Toast.LENGTH_LONG)
                .show();
    }

เรียบร้อย เพียงแค่นี้ก็ใช้งาน NDK ได้แล้วครับ ลองกดรันได้เลย ผลการทำงานเป็นดังนี้

screenshot18

และด้วยความสามารถของ NDK Support บน Android Studio ทำให้เราสามารถกดจิ้มที่ไฟล์ Java แล้วมันจะเด้งไปที่ไฟล์ภาษาซีให้ทันที

linkjni

แต่อย่างไรก็ตาม ฟังก์ชั่นอื่นๆยังคงใช้งานได้บ้างไม่ได้บ้าง คงต้องรออีกสักพักครับ

สรุป

โดยรวมแล้ว Gradle Build Tools ตัวใหม่เป็นอะไรที่น่าสนใจเพราะ DSL เปลี่ยนไปในทางที่ดีขึ้น แต่ตอนนี้ยังไม่ถึงเวลาที่จะใช้เพราะยังอยู่ในขั้นทดลองอยู่ แค่ศึกษาไว้ก่อนก็ดีเพราะในอนาคตอีกไม่นานก็คงต้องแก้ Gradle Script ตามรูปแบบใหม่นี้อยู่ดี

ข้อมูลเพิ่มเติม >> Experimental Plugin User Guide

จบครับ =)

ผู้เขียน: nuuneoi (Android GDE, CTO & CEO at The Cheese Factory)
นักพัฒนาแบบ Full-Stack ที่มีประสบการณ์ในการพัฒนาแอพฯแอนดรอยด์มากว่า 6 ปีและอยู่ในวงการพัฒนาแอพฯมือถือมากว่า 12 ปี มีความสนใจทางด้าน Infrastucture, Service Side, Design, UI&UX, Hardware, Optimization, Cooking, Photographing, Blogging, Training, Public Speaking และรักที่จะแชร์เรื่องราวให้ผู้คนได้อ่านได้ฟังกันผ่าน Blog