Explorar el Código

添加了闪光灯,重构了代码结构

Kevin hace 6 años
padre
commit
031a79d5d8

+ 72 - 0
android/src/main/java/info/geteasy/fqreader/DecodeHandler.java

@@ -0,0 +1,72 @@
+package info.geteasy.fqreader;
+
+import android.graphics.Rect;
+import android.hardware.Camera;
+import android.os.Handler;
+import android.os.Message;
+
+import java.util.List;
+
+import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.PluginRegistry;
+
+public class DecodeHandler extends Handler implements  Camera.PreviewCallback {
+    private Camera mCamera;
+    private DecodeThread mThread;
+    private EventChannel.EventSink eventSink;
+    DecodeHandler(Camera camera,
+                  List<String> scanType,
+                  Rect scanRect){
+        mCamera = camera;
+        Camera.Size size = mCamera.getParameters().getPreviewSize();
+        mThread = new DecodeThread(this,size,scanRect);
+        mThread.setFormats(scanType);
+        mThread.start();
+
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        super.handleMessage(msg);
+        switch (msg.what){
+            case 1://继续扫描
+                mCamera.setOneShotPreviewCallback(DecodeHandler.this);
+                break;
+            case 2: //停止扫描
+                if(eventSink != null)
+                    eventSink.success((String) msg.obj);
+                break;
+        }
+    }
+
+    @Override
+    public void onPreviewFrame(byte[] data, Camera camera) {
+        mThread.decode(data);
+    }
+
+    /**
+     * 释放资源
+     */
+    void release(){
+        mThread.release();
+    }
+    /**
+     * 注册通知事件
+     */
+    void registerEventChannel(PluginRegistry.Registrar registrar, long textureEntryId) {
+        new EventChannel(
+                registrar.messenger(), "fqreader/scanEvents" + textureEntryId)
+                .setStreamHandler(
+                        new EventChannel.StreamHandler() {
+                            @Override
+                            public void onListen(Object arguments, EventChannel.EventSink eventSink) {
+                                DecodeHandler.this.eventSink = eventSink;
+                            }
+
+                            @Override
+                            public void onCancel(Object arguments) {
+                                DecodeHandler.this.eventSink = null;
+                            }
+                        });
+    }
+}

+ 206 - 0
android/src/main/java/info/geteasy/fqreader/DecodeThread.java

@@ -0,0 +1,206 @@
+package info.geteasy.fqreader;
+
+import android.graphics.Rect;
+import android.hardware.Camera;
+import android.os.Handler;
+import android.os.Message;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.BinaryBitmap;
+import com.google.zxing.DecodeHintType;
+import com.google.zxing.MultiFormatReader;
+import com.google.zxing.NotFoundException;
+import com.google.zxing.PlanarYUVLuminanceSource;
+import com.google.zxing.Reader;
+import com.google.zxing.ReaderException;
+import com.google.zxing.Result;
+import com.google.zxing.aztec.AztecReader;
+import com.google.zxing.common.HybridBinarizer;
+import com.google.zxing.datamatrix.DataMatrixReader;
+import com.google.zxing.maxicode.MaxiCodeReader;
+import com.google.zxing.oned.CodaBarReader;
+import com.google.zxing.oned.Code128Reader;
+import com.google.zxing.oned.Code39Reader;
+import com.google.zxing.oned.Code93Reader;
+import com.google.zxing.oned.EAN13Reader;
+import com.google.zxing.oned.EAN8Reader;
+import com.google.zxing.oned.ITFReader;
+import com.google.zxing.oned.MultiFormatOneDReader;
+import com.google.zxing.pdf417.PDF417Reader;
+import com.google.zxing.qrcode.QRCodeReader;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+public class DecodeThread extends  Thread {
+    public boolean exit = false;
+    private Map<DecodeHintType, Object> mHints = new Hashtable<>();
+    private byte[] mImageBytes;;
+    private Rect mScanRect;
+    private Camera.Size mCameraSize;
+    private Handler mDecodeHandler;
+    private Reader[] mReaders;
+
+    public DecodeThread(
+                        Handler decodeHandler,
+                        Camera.Size cameraSize,
+                        Rect scanRect){
+        this.mScanRect = scanRect;
+        this.mCameraSize = cameraSize;
+        this.mDecodeHandler = decodeHandler;
+
+        //设置字符集为UTF-8
+        mHints.put(DecodeHintType.CHARACTER_SET, "utf-8");
+    }
+
+    public void decode(byte[] bytes){
+        synchronized (this){
+            this.notify();
+        }
+        this.mImageBytes = bytes;
+    }
+
+    @Override
+    public void run() {
+        synchronized (this) {
+            try {
+                this.wait();//等待开始
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+        while (!exit) {
+            try {
+                int width = mCameraSize.width;
+                int height = mCameraSize.height;
+
+                com.google.zxing.Result rawResult = null;
+                PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(mImageBytes,
+                        width, height,
+                        mScanRect.top,mScanRect.left,
+                        mScanRect.height(),mScanRect.width(),
+                        true);
+
+                BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
+                try {
+
+                    rawResult = decodeInternal(bitmap);
+                } catch (ReaderException re) {
+                    // continue
+                } catch (NullPointerException npe) {
+                    // This is terrible
+                } catch (ArrayIndexOutOfBoundsException aoe) {
+                    //
+                } finally {
+                    reset();
+                }
+//
+//                    if (rawResult == null) {
+//                        LuminanceSource invertedSource = source.invert();
+//                        bitmap = new BinaryBitmap(new HybridBinarizer(invertedSource));
+//                        try {
+//                            rawResult = multiFormatReader.decodeWithState(bitmap);
+//
+//                        } catch (NotFoundException e) {
+//                            // continue
+//                        } finally {
+//                            multiFormatReader.reset();
+//                        }
+//                    }
+
+                if (rawResult != null) {
+                    Message msg = new Message();
+                    msg.what = 2;
+                    msg.obj = rawResult.getText();
+                    this.mDecodeHandler.sendMessage(msg);
+                } else {
+                    Message msg = new Message();
+                    msg.what = 1;
+                    this.mDecodeHandler.sendMessage(msg);
+                }
+
+                synchronized (this) {
+                    this.wait();//等待下一次解码
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public void setFormats(List<String> formats){
+        ArrayList<Reader> readers = new ArrayList<>();
+        for(int i = 0;i< formats.size();i++){
+            String item = formats.get(i);
+            switch (item){
+                case "ScanType.CODABAR":
+                    readers.add(new CodaBarReader());
+                    break;
+                case "ScanType.QR_CODE":
+                    readers.add(new QRCodeReader());
+                    break;
+                case "ScanType.AZTEC":
+                    readers.add(new AztecReader());
+                    break;
+                case "ScanType.CODE_39":
+                    readers.add(new Code39Reader());
+                    break;
+                case "ScanType.CODE_93":
+                    readers.add(new Code93Reader());
+                    break;
+                case "ScanType.CODE_128":
+                    readers.add(new Code128Reader());
+                    break;
+                case "ScanType.EAN8":
+                    readers.add(new EAN8Reader());
+                    break;
+                case "ScanType.EAN13":
+                    readers.add(new EAN13Reader());
+                    break;
+                case "ScanType.ITF":
+                    readers.add(new ITFReader());
+                    break;
+                case "ScanType.DATA_MATRIX":
+                    readers.add(new DataMatrixReader());
+                    break;
+                case "ScanType.PDF_417":
+                    readers.add(new PDF417Reader());
+                    break;
+            }
+        }
+        this.mReaders = readers.toArray(new Reader[readers.size()]);
+
+    }
+
+    public  void release(){
+        synchronized (this) {
+            exit = true;
+            mImageBytes = null;
+            mReaders = null;
+            this.notify();//等待下一次解码
+        }
+    }
+
+    private void reset() {
+        if (mReaders != null) {
+            for (Reader reader : mReaders) {
+                reader.reset();
+            }
+        }
+    }
+
+    private Result decodeInternal(BinaryBitmap image) throws NotFoundException {
+        if (mReaders != null) {
+            for (Reader reader : mReaders) {
+                try {
+                    return reader.decode(image, mHints);
+                } catch (ReaderException re) {
+                    // continue
+                }
+            }
+        }
+        throw NotFoundException.getNotFoundInstance();
+    }
+}

+ 74 - 56
android/src/main/java/info/geteasy/fqreader/FqreaderPlugin.java

@@ -11,6 +11,7 @@ import android.hardware.camera2.CameraManager;
 import android.os.Build;
 
 import java.util.HashMap;
+import java.util.List;
 
 import io.flutter.plugin.common.MethodCall;
 import io.flutter.plugin.common.MethodChannel;
@@ -20,72 +21,89 @@ import io.flutter.plugin.common.PluginRegistry.Registrar;
 import io.flutter.view.FlutterView;
 import io.flutter.view.TextureRegistry;
 
-/** FqreaderPlugin */
+/**
+ * FqreaderPlugin
+ */
 public class FqreaderPlugin implements MethodCallHandler {
 
 
-  private FlutterView view;
-  private Activity activity;
-  private Registrar registrar;
+    private FlutterView view;
+    private Activity activity;
+    private Registrar registrar;
 
-  private ScanView scanView;
+    private ScanView scanView;
 
-  private FqreaderPlugin(Registrar registrar, FlutterView view, Activity activity) {
-    this.registrar = registrar;
-    this.view = view;
-    this.activity = activity;
-    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-      if (activity.checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
-        activity.requestPermissions(new String[]{Manifest.permission.CAMERA}, 1);
-      }
+    private FqreaderPlugin(Registrar registrar, FlutterView view, Activity activity) {
+        this.registrar = registrar;
+        this.view = view;
+        this.activity = activity;
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            if (activity.checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
+                activity.requestPermissions(new String[]{Manifest.permission.CAMERA}, 1);
+            }
+        }
     }
-  }
 
-  /** Plugin registration. */
-  public static void registerWith(Registrar registrar) {
-    final MethodChannel channel = new MethodChannel(registrar.messenger(), "fqreader");
+    /**
+     * Plugin registration.
+     */
+    public static void registerWith(Registrar registrar) {
+        final MethodChannel channel = new MethodChannel(registrar.messenger(), "fqreader");
 
-    channel.setMethodCallHandler(
-            new FqreaderPlugin(registrar, registrar.view(), registrar.activity()));
-  }
+        channel.setMethodCallHandler(
+                new FqreaderPlugin(registrar, registrar.view(), registrar.activity()));
+    }
 
-  @Override
-  public void onMethodCall(MethodCall call, Result result) {
-    switch (call.method){
-      case "initView":
-        if(scanView != null){
-          result.error("ScanView","Scan Already initialized",null);
-          return;
+    @Override
+    public void onMethodCall(MethodCall call, Result result) {
+        switch (call.method) {
+            case "initView":
+                if (scanView != null) {
+                    result.error("ScanView", "Scan Already initialized", null);
+                    return;
+                }
+                HashMap<String, Object> viewRectMap = call.argument("viewRect");
+                Rect viewRect = new Rect(
+                        (int) viewRectMap.get("left"),
+                        (int) viewRectMap.get("top"),
+                        (int) viewRectMap.get("right"),
+                        (int) viewRectMap.get("bottom")
+                );
+                HashMap<String, Object> scanRectMap = call.argument("scanRect");
+                Rect scanRect = new Rect(
+                        (int) scanRectMap.get("left"),
+                        (int) scanRectMap.get("top"),
+                        (int) scanRectMap.get("right"),
+                        (int) scanRectMap.get("bottom")
+                );
+                List<String> scanType = call.argument("scanType");
+                scanView = new ScanView(view, registrar,
+                        viewRect,
+                        scanRect,
+                        scanType,
+                        result);
+                break;
+            case "startScan":
+                scanView.startScan();
+                result.success(null);
+                break;
+            case "stopScan":
+                scanView.stopScan();
+                result.success(null);
+                break;
+            case "turnOn":
+                scanView.turnOn();
+                result.success(null);
+                break;
+            case "turnOff":
+                scanView.turnOff();
+                result.success(null);
+                break;
+            case "release":
+                scanView.release();
+                scanView = null;
+                break;
         }
-        HashMap<String,Object> viewRectMap = call.argument("viewRect");
-        Rect viewRect = new Rect(
-                (int)viewRectMap .get("left"),
-                (int)viewRectMap .get("top"),
-                (int)viewRectMap .get("right"),
-                (int)viewRectMap .get("bottom")
-        );
-        HashMap<String,Object> scanRectMap = call.argument("scanRect");
-        Rect scanRect = new Rect(
-                (int)scanRectMap.get("left"),
-                (int)scanRectMap.get("top"),
-                (int)scanRectMap.get("right"),
-                (int)scanRectMap.get("bottom")
-        );
-        scanView = new ScanView(view,registrar,viewRect,scanRect,result);
-        break;
-      case "startScan":
-        scanView.startScan();
-        result.success(null);
-        break;
-      case "stopScan":
-        scanView.stopScan();
-        result.success(null);
-        break;
-      case "release":
-        scanView.release();
-        scanView = null;
-        break;
     }
-  }
 
 }

+ 89 - 145
android/src/main/java/info/geteasy/fqreader/ScanView.java

@@ -19,8 +19,13 @@ import com.google.zxing.ReaderException;
 import com.google.zxing.common.HybridBinarizer;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
 
 import io.flutter.plugin.common.EventChannel;
 import io.flutter.plugin.common.MethodChannel;
@@ -32,173 +37,112 @@ import static android.content.ContentValues.TAG;
 import static java.security.AccessController.getContext;
 
 
-public class ScanView implements Camera.PreviewCallback,Runnable{
-    private FlutterView view;
+public class ScanView {
     private TextureRegistry.SurfaceTextureEntry textureEntry;
-    private Camera camera;
-    private Rect scanRect;
-    private PluginRegistry.Registrar registrar;
-    private MultiFormatReader multiFormatReader;
-    private EventChannel.EventSink eventSink;
-    private Handler resultHandler;
-    private Thread decodeThread;
-    private byte[] imageBytes;
-
-    ScanView(FlutterView view,PluginRegistry.Registrar registrar,Rect viewRect,Rect scanRect, MethodChannel.Result result){
-        this.view = view;
-        this.registrar = registrar;
-        this.scanRect = scanRect;
+    private Camera mCamera;
+    private DecodeHandler mDecodeHandler;
+
+    ScanView(FlutterView view,
+             PluginRegistry.Registrar registrar,
+             Rect viewRect,
+             Rect scanRect,
+             List<String> scanType,
+             MethodChannel.Result result) {
         try {
-            multiFormatReader = new MultiFormatReader();
-            this.textureEntry = view.createSurfaceTexture();
-            camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
-            Camera.Parameters param = camera.getParameters();
-            List<Camera.Size> sizes = param.getSupportedPreviewSizes();
+            mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
+            Camera.Parameters param = mCamera.getParameters();
             param.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
             param.setRotation(90);
-            double viewRatio = viewRect.width() * 1.0 / viewRect.height();
-            Camera.Size currentSize = sizes.get(0);
-            double currentRatio = currentSize.width * 1.0 / currentSize.height;
-            for(int i =1;i<sizes.size();i++){
-                Camera.Size  item= sizes.get(i);
-                double diffOld = Math.abs(currentRatio - viewRatio);
-                double diffNew = Math.abs(item.width * 1.0 / item.height - viewRatio);
-                if(diffOld < diffNew){
-                    currentSize = item;
-                    currentRatio = item.width * 1.0 / item.height;
-                }else if(diffOld == diffNew){
-                    if(item.height > currentSize.height){
-                        currentSize = item;
-                    }
-                }
-            }
 
-            param.setPreviewSize(currentSize.width,currentSize.height); // 设置预览图像大小
-            camera.setParameters(param);
-            camera.setDisplayOrientation(90);
-            camera.setPreviewTexture(textureEntry.surfaceTexture());
+            // 选择最合适的预览图像大小
+            Camera.Size currentSize = matchSize(viewRect, param);
+            // 设置预览图像大小
+            param.setPreviewSize(currentSize.width, currentSize.height);
+            mCamera.setParameters(param);
+            mCamera.setDisplayOrientation(90); //旋转90度,变成竖屏
+
+            //链接flutter纹理
+            this.textureEntry = view.createSurfaceTexture();
+            mCamera.setPreviewTexture(textureEntry.surfaceTexture());
+
+            //返回纹理ID
             result.success(textureEntry.id());
-            registerEventChannel();
-            decodeThread = new Thread(this);
-            decodeThread.start();
-            resultHandler = new Handler() {
-                @Override
-                public void handleMessage(Message msg) {
-                    super.handleMessage(msg);
-                    switch (msg.what){
-                        case 1://继续扫描
-                            camera.setOneShotPreviewCallback(ScanView.this);
-                            break;
-                        case 2: //停止扫描
-                            eventSink.success((String) msg.obj);
-                            break;
-                    }
-                }
-            };
 
-        }catch (Exception e) {
-            result.error("ScanView init",e.getMessage(),null);
+            mDecodeHandler = new DecodeHandler(mCamera, scanType, scanRect);
+            mDecodeHandler.registerEventChannel(registrar, textureEntry.id());
+
+        } catch (Exception e) {
+            result.error("ScanView init", e.getMessage(), null);
         }
     }
 
-    void startScan(){
-        camera.setOneShotPreviewCallback(this);
-        camera.startPreview();;
+    void startScan() {
+        mCamera.setOneShotPreviewCallback(mDecodeHandler);
+        mCamera.startPreview();
+        ;
     }
 
-    void stopScan(){
-        camera.setOneShotPreviewCallback(null);
-        camera.stopPreview();
+    void stopScan() {
+        mCamera.setOneShotPreviewCallback(null);
+        mCamera.stopPreview();
     }
 
-    void release(){
-        camera.release();
-        camera = null;
-        textureEntry.release();
-        textureEntry = null;
+    /**
+     * 开灯
+     */
+    void turnOn() {
+        Camera.Parameters param = mCamera.getParameters();
+        param.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
+        mCamera.setParameters(param);
     }
 
-    private void registerEventChannel() {
-        new EventChannel(
-                registrar.messenger(), "fqreader/qrcodeEvents" + textureEntry.id())
-                .setStreamHandler(
-                        new EventChannel.StreamHandler() {
-                            @Override
-                            public void onListen(Object arguments, EventChannel.EventSink eventSink) {
-                                ScanView.this.eventSink = eventSink;
-                            }
-
-                            @Override
-                            public void onCancel(Object arguments) {
-                                ScanView.this.eventSink = null;
-                            }
-                        });
+    /**
+     * 关灯
+     */
+    void turnOff() {
+        Camera.Parameters param = mCamera.getParameters();
+        param.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
+        mCamera.setParameters(param);
     }
 
-    @Override
-    public void onPreviewFrame(byte[] bytes, Camera camera) {
-        synchronized (this){
-            this.imageBytes = bytes;
-            this.notify();
-        }
+    void release() {
+        mCamera.release();
+        mCamera = null;
+        textureEntry.release();
+        textureEntry = null;
+        mDecodeHandler.release();
     }
 
-
-    @Override
-    public void run() {
-        while (true) {
-            try {
-                synchronized (this) {
-                    this.wait();
-                }
-                Camera.Parameters parameters = camera.getParameters();
-                Camera.Size size = parameters.getPreviewSize();
-                int width = size.width;
-                int height = size.height;
-
-
-                com.google.zxing.Result rawResult = null;
-                PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(imageBytes, width, height, scanRect.top, scanRect.left, scanRect.height(), scanRect.width(), false);
-
-                BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
-                try {
-                    rawResult = multiFormatReader.decode(bitmap);
-                } catch (ReaderException re) {
-                    // continue
-                } catch (NullPointerException npe) {
-                    // This is terrible
-                } catch (ArrayIndexOutOfBoundsException aoe) {
-
-                } finally {
-                    multiFormatReader.reset();
-                }
-//
-//                    if (rawResult == null) {
-//                        LuminanceSource invertedSource = source.invert();
-//                        bitmap = new BinaryBitmap(new HybridBinarizer(invertedSource));
-//                        try {
-//                            rawResult = multiFormatReader.decodeWithState(bitmap);
-//
-//                        } catch (NotFoundException e) {
-//                            // continue
-//                        } finally {
-//                            multiFormatReader.reset();
-//                        }
-//                    }
-
-                if (rawResult != null) {
-                    Message msg = new Message();
-                    msg.what = 2;
-                    msg.obj = rawResult.getText();
-                    this.resultHandler.sendMessage(msg);
-                } else {
-                    Message msg = new Message();
-                    msg.what = 1;
-                    this.resultHandler.sendMessage(msg);
+    /**
+     * 选择最合适的预览图片大小
+     *
+     * @param viewRect
+     * @param param
+     * @return
+     */
+    private Camera.Size matchSize(Rect viewRect, Camera.Parameters param) {
+        List<Camera.Size> sizes = param.getSupportedPreviewSizes();
+
+        double viewRatio = viewRect.width() * 1.0 / viewRect.height(); // 获取控件比例
+        Camera.Size currentSize = sizes.get(0);
+        double currentRatio = currentSize.width * 1.0 / currentSize.height; //获取第一个预览大小的比例
+
+        for (int i = 1; i < sizes.size(); i++) {
+            Camera.Size item = sizes.get(i);
+            double diffOld = Math.abs(currentRatio - viewRatio); //与控件比例的差异 旧
+            double diffNew = Math.abs(item.width * 1.0 / item.height - viewRatio);  //与控件比例的差异 新
+
+            if (diffOld < diffNew) { //如果旧的小于新的则使用新的预览大小
+                currentSize = item;
+                currentRatio = item.width * 1.0 / item.height;
+            } else if (diffOld == diffNew) {
+                if (item.height > currentSize.height) { //如果一样且新的像素大于旧的,则用新的
+                    currentSize = item;
                 }
-            } catch (InterruptedException e) {
-                e.printStackTrace();
             }
         }
+        return currentSize;
     }
+
+
 }

+ 56 - 17
example/lib/main.dart

@@ -14,24 +14,26 @@ class MyApp extends StatefulWidget {
 }
 
 class _MyAppState extends State<MyApp> {
+  GlobalKey<ScanViewState> scanView;
 
   @override
   void initState() {
     super.initState();
+    scanView = GlobalKey<ScanViewState>();
   }
 
   @override
   Widget build(BuildContext context) {
-
     return new MaterialApp(
-      home: Builder(builder: (context){
+      home: Builder(builder: (context) {
         ScreenUtil.getInstance().init(context);
 
         double bodyHeight = (ScreenUtil.screenHeight - ScreenUtil.appBarHeight);
-        Rect viewRect = Rect.fromLTRB(0, 60, ScreenUtil.screenWidth, ScreenUtil.screenHeight);
-        Rect scanRect= Rect.fromLTWH(
+        Rect viewRect = Rect.fromLTRB(
+            0, ScreenUtil.appBarHeight, ScreenUtil.screenWidth, ScreenUtil.screenHeight);
+        Rect scanRect = Rect.fromLTWH(
             ScreenUtil.screenWidth * 0.1,
-            (bodyHeight - ScreenUtil.screenWidth * 0.8) / 2,
+            (bodyHeight - bodyHeight * 0.8) / 2 + 60,
             ScreenUtil.screenWidth * 0.8,
             ScreenUtil.screenWidth * 0.8);
         return new Scaffold(
@@ -40,31 +42,68 @@ class _MyAppState extends State<MyApp> {
           ),
           body: Stack(
             children: <Widget>[
-              ScanView(onScan: (value){
-                showWeuiSuccessToast(
-                    context: context,
-                    message:Text("扫描成功:" + value)
-                );
-              },viewRect: viewRect,scanRect:scanRect),
+              ScanView(
+                  key: scanView,
+                  continuityScan: true,
+                  scanType: [
+                    ScanType.QR_CODE,
+                    ScanType.CODABAR,
+                    ScanType.CODE_39,
+                    ScanType.CODE_93,
+                    ScanType.CODE_128,
+                    ScanType.EAN8,
+                    ScanType.EAN13
+                  ],
+                  onScan: (value) async {
+                    showWeuiSuccessToast(
+                        context: context, message: Text("扫描成功:" + value),closeDuration:Duration(milliseconds: 500));
+                    return true;
+                  },
+                  viewRect: viewRect,
+                  scanRect: scanRect),
               Positioned(
                 top: 0.0,
                 left: 0.0,
-                child:FlatButton(child: Text("启动扫描"),color: Colors.red,onPressed: ()=>Fqreader.startScan(),),
+                child: FlatButton(
+                  child: Text("启动扫描"),
+                  color: Colors.red,
+                  onPressed: () => scanView.currentState.startScan(),
+                ),
               ),
               Positioned(
                 top: 0.0,
                 left: 80.0,
-                child:FlatButton(child: Text("暂停扫描"),color: Colors.red,onPressed: ()=>Fqreader.stopScan(),),
+                child: FlatButton(
+                  child: Text("暂停扫描"),
+                  color: Colors.red,
+                  onPressed: () => scanView.currentState.stopScan(),
+                ),
+              ),
+              Positioned(
+                top: 0.0,
+                left: 160.0,
+                child: FlatButton(
+                  child: Text("开灯"),
+                  color: Colors.red,
+                  onPressed: () => scanView.currentState.turnOn(),
+                ),
+              ),
+              Positioned(
+                top: 0.0,
+                left: 240.0,
+                child: FlatButton(
+                  child: Text("关灯"),
+                  color: Colors.red,
+                  onPressed: () => scanView.currentState.turnOff(),
+                ),
               ),
               Positioned(
-                top: scanRect.top,
+                top: scanRect.top - 60,
                 left: scanRect.left,
                 child: Container(
                   width: scanRect.width,
                   height: scanRect.height,
-                  decoration: BoxDecoration(
-                      border: Border.all()
-                  ),
+                  decoration: BoxDecoration(border: Border.all()),
                 ),
               )
             ],

+ 172 - 10
lib/fqreader.dart

@@ -7,11 +7,24 @@ import 'dart:ui' as ui;
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 
-class Fqreader {
+
+typedef ScanEvent = Future<bool> Function(String value);
+
+class _Fqreader {
   static const MethodChannel _channel =
   const MethodChannel('fqreader');
 
-  static Future<int> initView({@required Rect viewRect,@required Rect scanRect,double devicePixelRatio}) async {
+  static Future<int> initView({
+      @required Rect viewRect,
+      @required Rect scanRect,
+      @required List<ScanType> scanType,
+      double devicePixelRatio
+  }) async {
+    var scanStr = new List<String>();
+    scanType.forEach((item){
+      scanStr.add(item.toString());
+    });
+
     final int textureId = await _channel.invokeMethod('initView',{
       "viewRect":{
         "left":(viewRect.left * devicePixelRatio).toInt(),
@@ -24,26 +37,76 @@ class Fqreader {
         "top":(scanRect.top* devicePixelRatio).toInt(),
         "right":(scanRect.right* devicePixelRatio).toInt(),
         "bottom":(scanRect.bottom* devicePixelRatio).toInt(),
-      }
+      },
+      "scanType": scanStr
     });
     return textureId;
   }
-  static Future<String> startScan() async{
+  static Future startScan() async{
     await _channel.invokeMethod('startScan');
   }
 
   static Future stopScan() async{
     await _channel.invokeMethod('stopScan');
   }
+  static Future turnOn() async{
+    await _channel.invokeMethod("turnOn");
+  }
+  static Future turnOff() async{
+    await _channel.invokeMethod("turnOff");
+  }
+  static Future release() async{
+    await _channel.invokeMethod("release");
+  }
 }
 
 
 class ScanView extends StatefulWidget{
-  final ValueChanged<String> onScan;
+  /**
+   * 扫描事件
+   */
+  final ScanEvent onScan;
+
+  /**
+   * 扫描区域大小
+   */
   final Rect scanRect;
+
+  /**
+   * ScanView控件大小
+   */
   final Rect viewRect;
 
-  const ScanView({this.onScan,@required this.viewRect,@required this.scanRect});
+  /**
+   * 是否立即扫描
+   */
+  final bool autoScan;
+
+  /**
+   * 是否连续扫描
+   */
+  final bool continuityScan;
+
+  /**
+   * 连续扫描间隔
+   */
+  final Duration scanInterval;
+
+  /**
+   *  扫描的条码类型
+   */
+  final List<ScanType> scanType;
+
+  const ScanView({
+      Key key,
+      this.onScan,
+      @required this.viewRect,
+      @required this.scanRect,
+      this.scanType = const [ScanType.QR_CODE],
+      this.autoScan = true,
+      this.continuityScan = false,
+      this.scanInterval = const Duration(milliseconds:500)})
+    : super(key:key);
 
   @override
   State<StatefulWidget> createState() =>ScanViewState();
@@ -51,16 +114,25 @@ class ScanView extends StatefulWidget{
 
 class ScanViewState extends State<ScanView>{
   int _textureId;
+  StreamSubscription _readySubscription;
   @override
   void initState() {
     // TODO: implement initState
     super.initState();
     MediaQueryData mediaQuery = MediaQueryData.fromWindow(ui.window);
-    Fqreader.initView(viewRect: widget.viewRect,scanRect:widget.scanRect,devicePixelRatio:mediaQuery.devicePixelRatio).then((textureId){
+    _Fqreader.initView(
+        viewRect: widget.viewRect,
+        scanRect:widget.scanRect,
+        devicePixelRatio:mediaQuery.devicePixelRatio,
+        scanType: widget.scanType
+    ).then((textureId){
       setState(() {
         _textureId = textureId;
       });
-      new EventChannel('fqreader/qrcodeEvents$_textureId')
+      if(widget.autoScan){
+        _Fqreader.startScan();
+      }
+      _readySubscription = new EventChannel('fqreader/scanEvents$_textureId')
           .receiveBroadcastStream()
           .listen(_listener);
     });
@@ -73,12 +145,102 @@ class ScanViewState extends State<ScanView>{
         : new Container();
   }
 
-  Future<String> startScan() async{
+  @override
+  void dispose(){
+    super.dispose();
+    _readySubscription.cancel();
+    _Fqreader.release();
+  }
+
+  /**
+   * 开始扫描
+   */
+  Future startScan() async{
+    await _Fqreader.startScan();
+  }
 
+  /**
+   * 暂停扫描
+   */
+  Future stopScan() async{
+    await _Fqreader.stopScan();
+  }
+  /**
+   * 开灯
+   */
+  Future turnOn() async{
+    await _Fqreader.turnOn();
+  }
+  /**
+   * 关灯
+   */
+  Future turnOff() async{
+    await _Fqreader.turnOff();
   }
 
   void _listener(dynamic value) {
     if(widget != null)
-      widget.onScan(value);
+      {
+        if(!widget.continuityScan) //是否连续扫描
+          {
+            _Fqreader.stopScan();
+          }
+        widget.onScan(value).then((result){
+          if(widget.continuityScan && result){
+            Future.delayed(widget.scanInterval,(){
+              _Fqreader.startScan();
+            });
+          }else{
+            _Fqreader.stopScan();
+          }
+        });
+      }
   }
+}
+
+enum ScanType{
+  /**
+   *  普通二维码
+   */
+  QR_CODE,
+  /**
+   *  二维码 主要用于航空。比如坐飞机行李箱上贴的便签
+   */
+  AZTEC,
+  /**
+   * 条形码
+   */
+  CODABAR,
+  /**
+   * CODE 39 条形码
+   */
+  CODE_39,
+  /**
+   * CODE 92 条形码
+   */
+  CODE_93,
+  /**
+   *  CODE 128 条形码
+   */
+  CODE_128,
+  /**
+   * 商品用条形码 EAN8
+   */
+  EAN8,
+  /**
+   * 商品用条形码 EAN13
+   */
+  EAN13,
+  /**
+   * 全球贸易货号。主要用于运输方面的条形码
+   */
+  ITF,
+  /**
+   * 一种二维码
+   */
+  DATA_MATRIX,
+  /**
+   * PDF417条码是一种高密度、高信息含量的便携式数据文件
+   */
+  PDF_417
 }