Lembar Curang Gradle

Tampak bagi saya bahwa kebanyakan orang mulai berurusan dengan gradle hanya ketika sesuatu perlu ditambahkan ke proyek atau sesuatu tiba-tiba rusak - dan setelah menyelesaikan masalah "diperoleh dengan bekerja terlalu keras" pengalaman itu dilupakan dengan aman. Selain itu, banyak contoh di Internet mirip dengan mantra khusus yang tidak menambah pemahaman tentang apa yang terjadi:


android { compileSdkVersion 28 defaultConfig { applicationId "com.habr.hello" minSdkVersion 20 targetSdkVersion 28 } buildTypes { release { minifyEnabled false } } } 

Saya tidak akan menjelaskan secara rinci untuk apa setiap baris di atas - ini adalah detail pribadi dari penerapan plugin android. Ada sesuatu yang lebih berharga - pemahaman tentang bagaimana semuanya diatur. Informasi ini tersebar di berbagai situs / dokumentasi resmi / sumber hujan es dan plugin untuk itu - secara umum, ini adalah pengetahuan yang sedikit lebih universal yang tidak ingin saya lupakan.


Teks lebih lanjut dapat dianggap sebagai lembar contekan bagi mereka yang hanya menguasai gradle atau sudah lupa.


Tautan yang bermanfaat



Konsol


Android studio / IDEA susah payah menyembunyikan perintah gradle dari pengembang, dan bahkan ketika mengubah file build.gradle itu mulai membodohi atau memulai kembali proyek.


Dalam kasus seperti itu, memanggil gradle dari konsol jauh lebih mudah dan lebih cepat. Grapper wrapper biasanya datang dengan proyek dan berfungsi dengan baik di linux / macos / windows, kecuali di yang terakhir Anda perlu memanggil file bat bukan wrapper.


Tugas tantangan


 ./gradlew tasks 

menulis tugas yang tersedia.


 ./gradlew subprojectName:tasks --all 

Anda dapat menampilkan tugas-tugas dari sub proyek yang terpisah, dan bahkan dengan opsi --all , semua tugas, termasuk yang sekunder, akan ditampilkan.


Anda dapat memanggil tugas apa pun, dan semua tugas yang bergantung padanya akan dipanggil.


 ./gradlew app:assembleDevelopDebug 

Jika Anda terlalu malas untuk menulis seluruh nama, Anda dapat membuang surat-surat kecil:


 ./gradlew app:assembleDD 

Jika hujan es tidak dapat dengan jelas menebak tugas yang mereka pikirkan, itu akan menampilkan daftar opsi yang sesuai.


Penebangan


Jumlah informasi yang ditampilkan di konsol saat memulai tugas sangat bergantung pada tingkat pencatatan.
Selain default, ada -q, -w, -i, -d , well, atau --quiet, --warn, --info, --debug dalam meningkatkan jumlah informasi. Pada proyek yang kompleks, output dengan -d dapat memakan waktu lebih dari satu megabyte, dan karena itu lebih baik menyimpannya ke file segera dan mencari di sana dengan mencari kata kunci:


 ./gradlew app:build -d > myLog.txt 

Jika pengecualian dilemparkan ke suatu tempat, opsi -s untuk stacktrace.


Anda dapat menulis ke log sendiri:


 logger.warn('A warning log message.') 

logger adalah implementasi dari SLF4J.


Asyik


Apa yang terjadi di file build.gradle hanyalah kode asyik.


Untuk beberapa alasan, Groovy, sebagai bahasa pemrograman, tidak terlalu populer, meskipun, menurut saya, itu sendiri layak untuk setidaknya dipelajari sedikit. Bahasa lahir kembali pada tahun 2003 dan perlahan berkembang. Fitur menarik:


  • Hampir semua kode java adalah kode asyik yang valid. Sangat membantu untuk menulis kode kerja secara intuitif.
  • Bersamaan dengan statis, pengetikan dinamis didukung dalam alur, daripada String a = "a" Anda dapat dengan aman menulis def a = "a" atau bahkan def map = ['one':1, 'two':2, 'list' = [1,false]]
  • Ada beberapa penutupan di mana Anda dapat secara dinamis menentukan konteks eksekusi. Blok android {...} sama ditutup dan dieksekusi untuk beberapa objek.
  • Ada interpolasi string "$a, ${b}" , string multiline """yep, ${c}""" , dan string java biasa dibingkai oleh tanda kutip tunggal: 'text'
  • Ada kemiripan metode penyuluhan. Kumpulan bahasa standar sudah memiliki metode seperti findAll, setiap, masing-masing. Bagi saya pribadi, nama-nama metode itu tampak tidak biasa, tetapi yang terpenting adalah metode itu .
  • Gula sintaksis yang lezat, kodenya jauh lebih pendek dan sederhana. Anda tidak harus menulis tanda kurung di sekitar argumen fungsi, untuk deklarasi daftar dan [a,b,c], [key1: value1, key2: value2] hash [a,b,c], [key1: value1, key2: value2] sintaks yang bagus adalah: [a,b,c], [key1: value1, key2: value2]

Secara umum, mengapa bahasa seperti Python / Javascript telah meroket dan Groovy tidak - itu adalah misteri bagi saya. Pada masanya, ketika tidak ada lambdas di Jawa, dan alternatif seperti kotlin / scala baru saja muncul atau belum ada, Groovy harus terlihat seperti bahasa yang sangat menarik.


Itu adalah fleksibilitas dari sintaks groovy dan pengetikan dinamis yang memungkinkan kami untuk membuat DSL ringkas secara bertahap.


Sekarang dalam dokumentasi resmi Gradle, contohnya digandakan di Kotlin, dan sepertinya direncanakan untuk beralih ke sana, tetapi kode itu tidak lagi terlihat begitu sederhana dan menjadi lebih seperti kode normal:


 task hello { doLast { println "hello" } } 

vs.


 tasks.register("hello") { doLast { println("hello") } } 

Namun, penggantian nama di Kradle belum direncanakan.


Tahap perakitan


Mereka dibagi menjadi inisialisasi, konfigurasi, dan eksekusi.


Idenya adalah bahwa gradle mengumpulkan grafik ketergantungan asiklik dan hanya memanggil minimum yang diperlukan. Jika saya mengerti benar, tahap inisialisasi terjadi pada saat ketika kode dari build.gradle dieksekusi.


Sebagai contoh, ini:


 copy { from source to dest } 

Atau seperti ini:


 task epicFail { copy{ from source to dest } } 

Mungkin ini tidak jelas, tetapi di atas akan memperlambat inisialisasi. Agar tidak terlibat dalam menyalin file di setiap inisialisasi, Anda perlu menggunakan doLast{...} atau doFirst{...} dalam tugas - maka kode akan dibungkus dalam penutup dan akan dipanggil ketika tugas selesai.


 task properCopy { doLast { copy { from dest to source } } } 

atau lebih


 task properCopy(type: Copy) { from dest to source } 

Dalam contoh lama, doLast dapat melihat operator << bukannya doLast , tetapi mereka kemudian mengabaikannya karena perilaku yang tidak jelas.


 task properCopy << { println("files copied") } 

semua tugas


Apa yang lucu, dengan doLast dan doFirst Anda dapat menggantung beberapa jenis tindakan pada tugas apa pun:


 tasks.all { doFirst { println("task $name started") } } 

IDE menyarankan bahwa tasks memiliki metode whenTaskAdded(Closure ...) , tetapi metode all(Closure ...) bekerja jauh lebih menarik - penutup dipanggil untuk semua tugas yang ada, serta untuk tugas baru saat ditambahkan.


Buat tugas yang mencetak dependensi semua tugas:


 task printDependencies { doLast { tasks.all { println("$name dependsOn $dependsOn") } } } 

atau lebih:


 task printDependencies { doLast { tasks.all { Task task -> println("${task.name} dependsOn ${task.dependsOn}") } } } 

Jika tasks.all{} dipanggil saat runtime (di blok doLast ), maka kita akan melihat semua tugas dan dependensi.
Jika Anda melakukan hal yang sama tanpa doLast (mis., Selama inisialisasi), maka tugas yang dicetak mungkin tidak memiliki dependensi, karena belum ditambahkan.


Oh ya, kecanduan! Jika tugas lain harus bergantung pada hasil implementasi kami, maka ada baiknya menambahkan ketergantungan:


 anotherTask.dependsOn properCopy 

Atau bahkan seperti ini:


 tasks.all{ task -> if (task.name.toLowerCase().contains("debug")) { task.dependsOn properCopy } } 

input, output dan rakitan tambahan


Tugas umum akan dipanggil setiap waktu. Jika Anda menentukan bahwa tugas yang didasarkan pada file A menghasilkan file B, maka gradle akan melewatkan tugas jika file-file ini tidak berubah. Dan gradle tidak memeriksa tanggal modifikasi file, tetapi isinya.


 task generateCode(type: Exec) { commandLine "generateCode.sh", "input.txt", "output.java" inputs.file "input.txt" output.file "output.java" } 

Demikian pula, Anda dapat menentukan folder, serta beberapa nilai: inputs.property(name, value) .


deskripsi tugas


Saat memanggil ./gradlew tasks --all tugas standar memiliki deskripsi yang indah dan entah bagaimana dikelompokkan. Untuk tugas Anda, ini ditambahkan dengan sangat sederhana:


 task hello { group "MyCustomGroup" description "Prints 'hello'" doLast{ print 'hello' } } 

task.enabled


Anda dapat "mematikan" tugas - maka dependensinya masih akan dipanggil, tetapi itu sendiri tidak akan.


 taskName.enabled false 

beberapa proyek (modul)


multi-proyek dibangun dalam dokumentasi


Di proyek utama, Anda dapat menempatkan beberapa modul lagi. Sebagai contoh, ini digunakan dalam proyek android - hampir tidak ada dalam proyek root, plugin android termasuk dalam subproyek. Jika Anda ingin menambahkan modul baru, Anda dapat menambahkan yang lain, dan di sana, misalnya, Anda juga dapat menghubungkan plugin android, tetapi gunakan pengaturan lain untuk itu.


Contoh lain: saat menerbitkan proyek menggunakan jitpack, proyek root menjelaskan dengan pengaturan apa untuk menerbitkan modul anak yang bahkan mungkin tidak mencurigai publikasi.


Modul anak ditentukan dalam settings.gradle:


 include 'name' 

Baca lebih lanjut tentang dependensi antar proyek di sini.


buildSrc


Jika build.gradle banyak kode dalam build.gradle atau digandakan, itu bisa dipindahkan ke modul terpisah. Kami membutuhkan folder dengan nama ajaib buildSrc , di mana Anda dapat menempatkan kode di groovy atau java. (baik, atau lebih tepatnya, di buildSrc/src/main/java/com/smth/ code, tes dapat ditambahkan ke buildSrc/src/test ). Jika Anda menginginkan sesuatu yang lain, misalnya, tulis tugas Anda di scala atau gunakan beberapa dependensi, maka langsung di buildSrc Anda perlu membuat build.gradle dan tentukan dependensi yang diperlukan di dalamnya / aktifkan plugin.


Sayangnya, dengan sebuah proyek di buildSrc IDE dapat buildSrc dengan petunjuk, di sana Anda harus menulis impor dan kelas / tugas dari sana build.gradle juga harus mengimpornya ke build.gradle biasa. import com.smth.Taskname tidak sulit, Anda hanya perlu mengingat ini dan tidak memikirkan mengapa tugas dari buildSrc tidak ditemukan).


Untuk alasan ini, mudah untuk terlebih dahulu menulis sesuatu yang bekerja langsung di build.gradle , dan baru kemudian mentransfer kode ke buildSrc .


Jenis tugas sendiri


Tugas ini diturunkan dari DefaultTask , di mana ada banyak, banyak bidang, metode, dan hal lainnya. Kode AbstractTask diwarisi dari DefaultTask.


Poin yang berguna:


  • alih-alih menambahkan inputs dan outputs secara manual outputs Anda dapat menggunakan bidang dan anotasi @Input, @OutputFile : @Input, @OutputFile , dll.
  • metode yang akan dijalankan saat tugas dijalankan: @TaskAction .
  • metode yang mudah digunakan seperti copy{from ... , into... } masih dapat dipanggil, tetapi Anda harus memanggilnya secara eksplisit untuk proyek: project.copy{...}

Ketika seseorang di build.gradle menulis untuk tugas kita


 taskName { ... //some code } 

metode configure(Closure) dipanggil pada tugas.


Saya tidak yakin apakah ini adalah pendekatan yang tepat, tetapi jika sebuah tugas memiliki beberapa bidang yang kondisi timbal baliknya sulit dikendalikan dengan pengambil-pengambil, maka tampaknya cukup mudah untuk mendefinisikan kembali metode sebagai berikut:


 override def configure(Closure closure){ def result = super().configure(closure) //    / - return result; } 

Dan bahkan jika Anda menulis


 taskName.fieldName value 

maka metode configure akan tetap dipanggil.


Plugin sendiri


Seperti tugas, Anda dapat menulis plugin sendiri, yang akan mengonfigurasi sesuatu atau membuat tugas. Misalnya, apa yang terjadi di android{...} sepenuhnya merupakan prestasi ilmu hitam Plug-in Android, yang selain itu menciptakan banyak tugas seperti aplikasi: assembleDevelopDebug untuk semua kemungkinan kombinasi rasa / tipe build / dimenstion. Tidak ada yang rumit dalam menulis plugin Anda, untuk pemahaman yang lebih baik Anda dapat melihat kode plugin lain.


Ada langkah ketiga - Anda dapat menempatkan kode tidak di buildSrc , tetapi menjadikannya proyek yang terpisah. Kemudian, menggunakan https://jitpack.io atau yang lainnya, publikasikan plugin dan sambungkan dengan yang lain.


Akhirnya


Contoh di atas mungkin termasuk kesalahan ketik dan ketidakakuratan. Tulis dalam catatan pribadi atau tandai dengan ctrl+enter - Saya akan memperbaikinya. Contoh spesifik diambil dari dokumentasi, dan lihat artikel ini sebagai sedikit daftar "cara melakukannya".

Source: https://habr.com/ru/post/id458046/


All Articles