使用 Google Play Services – Vision 掃描 QRCode

李昀峻 2019/12/27 19:31:46
1553

 

前言:

當我們使用Xamarin.Andriod 要掃描QRCode, 可以使用Google Play Services – Vision

 

需做以下步驟

  • Android Support Library v7 AppCompat
  • Xamarin Android Support v4
  • Google Play Services – Vision

 

安裝NuGet套件

步驟一: Android Support Library v7 AppCompat

 

步驟二: Xamarin Android Support v4

 

步驟三: Google Play Services – Vision

 

 

 

這次要做的是第一頁有一個掃描圖示, 案下去圖示到第二頁開啟照相機, 掃描完成後帶值回第一頁。

第一頁:

axml:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:app="http://schemas.android.com/apk/res-auto"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent">

  <LinearLayout

                    android:id="@+id/linScanBarCode"

                    android:layout_width="250.0dp"

                    android:layout_height="180dp"

                    android:layout_gravity="center"

                    android:layout_marginBottom="10dp"

                    android:layout_marginTop="20dp"

                    android:gravity="center"

                    android:orientation="vertical">

                    <ImageView

                        android:id="@+id/imageView1"

                        android:layout_width="wrap_content"

                        android:layout_height="wrap_content"

                        android:layout_gravity="center"

                        android:src="@mipmap/pictures_ic_barcode" />

                   <TextView

                        android:id="@+id/txtQRCode"

                        android:layout_width="wrap_content"

                        android:layout_height="wrap_content"

                        android:layout_gravity="center"

                        android:text=""

                        android:textSize="14sp" />

                </LinearLayout>

</RelativeLayout>

C# Code

using Android.App;

using Android.OS;

using Android.Support.V7.App;

using Android.Runtime;

using Android.Widget;

using Android.Content;

 

namespace QRCodeReader

{

    [Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]

    public class MainActivity : AppCompatActivity

    {

        /// <summary>

        /// 掃描QRCode觸控區塊

        /// </summary>

        /// <value>The lin scan bar code.</value>

        private LinearLayout linScanBarCode;

 

        private const int SCANNING_REQUEST_CODE = 1;

        protected override void OnCreate(Bundle savedInstanceState)

        {

            base.OnCreate(savedInstanceState);

            // Set our view from the "main" layout resource

            SetContentView(Resource.Layout.activity_main);

            linScanBarCode = FindViewById<LinearLayout>(Resource.Id.linScanBarCode);

            linScanBarCode.Click += (sender, e) =>

            {

                var intentCameraATY = new Intent(this, typeof(CameraATY));

                StartActivityForResult(intentCameraATY, SCANNING_REQUEST_CODE);

            };

        }

 

        protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)

        {

            base.OnActivityResult(requestCode, resultCode, data);

            var txtQRCode = FindViewById<TextView>(Resource.Id.txtQRCode);

            if (requestCode == SCANNING_REQUEST_CODE)

            {

                if (data != null)

                {

                    var QRCode = data.GetStringExtra("QRCode");

                    txtQRCode.Text = QRCode;

                }

            }

        }

    }

}

 

第二頁

Camera.axml

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:background="@android:color/black">

     <SurfaceView 

        android:id="@+id/cameraView" 

        android:layout_width="match_parent" 

        android:layout_height="match_parent" 

        android:layout_centerInParent="true" /> 

 

    

      

</RelativeLayout>

CameraATY.cs

 

using Android.App;

using Android.Content;

using Android.OS;

using Android.Content.PM;

using Android.Views;

using Android.Graphics;

using Android.Gms.Vision.Barcodes;

using static Android.Gms.Vision.Detector;

using Android.Util;

using Android.Gms.Vision;

using Android.Runtime;

using Android.Support.V4.App;

using Android;

using QRCodeReader;

using System.IO;

using Android.Support.V4.Content;

 

namespace QRCodeReader

{

    [Activity(Label = "CameraATY", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden, WindowSoftInputMode = SoftInput.AdjustPan, ScreenOrientation = Android.Content.PM.ScreenOrientation.UserLandscape)]

 

    /// <summary>

    /// 掃描同意書編號

    /// </summary>

    public class CameraATY : Activity, ISurfaceHolderCallback, IProcessor

    {

        SurfaceView surfaceView;

        //TextView txtResult;

        BarcodeDetector barcodeDetector;

        CameraSource cameraSource;

    

        protected override void OnCreate(Bundle savedInstanceState)

        {

            base.OnCreate(savedInstanceState);

            SetContentView(Resource.Layout.Camera);

 

            var permissions = new string[] { Manifest.Permission.Camera };

 

            if (!ActivityCompat.ShouldShowRequestPermissionRationale(this, Manifest.Permission.Camera))

            {

                ActivityCompat.RequestPermissions(this, permissions, 100);

            }

 

            this.surfaceView = (SurfaceView)FindViewById(Resource.Id.cameraView);

                // 選擇掃描格式

            BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(this).SetBarcodeFormats(BarcodeFormat.QrCode).Build();

            cameraSource = new CameraSource.Builder(this, barcodeDetector).SetFacing(CameraFacing.Back).SetAutoFocusEnabled(true).Build();

            surfaceView.Holder.AddCallback(this);

            barcodeDetector.SetProcessor(this);

        }

 

        public void ReceiveDetections(Detections detections)

        {

            SparseArray qrcodes = detections.DetectedItems;

            if (qrcodes.Size() != 0)

            {

                var QRCode = ((Barcode)qrcodes.ValueAt(0)).RawValue;

 

                var intent = new Intent(this, typeof(MainActivity));

                intent.PutExtra("QRCode", QRCode);

                SetResult(Result.Ok, intent);

                Finish();

            }

        }

    

        public void Release()

        {

           

        }

 

        public void SurfaceChanged(ISurfaceHolder holder, [GeneratedEnum] Format format, int width, int height)

        {

           

        }

 

        public void SurfaceCreated(ISurfaceHolder holder)

        {

            cameraSource.Start(surfaceView.Holder);

        }

 

        public void SurfaceDestroyed(ISurfaceHolder holder)

        {

            cameraSource.Stop();

        }

    }

}

 

這段可以選擇你要的格式QrCode, 或是Code39條碼

 

 

開啟相機

 

 

ReceiveDetections會一直執行, 當感應到值得時候Size會大於0, 就可將直傳回第一

 

 

Activity傳直是使用startActivityForResult( ) 的方法

startActivityForResultstartActivity的不同之處在於:
1
startActivity( ) 
僅僅是跳轉到目標頁面,若是想跳回當前頁面,則必須再使用一次startActivity( )
2
startActivityForResult( ) 
可以一次性完成這項任務,當程式執行到這段程式碼的時候,假若從T1Activity跳轉到下一個Text2Activity,而當這個Text2Activity呼叫了finish()方法以後,程式會自動跳轉回T1Activity,並呼叫前一個T1Activity中的onActivityResult( )方法。

 

第一頁倒頁的時候需要傳一個requestCode 來識別傳回來的Activity

requestCode 可以自己設定

 

 

第二頁時要傳回值得時候使用Intent回傳Result.OkFinish()

 

 

Finish() 之後便會回第一頁的複寫OnActivityResult方法

此時用剛從第一頁來識別的requestCode來判斷

data就為從第二頁傳來的Intent

 

 

 

再測試的過程中有發現一個問題

Fail to connect to camera service 一直連結不到camera

 

 

此時就去檢查專案屬性的必要權限沒有勾選CAMERA, 勾選之後程式就可常執行了

 

 

 

 

李昀峻