The plugin's on-device proof (Mob.Plugin.SelfTest), run by
mix mob.selftest and mob_ci for every activated plugin.
One real recognition, no UI, no camera, no permission: the test renders the
word LEFT in large block letters into a PNG under Mob.data_dir/0, calls
recognize_text/1 on it, waits for the native delivery and deletes the file.
{:vision, :text, text}wheretextreadsLEFT(case and whitespace ignored) passes. That answer only comes from the recognizer's success path: on iOS the NIF loaded the file into aCGImageandVNRecognizeTextRequest(Vision, accurate level) ran on it on a background queue; on Android the zig NIF calledMobVisionBridge.recognize_textthrough JNI (sonativeRegisterran and the bootstrap handed the bridge an Activity),InputImage.fromFilePathdecoded the file and ML Kit's bundled Latin recognizer read it. Both recognizers run fully on device and offline (Vision ships with iOS, the ML Kit model is in thetext-recognitionartifact, not a Play services download), so an iOS simulator and an Android emulator are expected to pass like a phone.- Any other text, including
"", is a failure: the pipeline ran but did not read a clean, high-contrast word. {:vision, :error, reason}is a failure:"no_activity"(Android: the bootstrap never calledsetActivity),"no_image"(the native side could not open the file the test just wrote) or the recognizer's own error message.{:error, :bridge_not_registered}from the NIF (Android: the bootstrap never calledMobVisionBridge.register(), or the method-ID lookup failed) is a failure; so is no answer within 15 s.- The host stub's
nif_not_loadedis a failure naming the NIF.
There is no skip: the plugin needs no hardware, no permission and no network, so every device can give the full answer.