使用 Google Play Services – Vision 掃描 QRCode
前言:
當我們使用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( ) 的方法
startActivityForResult與startActivity的不同之處在於:
1、startActivity( )
僅僅是跳轉到目標頁面,若是想跳回當前頁面,則必須再使用一次startActivity( )。
2、startActivityForResult( )
可以一次性完成這項任務,當程式執行到這段程式碼的時候,假若從T1Activity跳轉到下一個Text2Activity,而當這個Text2Activity呼叫了finish()方法以後,程式會自動跳轉回T1Activity,並呼叫前一個T1Activity中的onActivityResult( )方法。
第一頁倒頁的時候需要傳一個requestCode 來識別傳回來的Activity
requestCode 可以自己設定
第二頁時要傳回值得時候使用Intent回傳Result.Ok並Finish()
Finish() 之後便會回第一頁的複寫OnActivityResult方法
此時用剛從第一頁來識別的requestCode來判斷
此data就為從第二頁傳來的Intent
再測試的過程中有發現一個問題
Fail to connect to camera service 一直連結不到camera
此時就去檢查專案屬性的必要權限沒有勾選CAMERA, 勾選之後程式就可常執行了