-
Notifications
You must be signed in to change notification settings - Fork 6
extractTextFromImage fails with file:// URIs on Android 10+ (FileUriExposedException) #17
Description
Description
extractTextFromImage() throws a generic "err" error when passed file paths from react-native-vision-camera on Android 10+. This is due to Android's scoped storage restrictions preventing file:// URIs from being used with InputImage.fromFilePath().
Environment
- Package version:
expo-text-extractor@0.1.2 - Platform: Android 10+ (API 29+)
- Camera library:
react-native-vision-camera(returns raw file system paths) - Expo SDK: 54
Steps to Reproduce
- Capture photo using
react-native-vision-camera:
const photoData = await cameraRef.current.takePhoto();
// photoData.path = "/data/user/0/com.example.app/cache/photo.jpg"- Pass the path to
extractTextFromImage:
const textBlocks = await extractTextFromImage(photoData.path);- Error thrown:
CodedException("err", ...)
Expected Behavior
Text extraction should work with raw file system paths from camera libraries that don't use content URIs.
Actual Behavior
Function fails with generic "err" error. Logs show:
Text recognition failed - ML Kit error {
"errorCode": "ERR_CODED",
"errorMessage": "err",
"errorName": "Error"
}
Root Cause Analysis
Current native implementation (ExpoTextExtractorModule.kt):
val uri = if (uriString.startsWith("content://")) {
Uri.parse(uriString)
} else {
val file = File(uriString)
Uri.fromFile(file) // Creates file:// URI
}
val inputImage = InputImage.fromFilePath(context, uri) // ❌ Fails on Android 10+Problem: According to the ML Kit InputImage documentation, fromFilePath(Context context, Uri imageUri) expects a proper content URI or an accessible file URI. On Android 10+ with scoped storage, file:// URIs created from Uri.fromFile() throw FileUriExposedException when passed to this method.
Why it works in the demo:
The demo uses expo-image-picker, which returns properly formatted content:// URIs that Android's ContentResolver can handle. Apps using other camera libraries (like react-native-vision-camera) that return raw file system paths will fail.
Suggested Fix
Use InputImage.fromBitmap() for file paths instead:
AsyncFunction("extractTextFromImage") { uriString: String, promise: Promise ->
try {
val context = appContext.reactContext!!
val inputImage = if (uriString.startsWith("content://")) {
// Handle content URIs (from expo-image-picker)
val uri = Uri.parse(uriString)
InputImage.fromFilePath(context, uri)
} else {
// Handle raw file paths (from react-native-vision-camera, etc.)
val file = File(uriString)
if (!file.exists()) {
throw Exception("File not found: $uriString")
}
// Use fromBitmap instead of fromFilePath to avoid FileUriExposedException
val bitmap = BitmapFactory.decodeFile(uriString)
if (bitmap == null) {
throw Exception("Failed to decode image file: $uriString")
}
InputImage.fromBitmap(bitmap, 0)
}
val recognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS)
recognizer.process(inputImage)
.addOnSuccessListener { visionText ->
val recognizedTexts = visionText.textBlocks.map { it.text }
promise.resolve(recognizedTexts)
}
.addOnFailureListener { error ->
// Include actual error message for debugging
promise.reject(
CodedException(
"ERR_TEXT_RECOGNITION",
error.message ?: "Text recognition failed",
error
)
)
}
} catch (error: Exception) {
promise.reject(
CodedException(
"ERR_UNKNOWN",
error.message ?: "Unknown error",
error
)
)
}
}Additional Improvement
Update error handling to return the actual error message instead of generic "err":
.addOnFailureListener { error ->
promise.reject(
CodedException(
"ERR_TEXT_RECOGNITION",
error.message ?: "Text recognition failed",
error
)
)
}Currently returns just CodedException("err", error) which loses the actual error information.
Current Workaround
For apps affected by this issue, we've had to disable post-capture OCR on Android:
if (Platform.OS === 'android') {
// Skip broken expo-text-extractor, show manual entry instead
return false;
}Impact
This affects any app using:
- ✅ Works:
expo-image-picker(returnscontent://URIs) - ❌ Fails:
react-native-vision-camera(returns file system paths) - ❌ Fails: Any direct file system image access
- ❌ Fails: Android 10+ with scoped storage enabled
References
- InputImage API Reference
- InputImage.fromBitmap() documentation
- InputImage.fromFilePath() documentation
- Android FileUriExposedException documentation
- Android scoped storage restrictions (API 29+)