Membuat aturan keep dari anotasi

Jetpack Keep memungkinkan Anda mendeklarasikan penggunaan refleksi dan Java Native Interface (JNI) dengan anotasi langsung dalam kode sumber Kotlin atau Java, bukan dalam file aturan keep terpisah. Plugin Jetpack Keep Gradle membaca anotasi ini pada waktu build dan membuat aturan keep yang diperlukan R8.

Jetpack Keep membantu pengoptimalan R8 tetap efektif seiring perubahan codebase Anda:

  • Aturan keep tetap berada di samping kode yang memerlukannya. Saat mengganti nama atau menghapus kode yang menggunakan refleksi, Anda mengupdate anotasi di tempat yang sama. Tidak ada file aturan terpisah yang perlu disinkronkan.

  • Aturan yang dihasilkan bersifat kondisional. R8 hanya mempertahankan target panggilan reflektif jika juga mempertahankan kode yang melakukan panggilan. Jika kode panggilan tidak digunakan dan R8 menghapusnya (sering terjadi pada fitur library opsional), R8 juga dapat menghapus target, sehingga aturan dari fitur yang tidak digunakan tidak akan menambah beban.

  • Lint menemukan refleksi untuk Anda. Library ini menyertakan pemeriksaan lint yang menandai panggilan reflektif yang tidak dianotasi, dan dapat menambahkan banyak anotasi secara otomatis.

Cara kerja Jetpack Keep

Pertimbangkan fungsi yang membuat instance class berdasarkan nama. Jika R8 tidak dapat mengetahui bahwa kode Anda menggunakan class, R8 akan menghapus konstruktor class, dan aplikasi akan error saat runtime. Untuk mencegah error, Anda dapat menambahkan aturan seperti berikut ke file aturan keep:

# Unconditional: R8 keeps this constructor even if it removes the reflection that invokes it.
-keep class com.example.ResourceLocatorImpl {
    <init>();
}

Dengan Jetpack Keep, Anda menganotasi fungsi yang melakukan refleksi:

// ResourceLocatorImpl isn't on this module's compile classpath, so both the
// annotation and the code refer to it by name.
@UsesReflectionToConstruct(
    className = "com.example.ResourceLocatorImpl",
    // Omitting parameterTypes keeps every constructor. An empty array keeps
    // only the no-argument constructor, which the code calls.
    parameterTypes = [],
)
fun loadResourceLocator(): ResourceLocator {
    val implClass = Class.forName("com.example.ResourceLocatorImpl")
    return implClass.getDeclaredConstructor().newInstance() as ResourceLocator
}

Pada waktu build, plugin Gradle akan membuat aturan keep untuk konstruktor. Tidak seperti aturan yang ditulis secara manual sebelumnya, aturan yang dihasilkan bersifat kondisional: R8 hanya mempertahankan konstruktor jika loadResourceLocator tetap ada di aplikasi yang dioptimalkan.

Persyaratan

Untuk menggunakan Jetpack Keep, project Anda memerlukan Plugin Android Gradle (AGP) 8.7 atau yang lebih baru.

Plugin Gradle mendukung jenis modul berikut:

Jenis modul Plugin yang diterapkan modul Penyiapan tambahan
Aplikasi Android com.android.application Tidak ada
Library Android com.android.library Tidak ada
Library Multiplatform Kotlin dengan target Android com.android.kotlin.multiplatform.library Tidak ada
Library JVM (Java atau Kotlin) java-library atau org.jetbrains.kotlin.jvm Mendaftarkan transformasi JAR

Menyiapkan Jetpack Keep

Untuk menggunakan Jetpack Keep, tambahkan library dan plugin Gradle ke setiap modul yang menggunakan refleksi atau JNI. Library menyediakan anotasi dan pemeriksaan lint, dan plugin mengubah anotasi menjadi aturan keep.

  1. Dalam file libs.versions.toml, tambahkan library dan plugin. Library dan plugin memiliki versi yang sama:

    [versions]
    # The library and the plugin ship together. Use one version for both so
    # that they stay in sync when you upgrade.
    annotationKeep = "1.0.0-alpha01"
    
    [libraries]
    androidx-annotation-keep = { group = "androidx.annotation.keep", name = "keep", version.ref = "annotationKeep" }
    
    [plugins]
    androidx-annotation-keep = { id = "androidx.annotation.keep", version.ref = "annotationKeep" }
    

    Gradle mendownload plugin dari repositori Maven Google, jadi pastikan repositori pluginManagement dalam file settings.gradle.kts Anda menyertakan google().

  2. Dalam file build.gradle.kts root, deklarasikan plugin bersama AGP tanpa menerapkannya:

    plugins {
        alias(libs.plugins.android.application) apply false
        // Other plugins.
    
        // The plugin relies on AGP classes that it doesn't bundle, so declare
        // it next to AGP. Declaring it here also gives every module the same
        // plugin version.
        alias(libs.plugins.androidx.annotation.keep) apply false
    }
    
  3. Dalam file build.gradle.kts setiap modul yang menggunakan refleksi atau JNI, terapkan plugin dan tambahkan dependensi library:

    plugins {
        alias(libs.plugins.android.application)
        // The plugin reads annotations only from this module's own code, so
        // apply it in every module that uses Jetpack Keep.
        alias(libs.plugins.androidx.annotation.keep)
    }
    
    dependencies {
        implementation(libs.androidx.annotation.keep)
    }
    
  4. Sinkronkan project Anda dengan file Gradle.

Untuk setiap varian build modul aplikasi Android, plugin mendaftarkan tugas <variant>ExtractKeepRules, seperti releaseExtractKeepRules, dan meneruskan aturan yang dihasilkan ke R8 untuk varian tersebut. Untuk modul library, plugin memaketkan aturan yang dihasilkan sebagai aturan keep konsumen dalam output library. Modul library JVM memerlukan penyiapan tambahan.

Menemukan refleksi dengan lint

Jetpack Keep menyertakan pemeriksaan lint berikut:

ReflectionWithoutKeepAnnotations
Menandai panggilan reflektif, seperti Class.forName, getDeclaredConstructor, getDeclaredMethod, dan getDeclaredField, yang tidak memiliki anotasi keep yang cocok.
MissingKeepAnnotationPlugin
Menandai modul yang bergantung pada androidx.annotation.keep:keep, tetapi tidak menerapkan plugin Gradle androidx.annotation.keep. Tanpa plugin, build Anda tidak akan membuat aturan keep dari anotasi.

Untuk menggunakan lint guna menganotasi modul Android, ikuti langkah-langkah berikut:

  1. Jalankan lint pada modul untuk menemukan panggilan reflektif yang memerlukan anotasi:

    ./gradlew :app:lint
    
  2. Terapkan perbaikan yang dapat dilakukan lint secara otomatis:

    ./gradlew :app:lintFix
    

    Lint dapat menambahkan anotasi secara otomatis saat dapat menentukan class dan anggota yang direfleksikan oleh kode.

  3. Tinjau setiap anotasi yang ditambahkan untuk mengonfirmasi bahwa anotasi tersebut cocok dengan fungsi kode Anda. Misalnya, pastikan jenis parameter cocok dengan konstruktor atau metode yang dipanggil kode Anda.

  4. Selesaikan temuan yang tersisa di Android Studio. Jika lint tidak dapat menentukan class target, perbaikan cepat akan menyisipkan anotasi dengan placeholder TODO untuk Anda selesaikan. Anda juga dapat menambahkan anotasi secara manual.

    Misalnya, fungsi berikut menerima nama class sebagai parameter, sehingga lint tidak dapat menentukan class mana yang dibuatnya. Perbaikan cepat menambahkan anotasi dengan placeholder:

    @UsesReflectionToConstruct(
        className = TODO(),
        parameterTypes = []
    )
    fun createInstance(className: String): Any =
        Class.forName(className).getDeclaredConstructor().newInstance()
    

    Ganti placeholder dengan class yang dibuat oleh kode Anda. Jika class tersedia pada waktu kompilasi, gunakan classConstant, bukan className. Di Kotlin, kode Anda tidak akan dikompilasi sampai Anda mengganti TODO().

  5. Periksa aturan keep yang dihasilkan plugin dari anotasi Anda sebelum menghapus aturan yang ada. Untuk modul aplikasi, jalankan tugas ekstraksi untuk varian rilis:

    ./gradlew :app:releaseExtractKeepRules
    

    Plugin menulis aturan ke app/build/generated/release/androidx.annotation.keep.rules.pro. Untuk modul library, lihat Memverifikasi aturan yang dihasilkan.

  6. Hapus aturan keep yang digantikan oleh anotasi baru dari file aturan keep Anda. Aturan juga dapat mencakup refleksi yang tidak ditandai oleh lint, seperti refleksi dalam modul lain atau dalam library, jadi periksa setiap aturan sebelum Anda menghapusnya:

    • Untuk aturan seluruh paket, seperti -keep class com.example.** { *; }, pastikan anotasi atau aturan lainnya mencakup semua refleksi pada class paket.
    • Untuk aturan yang mempertahankan class atau anggota tertentu, pastikan aturan tersebut sangat cocok dengan salah satu aturan yang dihasilkan, atau tidak ada refleksi lain yang bergantung padanya.
  7. Uji build rilis Anda.

Memberi anotasi pada kode Anda

Tambahkan anotasi Jetpack Keep ke kode yang melakukan refleksi: fungsi, konstruktor, kolom, atau class yang berisi panggilan reflektif. Anotasi menjelaskan target refleksi, dan aturan yang dihasilkan hanya mempertahankan target tersebut jika R8 mempertahankan kode yang dianotasi.

Pilih anotasi berdasarkan fungsi kode Anda:

Annotation Gunakan saat kode Anda
@UsesReflectionToConstruct Memanggil konstruktor melalui refleksi, misalnya dengan getDeclaredConstructor().newInstance().
@UsesReflectionToAccessMethod Memanggil metode melalui refleksi, misalnya dengan getMethod atau getDeclaredMethod.
@UsesReflectionToAccessField Membaca atau menulis kolom melalui refleksi, misalnya dengan getField atau getDeclaredField.
@UnconditionallyKeep Dipanggil dari luar kode Kotlin atau Java aplikasi Anda, misalnya dari kode native melalui JNI. Gunakan anotasi ini hanya jika Anda tidak dapat menggunakan anotasi @UsesReflection*, yang menghasilkan aturan bersyarat.

Semua anotasi @UsesReflection* mengikuti konvensi berikut:

  • Identifikasi class target dengan classConstant atau className. Jika class tersedia pada waktu kompilasi, gunakan classConstant. Compiler memeriksa referensi, dan pemfaktoran ulang IDE seperti penggantian nama akan memperbaruinya. Gunakan className hanya jika class tidak tersedia pada waktu kompilasi, seperti class dalam dependensi opsional. Kedua parameter ini saling terpisah.
  • Targetkan class yang paling spesifik. Aturan yang dihasilkan akan mempertahankan anggota yang cocok di class yang Anda tentukan dan di subclass atau implementasi antarmukanya. Makin umum class, makin banyak kode yang dipertahankan R8.
  • Tentukan jenis parameter untuk mempertahankan satu overload. Jika Anda tidak menetapkan parameterTypes atau parameterTypeNames, aturan akan mempertahankan semua konstruktor atau semua overload metode. Untuk hanya mempertahankan konstruktor atau metode tanpa argumen, teruskan array kosong.
  • Ulangi anotasi untuk beberapa target. Jika satu fungsi merefleksikan lebih dari satu class atau anggota, tambahkan satu anotasi untuk setiap target.

Membuat objek dengan refleksi

Gunakan @UsesReflectionToConstruct saat kode Anda membuat instance class melalui refleksi. Dalam contoh berikut, runner tugas membuat instance implementasi antarmuka StartupTask berdasarkan nama. Karena anotasi menentukan antarmuka, aturan yang dihasilkan akan mempertahankan konstruktor tanpa argumen dari setiap implementasi StartupTask, selama R8 mempertahankan execute:

interface StartupTask {
    fun run()
}

object TaskRunner {
    // The task class is known only at runtime, so target the interface that
    // every task implements.
    @UsesReflectionToConstruct(classConstant = StartupTask::class, parameterTypes = [])
    fun execute(className: String) {
        val task = Class.forName(className)
            .getDeclaredConstructor()
            .newInstance() as StartupTask
        task.run()
    }
}

Memanggil metode dengan refleksi

Gunakan @UsesReflectionToAccessMethod saat kode Anda memanggil metode melalui refleksi. Tetapkan methodName ke nama metode. Dalam contoh berikut, kode memanggil metode statis dalam dependensi opsional. Class ini tidak tersedia pada waktu kompilasi, sehingga anotasi menggunakan className, bukan classConstant:

object CrashReporting {
    @UsesReflectionToAccessMethod(
        className = "com.example.crashlib.CrashReporter",
        methodName = "log",
        // Omitting parameterTypes keeps every log overload. Keep only the one
        // that the code calls.
        parameterTypes = [String::class],
    )
    fun log(message: String) {
        val reporterClass = try {
            Class.forName("com.example.crashlib.CrashReporter")
        } catch (e: ClassNotFoundException) {
            // Crash reporting is optional, so skip it instead of failing.
            return
        }
        reporterClass.getMethod("log", String::class.java).invoke(null, message)
    }
}

Mengakses kolom dengan refleksi

Gunakan @UsesReflectionToAccessField saat kode Anda membaca atau menulis kolom melalui refleksi. Tetapkan fieldName ke nama kolom:

class UserProfileFetcher {
    // User doesn't expose internalId, so reading it requires reflection.
    @UsesReflectionToAccessField(classConstant = User::class, fieldName = "internalId")
    fun readInternalId(user: User): Any? {
        val field = User::class.java.getDeclaredField("internalId")
        field.isAccessible = true
        return field.get(user)
    }
}

Mempertahankan kode yang dipanggil dari luar aplikasi Anda

Gunakan @UnconditionallyKeep untuk kode yang dipanggil dari luar kode Kotlin atau Java aplikasi Anda, seperti metode yang dipanggil kode native melalui JNI. Beri anotasi pada elemen yang dipanggil, bukan kode yang memanggilnya:

class NativeBridge {
    // Only native code calls this method, through a JNI lookup by name that
    // R8 can't see. Keep the method and its name unconditionally.
    @UnconditionallyKeep
    fun onNativeEvent(message: String) {
        Log.d("NativeBridge", "Received from native code: $message")
    }

    // The default proguard-android-optimize.txt file already keeps native
    // method names, so this method doesn't need an annotation.
    external fun startNativeProcess()
}

Aturan yang dihasilkan akan mempertahankan metode yang dianotasi dan class yang memuatnya, dengan nama aslinya. Aturan ini tidak mempertahankan class lain yang dirujuk oleh tanda tangan metode. Jika kode native bergantung pada class tersebut, anotasikan juga, atau tambahkan aturan keep untuk class tersebut. Untuk mengetahui informasi selengkapnya tentang JNI dan R8, lihat Interaksi dengan kode native melalui JNI.

Secara default, @UnconditionallyKeep mempertahankan nama elemen. Jika pemanggil eksternal tidak bergantung pada nama, tetapkan shouldPreserveName = false agar R8 dapat mengganti nama elemen.

Memverifikasi aturan yang dibuat

Bagian ini menjelaskan cara memeriksa aturan yang dihasilkan untuk setiap jenis modul. Untuk modul aplikasi, plugin meneruskan aturan langsung ke R8. Untuk modul library, plugin mengemas aturan sebagai aturan keep konsumen dalam output library. Aplikasi yang bergantung pada library Anda akan menerapkan aturan ini secara otomatis saat menjalankan R8, meskipun aplikasi tersebut tidak menggunakan Jetpack Keep. Untuk informasi selengkapnya tentang aturan keep konsumen, lihat Pengoptimalan untuk penulis library.

Aplikasi Android

Untuk memeriksa aturan keep yang dihasilkan plugin untuk modul aplikasi, jalankan tugas ekstraksi untuk varian build:

./gradlew :app:releaseExtractKeepRules

Plugin menulis aturan untuk setiap varian ke app/build/generated/<variant>/androidx.annotation.keep.rules.pro. Komentar # context: sebelum setiap aturan mengidentifikasi kode yang dianotasi yang menghasilkannya.

Untuk memeriksa pengaruh aturan yang dihasilkan terhadap pengoptimalan bersama dengan aturan keep lainnya, gunakan R8 Configuration Analyzer.

Library Android

Modul library Android tidak memerlukan penyiapan tambahan. Saat Anda mem-build AAR, plugin akan menambahkan aturan yang dihasilkan ke file proguard.txt AAR, setelah aturan keep konsumen yang sudah ada di AAR. Plugin mendaftarkan tugas <variant>KeepRulesTransformAar untuk setiap varian build guna melakukan hal ini.

Untuk memverifikasi aturan, build AAR, misalnya dengan ./gradlew :mylibrary:assembleRelease, dan buka proguard.txt di AAR yang dihasilkan. Aturan yang dihasilkan akan muncul di bagian dengan header berikut:

#################################################################
#   Rules generated from androidx.annotation.keep annotations   #
#################################################################

Di macOS dan Linux, Anda juga dapat mencetak aturan dari command line:

unzip -p mylibrary/build/intermediates/aar/release/releaseKeepRulesTransformAar/mylibrary-release.aar proguard.txt

Library Multiplatform Kotlin

Modul library Multiplatform Kotlin dengan target Android juga tidak memerlukan penyiapan tambahan. Saat Anda mem-build AAR untuk target Android, plugin akan menambahkan aturan yang dihasilkan ke file proguard.txt AAR dengan cara yang sama seperti untuk library Android. Plugin mendaftarkan tugas androidMainKeepRulesTransformAar untuk melakukannya.

Untuk memverifikasi aturan, jalankan tugas tersebut dan buka proguard.txt di AAR yang dibuatnya. Di macOS dan Linux, Anda dapat mencetak aturan dari command line:

./gradlew :mylibrary:androidMainKeepRulesTransformAar
unzip -p mylibrary/build/intermediates/aar/androidMain/androidMainKeepRulesTransformAar/mylibrary.aar proguard.txt

Library JVM

Sebelum Anda dapat memverifikasi aturan untuk modul library JVM, konfigurasikan modul agar plugin menambahkan aturan yang dihasilkan ke salinan JAR-nya. Kemudian, jalankan tugas transformasi yang Anda daftarkan dan periksa file aturan dalam JAR yang dibuatnya. Misalnya, jika Anda menamai tugas keepRulesJar, Anda dapat mencetak aturan di macOS dan Linux dengan perintah berikut:

./gradlew :mylibrary:keepRulesJar
unzip -p mylibrary/build/intermediates/annotation-keep/keepRulesJar/mylibrary-keep-rules.jar \
    "META-INF/com.android.tools/*" "META-INF/proguard/*"

Mengonfigurasi library JVM

Untuk modul library JVM yang menghasilkan JAR, plugin tidak mengubah JAR secara otomatis. Sebagai gantinya, gunakan fungsi annotationKeep.registerJavaArchiveTransform untuk mendaftarkan tugas yang membuat salinan JAR dengan aturan yang dibuat, lalu publikasikan JAR tersebut. Tambahkan kode berikut ke file build.gradle.kts modul library:

plugins {
    id("java-library")
    alias(libs.plugins.jetbrains.kotlin.jvm)
    alias(libs.plugins.androidx.annotation.keep)
}

val jarTask = tasks.named<Jar>("jar")

// Apps run R8 on this library's code, so the generated rules must be inside
// the JAR. The plugin handles this automatically only for Android modules.
val keepRulesJarTask = annotationKeep.registerJavaArchiveTransform(
    taskName = "keepRulesJar",
    input = jarTask.flatMap { it.archiveFile },
    fileName = jarTask.flatMap { it.archiveFileName }.map { it.replace(".jar", "-keep-rules.jar") },
)

// Consumers of this library resolve apiElements and runtimeElements, so add
// the JAR that contains the generated rules to them.
configurations.configureEach {
    if (name == "apiElements" || name == "runtimeElements") {
        outgoing.artifact(keepRulesJarTask.flatMap { it.outputJar })
    }
}

dependencies {
    implementation(libs.androidx.annotation.keep)
}

Transformasi menambahkan aturan yang dihasilkan ke lokasi aturan R8 yang ditargetkan JAR, META-INF/com.android.tools/r8/proguard.txt. Jika JAR sudah berisi aturan di META-INF/com.android.tools/ atau META-INF/proguard/, transformasi akan menambahkan aturan yang dihasilkan ke file aturan yang ada. Untuk informasi selengkapnya tentang lokasi ini, lihat Mendukung berbagai versi R8.

Setelah mendaftarkan transformasi, verifikasi aturan di JAR.

Contoh: Memuat library add-on opsional

Library sering menggunakan refleksi untuk memuat add-on opsional. Misalnya, SDK analisis mungkin mengirimkan library inti dan add-on video. Add-on bergantung pada library inti, sehingga library inti tidak dapat merujuk ke class add-on secara langsung. Sebagai gantinya, library inti akan mencari class add-on berdasarkan nama saat runtime dan mengaktifkan analisis video hanya jika class tersebut ditemukan.

Karena library inti menggunakan class add-on hanya melalui refleksi, R8 dapat menghapus class atau konstruktornya dari build rilis aplikasi, yang membuat pencarian gagal. Kegagalan hanya terjadi di build rilis aplikasi yang menyertakan add-on, sehingga sulit dideteksi dalam pengujian.

Tanpa Jetpack Keep, add-on akan mengirimkan aturan keep konsumen untuk class-nya, seperti yang ditunjukkan dalam Refleksi untuk mendukung dependensi opsional:

# In the add-on's consumer keep rules file.
-keep class com.example.analytics.video.VideoEventTracker {
    <init>();
}

Aturan ini berada di library yang berbeda dengan pencarian yang memerlukannya, sehingga keduanya bisa tidak sinkron. Dengan Jetpack Keep, Anda dapat menganotasi pencarian di library inti:

// In the core library.
interface AnalyticsPlugin {
    fun start()
}

object AnalyticsManager {
    // The annotation and the lookup share this constant so that they can't
    // refer to different classes.
    private const val VIDEO_TRACKER_CLASS =
        "com.example.analytics.video.VideoEventTracker"

    @UsesReflectionToConstruct(
        className = VIDEO_TRACKER_CLASS,
        parameterTypes = [],
    )
    fun initialize() {
        val tracker = try {
            Class.forName(VIDEO_TRACKER_CLASS)
                .getDeclaredConstructor()
                .newInstance() as AnalyticsPlugin
        } catch (e: ClassNotFoundException) {
            // Apps that don't play video leave out the add-on, so a missing
            // class isn't an error.
            return
        }
        // This is an ordinary interface call, not a reflective one, so R8
        // keeps start() without an annotation.
        tracker.start()
    }
}

Anotasi mengikuti panduan berikut:

  • Beri anotasi pada kode yang melakukan refleksi. Anotasi ada di initialize, yang memanggil Class.forName, bukan di class add-on.
  • Pilih anotasi berdasarkan fungsi kode. Pencarian akan membuat instance class, sehingga kode menggunakan @UsesReflectionToConstruct.
  • Gunakan className untuk class yang tidak dapat Anda referensikan. Class add-on tidak ada di classpath kompilasi library inti, sehingga anotasi tidak dapat menggunakan classConstant.
  • Hanya pertahankan konstruktor yang dipanggil oleh kode. Pencarian memanggil konstruktor tanpa argumen, sehingga parameterTypes adalah array kosong.

Saat Anda mem-build AAR library inti, plugin akan menambahkan aturan yang mempertahankan VideoEventTracker dan konstruktor tanpa argumennya setiap kali R8 mempertahankan initialize. Aplikasi yang menggunakan SDK menerapkan aturan ini secara otomatis, meskipun tidak menggunakan Jetpack Keep, sehingga add-on tidak memerlukan aturannya sendiri. Dibandingkan dengan aturan add-on, pendekatan ini memiliki keuntungan berikut:

  • Aturan tetap berada di samping pencarian. Library inti memiliki pencarian dan aturan, sehingga Anda dapat memperbaruinya bersama-sama, bukan mengoordinasikan perubahan di dua library.
  • R8 masih dapat menghapus kode yang tidak digunakan. Jika aplikasi menyertakan add-on, tetapi tidak pernah memanggil initialize, aturan yang dihasilkan tidak akan berlaku, dan R8 dapat menghapus VideoEventTracker. Aturan add-on akan mempertahankannya di setiap aplikasi yang menyertakan add-on.
  • Lint menangkap pencarian yang tidak dianotasi. Jika library inti nantinya menambahkan pencarian reflektif lain tanpa anotasi, lint akan menandainya, sehingga Anda dapat memperbaikinya sebelum merilis library.

Untuk mengonfirmasi hasilnya, pastikan aturan yang dihasilkan muncul di file proguard.txt AAR, seperti yang dijelaskan dalam Library Android. Kemudian, uji build rilis aplikasi yang menyertakan add-on, karena di situlah aturan yang tidak ada akan merusak analisis video.

Batasan

Jetpack Keep belum mendeteksi refleksi yang menemukan class dan anggota berdasarkan anotasinya, atau membuat aturan keep untuknya. Fitur ini sedang direncanakan.

Sebelum itu, gunakan aturan keep untuk jenis refleksi ini. Misalnya, aturan berikut mempertahankan setiap anggota yang dianotasi dengan @SomeAnnotation di class yang dipertahankan R8:

-keepclassmembers class * {
    @com.example.annotation.SomeAnnotation <methods>;
    @com.example.annotation.SomeAnnotation <fields>;
}

Jika Jetpack Keep tidak berfungsi untuk kasus penggunaan Anda, atau jika Anda memiliki masukan lain, laporkan masalah.

Referensi lainnya