Skip to content

Commit 4504953

Browse files
committed
fix(android): restore compile-time selective install for text recognition and barcode scanning
The v2 hardening PR fixed a real compile failure by making com.google.mlkit:text-recognition and com.google.mlkit:barcode-scanning unconditional dependencies, defeating the library's selective-install purpose: a consumer who only wants barcode scanning still got the full text-recognition SDK bundled, and vice versa. Root cause: Kotlin has no #if-equivalent preprocessor. Six Kotlin files (TextRecognitionServiceFactory/MLKitTextRecognitionService/MLKitTextAdapter and their barcode equivalents) import concrete MLKit types at file scope, so they fail to compile whenever the corresponding artifact is missing from the classpath - regardless of whether the runtime feature flag ever lets that code execute. iOS never had this problem since its Swift equivalents use #if MLKIT_TEXT_RECOGNITION_ANY / #if MLKIT_BARCODE_SCANNING, which genuinely elides the guarded code (and its imports) at compile time. Fixed by giving Kotlin the same guarantee via Gradle conditional source sets instead of reflection (MLKit's real client APIs return async Task<T> objects with listener callbacks, which would need a java.lang.reflect.Proxy to invoke reflectively - fragile under R8 and adds reflection overhead to code that runs every camera frame): - Moved the 6 MLKit-coupled files into textRecognitionEnabled/ barcodeScanningEnabled source sets (content unchanged, path only). - Added tiny stub factories in textRecognitionDisabled/ barcodeScanningDisabled that throw if ever reached (they aren't - HybridVisionCameraMLKit already gates construction before this point), existing purely so the always-compiled Hybrid* classes have something to compile against. - android/build.gradle picks the enabled/disabled source dir per flag, and re-gates the two base MLKit SDKs behind their flags again. - Added com.google.mlkit:vision-common as an explicit, always-on dependency: three files (ProcessedImage, ImagePreprocessor, HybridFrameSpec+toProcessedImage) use its InputImage type unconditionally for the shared image-preprocessing pipeline. This isn't a version bump - it's already resolved transitively today at the same 17.3.0. - Updated the README caveat that documented this exact limitation, since it's no longer true. Verified locally (not just "it compiles"): with barcodeScanning:false, com.google.mlkit:barcode-scanning is fully absent from the resolved debugRuntimeClasspath; with textRecognition and all 4 language variants false, com.google.mlkit:text-recognition is fully absent. Full yarn test suite passes (93/93).
1 parent 050c005 commit 4504953

10 files changed

Lines changed: 49 additions & 12 deletions

File tree

‎README.md‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,11 @@ OCR languages you do not need to reduce binary size. Configuration keys for
8282
post-v2 roadmap features remain reserved and disabled; enabling one does not
8383
provide a public JS/Nitro API in v2.
8484

85-
On Android, the Latin OCR and barcode base SDKs remain compile-time
86-
dependencies even when their feature flags are disabled because v2's native
87-
implementation references their API types. Those flags control runtime
88-
availability; the four optional OCR language modules are still omitted when
89-
disabled.
85+
Both `textRecognition` and `barcodeScanning` are fully optional at compile
86+
time on both platforms: disabling one removes its native SDK from the build
87+
entirely instead of only gating it at runtime, so consumers who only need
88+
barcode scanning (or only text recognition) do not pay for the other's
89+
dependencies or binary size.
9090

9191
### Android (Gradle)
9292

‎android/build.gradle‎

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,9 @@ android {
166166
java.srcDirs += [
167167
"generated/java",
168168
"generated/jni",
169-
"../nitrogen/generated/android/kotlin/com/margelo/nitro/visioncameramlkit"
169+
"../nitrogen/generated/android/kotlin/com/margelo/nitro/visioncameramlkit",
170+
anyTextRecognition ? "src/textRecognitionEnabled/java" : "src/textRecognitionDisabled/java",
171+
mlkitConfig.barcodeScanning ? "src/barcodeScanningEnabled/java" : "src/barcodeScanningDisabled/java",
170172
]
171173
}
172174
}
@@ -188,14 +190,19 @@ dependencies {
188190
implementation "androidx.exifinterface:exifinterface:1.3.7"
189191

190192
// ===== GoogleMLKit Vision =====
191-
// Base SDKs for the two v2 features are compile-time dependencies because
192-
// their public types are referenced by unconditional Kotlin sources. Feature
193-
// flags still control runtime availability; optional OCR language models stay
194-
// selective so consumers can trim those larger model artifacts.
193+
// vision-common is always present: it's a small shared-types artifact (InputImage,
194+
// etc.) used by the image-preprocessing pipeline regardless of which MLKit feature
195+
// is enabled, and carries no OCR/barcode model weights. Every feature-specific SDK
196+
// below stays properly gated behind its own flag and its own conditional Kotlin
197+
// source set (see sourceSets above), so enabling only one feature (e.g. barcode
198+
// scanning) does not pull in or compile against the others.
199+
implementation "com.google.mlkit:vision-common:17.3.0"
195200

196201
// Text recognition v2
197202
// https://developers.google.com/ml-kit/vision/text-recognition/v2/android
198-
implementation "com.google.mlkit:text-recognition:16.0.1"
203+
if (anyTextRecognition) {
204+
implementation "com.google.mlkit:text-recognition:16.0.1"
205+
}
199206
if (mlkitConfig.textRecognitionChinese) {
200207
implementation "com.google.mlkit:text-recognition-chinese:16.0.1"
201208
}
@@ -250,7 +257,9 @@ dependencies {
250257

251258
// Barcode scanning
252259
// https://developers.google.com/ml-kit/vision/barcode-scanning/android
253-
implementation "com.google.mlkit:barcode-scanning:17.3.0"
260+
if (mlkitConfig.barcodeScanning) {
261+
implementation "com.google.mlkit:barcode-scanning:17.3.0"
262+
}
254263

255264
// Image labeling (Base Model) -> Custom models will be added soon
256265
// https://developers.google.com/ml-kit/vision/image-labeling/android
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.visioncameramlkit.infrastructure.mlkit.factories
2+
3+
import com.visioncameramlkit.domain.models.BarcodeScanningOptions
4+
import com.visioncameramlkit.domain.models.BarcodeScanningResult
5+
import com.visioncameramlkit.domain.services.IRecognitionService
6+
7+
object BarcodeScanningServiceFactory {
8+
fun create(options: BarcodeScanningOptions = BarcodeScanningOptions()): IRecognitionService<BarcodeScanningResult> {
9+
throw IllegalStateException(
10+
"Barcode scanning is not enabled in this build. Enable barcodeScanning in your MLKit " +
11+
"configuration to use this feature.",
12+
)
13+
}
14+
}

android/src/main/java/com/visioncameramlkit/infrastructure/mlkit/MLKitBarcodeScanningService.kt renamed to android/src/barcodeScanningEnabled/java/com/visioncameramlkit/infrastructure/mlkit/MLKitBarcodeScanningService.kt

File renamed without changes.

android/src/main/java/com/visioncameramlkit/infrastructure/mlkit/adapters/MLKitBarcodeAdapter.kt renamed to android/src/barcodeScanningEnabled/java/com/visioncameramlkit/infrastructure/mlkit/adapters/MLKitBarcodeAdapter.kt

File renamed without changes.

android/src/main/java/com/visioncameramlkit/infrastructure/mlkit/factories/BarcodeScanningServiceFactory.kt renamed to android/src/barcodeScanningEnabled/java/com/visioncameramlkit/infrastructure/mlkit/factories/BarcodeScanningServiceFactory.kt

File renamed without changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.visioncameramlkit.infrastructure.mlkit.factories
2+
3+
import com.visioncameramlkit.domain.models.TextRecognitionLanguage
4+
import com.visioncameramlkit.domain.models.TextRecognitionResult
5+
import com.visioncameramlkit.domain.services.IRecognitionService
6+
7+
object TextRecognitionServiceFactory {
8+
fun create(language: TextRecognitionLanguage = TextRecognitionLanguage.LATIN): IRecognitionService<TextRecognitionResult> {
9+
throw IllegalStateException(
10+
"Text recognition is not enabled in this build. Enable textRecognition (or a language " +
11+
"variant) in your MLKit configuration to use this feature.",
12+
)
13+
}
14+
}

android/src/main/java/com/visioncameramlkit/infrastructure/mlkit/MLKitTextRecognitionService.kt renamed to android/src/textRecognitionEnabled/java/com/visioncameramlkit/infrastructure/mlkit/MLKitTextRecognitionService.kt

File renamed without changes.

android/src/main/java/com/visioncameramlkit/infrastructure/mlkit/adapters/MLKitTextAdapter.kt renamed to android/src/textRecognitionEnabled/java/com/visioncameramlkit/infrastructure/mlkit/adapters/MLKitTextAdapter.kt

File renamed without changes.

android/src/main/java/com/visioncameramlkit/infrastructure/mlkit/factories/TextRecognitionServiceFactory.kt renamed to android/src/textRecognitionEnabled/java/com/visioncameramlkit/infrastructure/mlkit/factories/TextRecognitionServiceFactory.kt

File renamed without changes.

0 commit comments

Comments
 (0)