Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/ExampleApp/app/screens/BarcodeScanningScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { AppStackScreenProps } from "../navigators"
import { Text, Icon, ImageSelector, Screen } from "../components"
import { useTypedNavigation } from "../navigators/useTypedNavigation"

import RNMLKitBarcodeScanningModule from "@infinitered/react-native-mlkit-barcode-scanning"
import RNMLKitBarcodeScanningModule from "@infinitered/react-native-mlkit-barcode-scanning"
import type { BarcodeScannerResult } from "@infinitered/react-native-mlkit-barcode-scanning"
import { UseExampleImageStatus, SelectedImage } from "../utils/useExampleImage"

Expand Down Expand Up @@ -60,6 +60,7 @@ export const BarcodeScanningScreen: FC<BarcodeScanningScreenProps> = observer(
if (!image?.uri) return
setIsScanning(true)
try {
// await RNMLKitBarcodeScanningModule.initialize()
const scanResult = await RNMLKitBarcodeScanningModule.process(image.uri)
setResult(scanResult)
setStatus("done")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ if (useManagedAndroidSdkVersions) {
ext.safeExtGet = { prop, fallback ->
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}

// Ensures backward compatibility
ext.getKotlinVersion = {
if (ext.has("kotlinVersion")) {
ext.kotlinVersion()
} else {
ext.safeExtGet("kotlinVersion", "1.8.10")
}
}
}
project.android {
compileSdkVersion safeExtGet("compileSdkVersion", 36)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import android.net.Uri
import com.google.mlkit.vision.common.InputImage
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.BarcodeScanner
import expo.modules.kotlin.AppContext
import kotlinx.coroutines.CompletableDeferred
import red.infinite.reactnativemlkit.core.RNMLKitImage
import red.infinite.reactnativemlkit.barcodescanning.RNMLKitBarcodeScannerResult

// private var options: RNMLKitBarcodeScannerOptions
class RNMLKitBarcodeScanner() {

private var barcodeScanner: BarcodeScanner? = BarcodeScanning.getClient()

suspend fun detectInImage(imagePath: String, appContext: AppContext): Result<RNMLKitBarcodeScannerResult> {
val result = CompletableDeferred<Result<RNMLKitBarcodeScannerResult>>()

try {
if(appContext.reactContext == null) {
val exception = Exception("RNMLKitBarcodeScanner: React Context is null")
result.complete(Result.failure(exception))
return result.await()
}

var image: InputImage = RNMLKitImage(Uri.parse(imagePath), appContext.reactContext!!).image

barcodeScanner?.process(image)?.addOnSuccessListener { barcodes ->
val expoBarcodes = RNMLKitBarcodeScannerResult(barcodes, imagePath)
result.complete(Result.success(expoBarcodes))
}?.addOnFailureListener { e ->
result.complete(Result.failure(e))
}
} catch (e: Exception) {
result.complete(Result.failure(e))
}
return result.await()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package red.infinite.reactnativemlkit.barcodescanning

import expo.modules.kotlin.records.Record
import expo.modules.kotlin.records.Field
import com.google.mlkit.vision.barcode.common.Barcode
import red.infinite.reactnativemlkit.core.RNMLKitRect

data class RNMLKitBarcodeScannerResultRecord(
@Field var barcodes: List<RNMLKitBarcode> = mutableListOf(),
@Field var imagePath: String
) : Record

class RNMLKitBarcodeScannerResult(private val barcodes: List<Barcode>, private val imagePath: String) {
val record: RNMLKitBarcodeScannerResultRecord
get() = RNMLKitBarcodeScannerResultRecord(
barcodes = barcodes.map { barcode ->
RNMLKitBarcode().apply {
//frame = RNMLKitRect.fromRect(barcode.boundingBox ?? RNMLKitRect.zero())
rawValue = barcode.rawValue
displayValue = barcode.displayValue
}
},
imagePath = imagePath
)
}

data class RNMLKitBarcode(
@Field var frame: RNMLKitRect = RNMLKitRect.zero(),
@Field var rawValue: String? = null,
@Field var displayValue: String? = null
) : Record
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
package red.infinite.reactnativemlkit
package red.infinite.reactnativemlkit.barcodescanning

import RNMLKitBarcodeScanner

import android.net.Uri

import expo.modules.kotlin.Promise
import expo.modules.kotlin.exception.CodedException
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
import java.net.URL
import kotlinx.coroutines.runBlocking
import red.infinite.reactnativemlkit.core.RNMLKitModule

class RNMLKitBarcodeScanningModule : Module() {
class RNMLKitBarcodeScanningModule : RNMLKitModule("RNMLKitBarcodeScanning") {
private var barcodeScanner: RNMLKitBarcodeScanner? = null
// Each module class must implement the definition function. The definition consists of components
// that describes the module's functionality and behavior.
// See https://docs.expo.dev/modules/module-api for more details about available components.
Expand All @@ -14,37 +22,38 @@ class RNMLKitBarcodeScanningModule : Module() {
// The module will be accessible from `requireNativeModule('RNMLKitBarcodeScanning')` in JavaScript.
Name("RNMLKitBarcodeScanning")

// Defines constant property on the module.
Constant("PI") {
Math.PI
}

// Defines event names that the module can send to JavaScript.
Events("onChange")

// Defines a JavaScript synchronous function that runs the native code on the JavaScript thread.
Function("hello") {
"Hello world! 👋"
// options: RNMLKitFaceDetectorOptionsRecord,
AsyncFunction("initialize") { promise: Promise ->
log.d("initialize: Initializing Barcode Scanner")
barcodeScanner = RNMLKitBarcodeScanner()
log.d("initialize: Initializing Barcode Scanner")
promise.resolve(null)
}

// Defines a JavaScript function that always returns a Promise and whose native code
// is by default dispatched on the different thread than the JavaScript runtime runs on.
AsyncFunction("setValueAsync") { value: String ->
// Send an event to JavaScript.
sendEvent("onChange", mapOf(
"value" to value
))
}
AsyncFunction("process") { imagePath: String, promise: Promise ->
val imageUri = Uri.parse(imagePath)

runBlocking suspend@{
val barcodeScanner = barcodeScanner
if (barcodeScanner == null) {
handleException(promise, message = "Barcode Scanner not initialized")
return@suspend
}
try {
var result =
barcodeScanner.detectInImage(imagePath, appContext).getOrElse {
handleException(promise, it)
throw it
}
promise.resolve(result.record)
} catch (e: Exception) {
handleException(promise, e)
}

// Enables the module to be used as a native view. Definition components that are accepted as part of
// the view definition: Prop, Events.
View(RNMLKitBarcodeScanningView::class) {
// Defines a setter for the `url` prop.
Prop("url") { view: RNMLKitBarcodeScanningView, url: URL ->
view.webView.loadUrl(url.toString())
}
// Defines an event that the view can send to JavaScript.
Events("onLoad")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
"modules": ["RNMLKitBarcodeScanningModule"]
},
"android": {
"modules": ["red.infinite.reactnativemlkit.RNMLKitBarcodeScanningModule"]
"modules": ["red.infinite.reactnativemlkit.barcodescanning.RNMLKitBarcodeScanningModule"]
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { NativeModule, requireNativeModule } from 'expo';
import { NativeModule, requireNativeModule } from "expo";

import { BarcodeScannerResult } from './RNMLKitBarcodeScanning.types';
import { BarcodeScannerResult } from "./RNMLKitBarcodeScanning.types";

declare class RNMLKitBarcodeScanningModule extends NativeModule {
initialize(): Promise<void>;
process(imagePath: string): Promise<BarcodeScannerResult>;
}

// This call loads the native module object from the JSI.
export default requireNativeModule<RNMLKitBarcodeScanningModule>('RNMLKitBarcodeScanning');
export default requireNativeModule<RNMLKitBarcodeScanningModule>("RNMLKitBarcodeScanning");