Repository navigation
fix(ios): keep text recognition switch exhaustive under selective install - #23
Merged
Merged
Conversation
…tall TextRecognitionServiceFactory wrapped each `case` of `switch language` in its own `#if MLKIT_TEXT_RECOGNITION*` flag with no `default:`. Disabling any single language model compiled that case out while DomainTextRecognitionLanguage still declared all five, so the switch was no longer exhaustive and iOS failed to build with "switch must be exhaustive". Every partial selection broke; only all-five-enabled or all-five-disabled (where MLKIT_TEXT_RECOGNITION_ANY drops the whole file) compiled, which defeats the point of selective install. Move the `#if` guards inside each `case` body via a `makeOptions(for:)` helper returning nil for models excluded from the build. The switch now lists all five cases unconditionally, so it stays exhaustive under every flag combination and adding a language still fails the build until it is handled here — which a `default:` clause would have silently swallowed. Unavailable languages now throw a descriptive RuntimeError naming the configuration key to enable, matching the IllegalStateException Android already throws from its own factory, instead of crashing via fatalError. createTextRecognizer/create become throwing, so HybridTextRecognizer.init throws and its only call site in HybridVisionCameraMLKit uses `try`. Fixes #22
Records the fix under [Unreleased]; the version header gets stamped at release time. Describes the failure mode (non-exhaustive switch under any partial language selection) and the new behavior for languages excluded from the build.
This was referenced Aug 20, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related to #22 (intentionally not using a closing keyword — see Notes).
Summary
Text recognition failed to build on iOS as soon as any single language model
was disabled through the selective ML Kit install, which is the entire point
of that feature. Reported against 2.0.0 with an Expo prebuild config, but the
bare Podfile path produces identical flags and fails the same way.
Root cause
DomainTextRecognitionLanguagedeclares all five cases unconditionally, whileevery
caseinTextRecognitionServiceFactory.createTextRecognizerwasindividually wrapped in its own
#if MLKIT_TEXT_RECOGNITION*flag with nodefault:. Disabling a language compiled itscaseout while the enum stilldeclared it, so the switch was no longer exhaustive:
Only all-five-enabled compiled, or all-five-disabled (where
MLKIT_TEXT_RECOGNITION_ANYgoes unset and the whole file drops out). Everypartial selection — the feature's actual purpose — was broken.
This shipped because no iOS CI job compiles a partial config:
build-ios.ymlbuilds the example app, and
example/ios/Podfilepins all five totrue.The fix
The
#ifguards move inside eachcasebody, via amakeOptions(for:)helper that returns
nilfor models excluded from the build. The switch listsall five cases unconditionally, so it stays exhaustive under every flag
combination.
A language whose model was excluded now throws a descriptive error naming the
configuration key to enable, matching the
IllegalStateExceptionAndroidalready raises from its own factory.
createTextRecognizer/createbecomethrowing, so
HybridTextRecognizer.initthrows and its single call site inHybridVisionCameraMLKitusestry.Alternatives considered and rejected
default:+fatalError(suggested in the issue) compiles, and Swiftemits no unreachable-default warning when all five are enabled. Rejected
because it crashes the process where Android throws a catchable exception for
the same misconfiguration, and because it permanently disables exhaustiveness
checking — verified by simulating a sixth enum case: the
default:versioncompiles silently, this version fails the build.
Gating the enum cases (the issue's alternative) does not work.
TextRecognitionLanguage+toDomain.swiftmaps the Nitro-generatedTextRecognitionLanguage— C++-backed, all five cases, marked DO NOT MODIFY —so removing domain cases relocates the same error into the mapper. It also
would not surface at the JS/TS boundary, since that union is generated from the
Nitro spec and is independent of build flags.
Validation
Real
pod install+xcodebuildper config, reading the emittedSWIFT_ACTIVE_COMPILATION_CONDITIONSback from the generated xcconfig ratherthan trusting the Podfile (the podspec merges over all-
truedefaults and doesnot validate keys, so a typo would silently produce an all-enabled build).
developswitch must be exhaustiveat 31:7Rows 1 and 2 use an identical Podfile and identical emitted flags; the branch
is the only variable. Row 1 reproduces the reporter's error at the same file,
line, and column. Row 3 also confirms the podspec still pulls base
GoogleMLKit/TextRecognitionfor shared types whentextRecognition => false.Not covered: the runtime throw reaching JS. Low risk rather than unknown —
HybridVisionCameraMLKit.createTextRecognizeralready threw aRuntimeErrorfor the disabled-feature case before this change, so that propagation path is
pre-existing and exercised.
Notes
developchanges nothing. Note the fix commit body does contain one, whichwill auto-close iOS build fails with "switch must be exhaustive" when any text recognition language model is disabled #22 when it reaches
main— to be amended before release.complete set, so the enum will not grow.
[Unreleased]; version header stamped at release.