Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
762a559
Implement camera switching for Android
ikbendewilliam Dec 7, 2021
c42e65a
Add method canChangeCamera
ikbendewilliam Dec 8, 2021
22d7372
Switch camera on iOS
herre Dec 9, 2021
7e5e25e
Fix build issue
ikbendewilliam Dec 9, 2021
dd764a8
Merge pull request #1 from ikbendewilliam/feature/can-switch-camera
ikbendewilliam Dec 9, 2021
8f5c69a
Fixed PR Comments
ikbendewilliam Dec 28, 2021
4ff1eee
Enable pause & resume on continuous scanning mode in iOS
rwillemsandroid Apr 21, 2022
4aca0cd
Merge pull request #2 from rwillemsandroid/feature/pause-resume-in-co…
ikbendewilliam Apr 21, 2022
c734a89
Update kotlin version
ikbendewilliam Jul 17, 2023
dfbd6ea
Flutter update
ikbendewilliam Oct 26, 2023
8a8f02d
renamed to icapps
jorre127 Nov 25, 2024
328f777
update android version
jorre127 Nov 25, 2024
6b44afb
fix android
jorre127 Nov 25, 2024
8bf93a3
fix ios
jorre127 Nov 25, 2024
b0eb637
updated changelog
jorre127 Nov 25, 2024
af1e57d
dart format
jorre127 Nov 25, 2024
d0830fa
updated version
jorre127 Nov 25, 2024
636425b
updated platform interface version
jorre127 Nov 25, 2024
351b145
Merge pull request #4 from jorre127/feature/android-update
jorre127 Nov 25, 2024
39cb4f2
publishing fix
jorre127 Nov 25, 2024
9e5c5ed
further rename
jorre127 Nov 25, 2024
69cb061
further rename to icapps
jorre127 Nov 25, 2024
c6e1a86
Merge pull request #5 from jorre127/feature/android-update
jorre127 Nov 25, 2024
35d7e48
added namespace
jorre127 Jun 27, 2025
bacfdab
Merge pull request #6 from icapps/feature/add-namespace
jorre127 Jun 27, 2025
546b9d0
Update dependencies
jorre127 Nov 5, 2025
fcb0c88
update plugin
jorre127 Nov 5, 2025
fb83485
updated package so it's 16kb compatible
jorre127 Nov 5, 2025
7ce6669
updated change log
jorre127 Nov 5, 2025
7b16b04
Merge pull request #7 from icapps/feature/update-dependencies
jorre127 Nov 6, 2025
f6791a3
possible fix for crash
jorre127 Nov 6, 2025
cfc959c
add import
jorre127 Nov 6, 2025
735b62b
update version
jorre127 Nov 6, 2025
b6025f9
Merge pull request #8 from icapps/feature/update-dependencies
jorre127 Nov 6, 2025
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
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Contributing to fast_barcode_scanner
Contributing to icapps_fast_barcode_scanner

Contributions are welcome by submitting a PR for to be reviewed.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Packages

### fast_barcode_scanner:
### icapps_fast_barcode_scanner:
code for the cross-platform facing plugin, used to display a camera view within Flutter applications

[![pub package](https://img.shields.io/pub/v/fast_barcode_scanner.svg)](https://pub.dartlang.org/packages/fast_barcode_scanner)
Expand Down
22 changes: 22 additions & 0 deletions fast_barcode_scanner/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@

## 1.5.1

- Fix crashes on android

## 1.5.0

- Updated to be 16KB compatible

## 1.4.1

- Added namespace for android

## 1.4.0

- Further rename to icapps_fast_barcode_scanner

## 1.3.0

- Forked to icapps_fast_barcode_scanner
- fix 'Type mismatch: inferred type is Activity? but Context was expected'

## 1.1.4

- Fixes `pauseDetector` on iOS
Expand Down
4 changes: 2 additions & 2 deletions fast_barcode_scanner/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ A fast barcode scanner using **MLKit** (and **CameraX**) on Android and **AVFoun
## Installation
Add the following line to your **pubspec.yaml**:
```yaml
fast_barcode_scanner: ^1.1.0
icapps_fast_barcode_scanner: ^1.1.0
```
### iOS
Add the `NSCameraUsageDescription` key to your `ios/Runner/Info.plist`, like so:
Expand All @@ -30,7 +30,7 @@ minSdkVersion 21
The barcode scanner consists of two main classes `CameraController` and `BarcodeCamera`.
A full example looks like this:
```dart
import 'package:fast_barcode_scanner/fast_barcode_scanner.dart';
import 'package:icapps_fast_barcode_scanner/icapps_fast_barcode_scanner.dart';

class MyScannerScreen extends StatelessWidget {
@override
Expand Down
13 changes: 7 additions & 6 deletions fast_barcode_scanner/android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
group 'com.jhoogstraat.fast_barcode_scanner'
group 'com.icapps.icapps_fast_barcode_scanner'
version '1.0-SNAPSHOT'

buildscript {
ext.kotlin_version = '1.3.50'
ext.kotlin_version = '1.9.24'
repositories {
google()
mavenCentral()
}

dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.android.tools.build:gradle:8.5.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Expand All @@ -25,7 +25,8 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

android {
compileSdkVersion 31
namespace 'com.icapps.icapps_fast_barcode_scanner'
compileSdkVersion 34

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
Expand Down Expand Up @@ -53,8 +54,8 @@ android {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

def camerax_version = "1.1.0-alpha10"
def mlkit_version = "17.0.0"
def camerax_version = "1.4.0"
def mlkit_version = "17.3.0"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
2 changes: 1 addition & 1 deletion fast_barcode_scanner/android/settings.gradle
Original file line number Diff line number Diff line change
@@ -1 +1 @@
rootProject.name = 'fast_barcode_scanner'
rootProject.name = 'icapps_fast_barcode_scanner'
2 changes: 1 addition & 1 deletion fast_barcode_scanner/android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jhoogstraat.fast_barcode_scanner">
package="com.icapps.icapps_fast_barcode_scanner">
<uses-feature android:name="android.hardware.camera.any" />
<uses-permission android:name="android.permission.CAMERA"/>
</manifest>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.jhoogstraat.fast_barcode_scanner
package com.icapps.icapps_fast_barcode_scanner

import android.Manifest
import android.app.Activity
Expand All @@ -13,7 +13,7 @@ import androidx.core.util.Consumer
import androidx.lifecycle.LifecycleOwner
import com.google.android.gms.tasks.OnFailureListener
import com.google.android.gms.tasks.OnSuccessListener
import com.google.mlkit.vision.barcode.Barcode
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.barcode.BarcodeScannerOptions

import io.flutter.plugin.common.MethodChannel.Result
Expand All @@ -23,7 +23,7 @@ import java.util.ArrayList
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

data class CameraConfig(val formats: IntArray, val mode: DetectionMode, val resolution: Resolution, val framerate: Framerate, val position: CameraPosition)
data class CameraConfig(val formats: IntArray, val mode: DetectionMode, val resolution: Resolution, val framerate: Framerate, var position: CameraPosition)

class BarcodeReader(private val flutterTextureEntry: TextureRegistry.SurfaceTextureEntry, private val listener: (List<Barcode>) -> Unit) : RequestPermissionsResultListener {
/* Android Lifecycle */
Expand Down Expand Up @@ -100,10 +100,32 @@ class BarcodeReader(private val flutterTextureEntry: TextureRegistry.SurfaceText
}

fun toggleTorch(result: Result) {
if (!isInitialized) return
if (!isInitialized || activity == null) return
camera.cameraControl.enableTorch(camera.cameraInfo.torchState.value != TorchState.ON).addListener(Runnable {
result.success(camera.cameraInfo.torchState.value == TorchState.ON)
}, ContextCompat.getMainExecutor(activity))
}, ContextCompat.getMainExecutor(activity!!))
}

fun canChangeCamera(result: Result) {
try {
val cameraProviderFuture = ProcessCameraProvider.getInstance(activity!!)
cameraProviderFuture.addListener(Runnable {
val cameraProviderForChangeCamera = cameraProviderFuture.get()
val hasFrontCamera = cameraProviderForChangeCamera.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA)
val hasBackCamera = cameraProviderForChangeCamera.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA)
result.success(hasFrontCamera && hasBackCamera)
}, ContextCompat.getMainExecutor(activity!!))
} catch (exc: Exception) {
result.success(false)
}
}

fun changeCamera(position: String, result: Result) {
cameraConfig.position = when (position) {
"front" -> CameraPosition.front
else -> CameraPosition.back
}
initCamera()
}

private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
Expand Down Expand Up @@ -148,12 +170,8 @@ class BarcodeReader(private val flutterTextureEntry: TextureRegistry.SurfaceText
// Select camera
val selectorBuilder = CameraSelector.Builder()
when (cameraConfig.position) {
CameraPosition.front -> {
selectorBuilder.requireLensFacing(CameraSelector.LENS_FACING_FRONT)
}
CameraPosition.back -> {
selectorBuilder.requireLensFacing(CameraSelector.LENS_FACING_BACK)
}
CameraPosition.front -> selectorBuilder.requireLensFacing(CameraSelector.LENS_FACING_FRONT)
CameraPosition.back -> selectorBuilder.requireLensFacing(CameraSelector.LENS_FACING_BACK)
}
cameraSelector = selectorBuilder.build()

Expand Down Expand Up @@ -211,7 +229,7 @@ class BarcodeReader(private val flutterTextureEntry: TextureRegistry.SurfaceText
}

companion object {
private const val TAG = "fast_barcode_scanner"
private const val TAG = "icapps_fast_barcode_scanner"
private const val REQUEST_CODE_PERMISSIONS = 10
private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package com.icapps.icapps_fast_barcode_scanner


import androidx.annotation.NonNull
import android.app.Activity
import androidx.camera.core.CameraSelector
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat

import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding

import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry

/** FastBarcodeScannerPlugin */
class FastBarcodeScannerPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, PluginRegistry.RequestPermissionsResultListener {
private lateinit var channel : MethodChannel
private var reader: BarcodeReader? = null

private var pluginBinding: FlutterPlugin.FlutterPluginBinding? = null
private var activity: Activity? = null


override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
this.pluginBinding = flutterPluginBinding
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.icapps/icapps_fast_barcode_scanner")
}

override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
this.pluginBinding = null
}

// https://flutter.dev/docs/development/packages-and-plugins/plugin-api-migration#uiactivity-plugin
// https://github.com/flutter/plugins/blob/master/packages/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
this.activity = binding.activity
binding.addRequestPermissionsResultListener(this)
channel.setMethodCallHandler(this)
}

override fun onDetachedFromActivity() {
channel.setMethodCallHandler(null)
reader?.detachFromActivity()
this.activity = null
}

override fun onDetachedFromActivityForConfigChanges() {
onDetachedFromActivity()
}

override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
onAttachedToActivity(binding)
}

override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
): Boolean {
return reader?.onRequestPermissionsResult(requestCode, permissions, grantResults) ?: false
}

override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
@Suppress("UNCHECKED_CAST")
when (call.method) {
"start" -> {
if (activity == null) {
result.error("0", "Activity not connected!", null)
return
}

pluginBinding?.let { binding ->
if (reader == null) {
reader =
BarcodeReader(binding.textureRegistry.createSurfaceTexture()) { barcodes ->
barcodes.firstOrNull()?.also { barcode ->
channel.invokeMethod(
"read",
listOf(barcodeStringMap[barcode.format], barcode.rawValue)
)
}
}
reader!!.attachToActivity(activity!!)
}

// Start the reader *inside* the null-safe block
reader!!.start(call.arguments as HashMap<String, Any>, result)

} ?: run {
// This runs if pluginBinding is null
result.error("1", "Plugin not attached to an engine.", null)
}
reader!!.start(call.arguments as HashMap<String, Any>, result)
}
"stop" -> reader?.stop(result)
"pause" -> reader?.stop(result)
"resume" -> reader?.resume(result)
"toggleTorch" -> reader?.toggleTorch(result)
"canChangeCamera" -> {
if (activity == null) {
result.error("0", "Activity not connected!", null)
return
}
try {
val cameraProviderFuture = ProcessCameraProvider.getInstance(activity!!)
cameraProviderFuture.addListener({
val cameraProviderForChangeCamera = cameraProviderFuture.get()
val hasFrontCamera =
cameraProviderForChangeCamera.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA)
val hasBackCamera =
cameraProviderForChangeCamera.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA)
result.success(hasFrontCamera && hasBackCamera)
}, ContextCompat.getMainExecutor(activity!!))
} catch (exc: Exception) {
result.success(false)
}
}
"changeCamera" -> reader?.changeCamera(call.arguments as String, result)
else -> result.notImplemented()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.jhoogstraat.fast_barcode_scanner
package com.icapps.icapps_fast_barcode_scanner

import androidx.camera.core.ExperimentalGetImage
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import com.google.android.gms.tasks.OnFailureListener
import com.google.android.gms.tasks.OnSuccessListener
import com.google.mlkit.vision.barcode.Barcode
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.common.InputImage
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.jhoogstraat.fast_barcode_scanner
package com.icapps.icapps_fast_barcode_scanner

import android.util.Size
import com.google.mlkit.vision.barcode.Barcode
import com.google.mlkit.vision.barcode.common.Barcode

enum class Framerate {
fps30, fps60, fps120, fps240;
Expand Down
Loading