楔子
许多安卓er开发时的一大事务就是扫码支付,而在我开发进程中遇到的则是扫描绑定设备这个场景,但归根到底,它们都是根据扫描二维码这一功用完结的,那么如何去做这块功用就成了是最重要的。
正文
在目前这个大环境下,我想大多数开发者不会去自动手撸一个扫码的轮子,一般仍是会自动寻求开源库的协助,所以咱们的需求也理所当然的变成了如安在林林总总五花八门的库中选取最合适的那个,然后去运用它,这一进程不同的开发者有不同的挑选,也就会有不同的完结办法,所以接下来就来跟随作者的视角看看我是如何完结这个功用吧。
准备工作
由于扫描二维码需求运用相机,所以第一步咱们要向用户恳求这一权限,然后是导入咱们挑选的开源库依靠,再配合CameraX库(用于运用安卓机相机功用的官方开源库)的运用去完结扫描二维码,剖析内容,最终向用户生成成果(这一步随着事务不同改变,成果的处理多种多样,这儿就用网站链接二维码示例,最终剖析好跳到浏览器拜访网页或许翻开webView拜访),这儿梳理好完结步骤,接下来一步步往下走即可。
开源库的挑选
我再查询了一番资料后,基本了解了一些开源库的功用来源以及作用,所以我挑选了Google的MLkit库,这个库是用于各种机器学习功用的,这儿咱们运用它的扫描和解析二维码这部分功用,由于是官方出的,还有许多配套的功用库,比方Google Play Services Vision 库
,但是需求有配套的Google play结构服务之类的,总之在能用谷歌时是十分凶猛的,当然还有许多好的库能够用,比方Zxing库等,这儿不再展开说。
在导入依靠前能够在清单文件AndroidManifest.xml中加入:
<!-- 扫描二维码所需权限 -->
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
之后咱们这儿直接把依靠导入app下的build.gradle文件中:
dependencies {
...
// 相机相关依靠
implementation 'androidx.camera:camera-camera2:1.1.0'
implementation 'androidx.camera:camera-lifecycle:1.1.0'
implementation 'androidx.camera:camera-view:1.1.0-beta02'
// MLKit Barcode Scanning依靠
implementation 'com.google.mlkit:barcode-scanning:17.0.0'
//动态权限获取
implementation 'pub.devrel:easypermissions:3.0.0'
// implementation 'com.google.zxing:core:3.5.1'
// implementation 'me.dm7.barcodescanner:zxing:1.9.13'
// implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
}
这儿简略说一下导入的几个依靠:
- CameraX库依靠
这儿相机相关的依靠增加了三个,都是CameraX库的,它们分别是:
- Camera2 API:CameraX 库运用 Camera2 API 来拜访相机硬件。
implementation 'androidx.camera:camera-camera2:1.1.0'
依靠包括 Camera2 API 的完结。 - Lifecycle 组件:CameraX 库运用 Lifecycle 组件来办理相机的生命周期。
implementation 'androidx.camera:camera-lifecycle:1.1.0'
依靠包括 Lifecycle 组件的完结。 - Viewfinder 组件:CameraX 库供给了一个名为 Viewfinder 的组件,它能够用来显现相机预览。
implementation 'androidx.camera:camera-view:1.1.0-beta02'
依靠包括 Viewfinder 组件的完结。
这些依靠之所以需求一起运用,是由于它们一起组成了 CameraX 库的核心部分,而且这些依靠之间也存在依靠关系,camera-view
依靠需求依靠camera-camera2
和camera-lifecycle
依靠。
当然,它们也能够独立运用,比方:如果咱们需求在运用中运用 CameraX 的相机预览功用,则应该增加camera-view
依靠;想要拜访相机硬件并捕获图画的话,就得增加camera-camera2
依靠;camera-lifecycle
依靠则供给了相机生命周期的办理功用,能够协助咱们更好地办理相机资源。
为了方便起见,咱们仍是把三个依靠都增加进项目中吧。
- MLKit Barcode Scanning依靠
这个就是咱们用来完结扫描功用的重要依靠,是导入了MLKit库的 Barcode Scanning部分,用来扫描和解析条形码和二维码的。
- 简化 Android 权限恳求依靠
这个库的导入是用于简化 Android 权限恳求的进程。该库由 Google 开发和维护,旨在供给一种简略、易用的办法来恳求用户授权,以便运用程序能够拜访灵敏权限,运用这个库咱们能够不必编写杂乱的权限恳求逻辑,而是能够在几行代码中完结权限恳求和处理。
上面就是咱们增加的几个依靠的简略的说明补充,同步好Gradle(Sync Project with Gradle Files ),接下来进入事务层。
代码开发
首先当然先把UI布局大约结构写好:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.camera.view.PreviewView
android:id="@+id/preview_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/result_text_view"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/result_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:background="@android:color/white"
android:gravity="center"
android:textColor="@android:color/black"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
这儿咱们简略的处理了一下UI,在约束布局ConstraintLayout中增加了用来预览相机画面的PreviewView组件和用来输出二维码剖析成果的TextView。
接下来就是处理Activity层代码:
这部分代码过长,就不放进文章了,能够去作者的Github地址上看看本文件内容(QrScanActivity.java):MyTest/app/src/main/java/com/example/mytest/QrScanActivity.java at main ObliviateOnline/MyTest GitHub
这地方的逻辑处理其实也不杂乱,咱们渐渐剖析。
第一步:动态恳求相机权限
首先咱们由于需求调用摄像头,所以应该动态向用户恳求权限:
这儿是调用了咱们的EasyPermissions库
,这块代码能够参阅作者之前的文章(安卓开发小技巧——动态获取权限 – ()),作用如下:
有了相机调用权限后,这儿先在QrScanActivity
中创立这些一会要用的目标:
private PreviewView previewView;
private TextView resultTextView;
private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
private BarcodeScanner barcodeScanner;
其中previewView用来处理摄像头预览画面;
resultTextView是扫描成果输出;
而cameraProviderFuture是一个ListenableFuture<ProcessCameraProvider>
类型的目标,它是用于获取ProcessCameraProvider
实例,ProcessCameraProvider
类供给了一个相机生命周期的办理器,可用于绑定相机的不同组件(例如Preview
、ImageAnalysis
)以及相机的生命周期。经过运用cameraProviderFuture.get()
办法,能够在需求时获取ProcessCameraProvider
实例。由于相机初始化需求必定的时刻,因而cameraProviderFuture
能够异步地初始化相机,并在相机准备好后通知运用程序,如下:
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
Preview preview = new Preview.Builder().build();
preview.setSurfaceProvider(previewView.getSurfaceProvider());
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();
Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview);
// 绑定ImageAnalysis实例到相机生命周期中
cameraProvider.bindToLifecycle(this, cameraSelector, imageAnalysis);
最终的barcodeScanner就是咱们MLKit库用来处理二维码的,咱们能够经过BarcodeScanning.getClient()
创立了一个BarcodeScanner
实例。然后在ImageAnalysis.Analyzer
的analyze()
办法中,咱们经过BarcodeScanner
实例的process()
办法,将相机捕捉到的图画作为输入,履行二维码的辨认操作。如果辨认成功,咱们能够在回调中获取到辨认成果,并将成果显现在 UI 界面上:
即如下这块代码:
// 创立BarcodeScanner实例
barcodeScanner = BarcodeScanning.getClient();
// 创立ImageAnalysis实例
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build();
// 设置ImageAnalysis剖析器
imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this), new ImageAnalysis.Analyzer() {
@Override
@OptIn(markerClass = ExperimentalGetImage.class)
public void analyze(@NonNull ImageProxy image) {
// 获取ImageProxy目标
Image mediaImage = image.getImage();
if (mediaImage != null) {
// 创立InputImage目标
InputImage inputImage = InputImage.fromMediaImage(mediaImage, image.getImageInfo().getRotationDegrees());
// 运用BarcodeScanner辨认二维码
barcodeScanner.process(inputImage)
.addOnSuccessListener(barcodes -> {
for (Barcode barcode : barcodes) {
if (barcode.getFormat() == Barcode.FORMAT_QR_CODE) {
String qrCodeValue = barcode.getRawValue();
// 在UI线程中更新TextView
runOnUiThread(() -> resultTextView.setText(qrCodeValue));
}
}
})
.addOnFailureListener(e -> {
// 处理扫描失利的状况
Log.e("QrScanActivity", "Failed to scan barcode", e);
})
.addOnCompleteListener(task -> image.close());
} else {
image.close();
}
}
});
完结上述代码后,咱们就能运行程序,完结扫描二维码并辨认,完好作用流程如下:
可能不给放扫描二维码的页面。。。删了,后边再看看
能够看到页面最底下显现了二维码的辨认后内容,我这儿是在二维码里放了一句诗,当然,这个扫二维码的进程是接连的,也就是能够及时的,二维码改变能够当即重新出成果:
cameraProviderFuture.addListener(() -> {}, ContextCompat.getMainExecutor(this));
原理就是前面的那段代码中setupCamera办法
完结的,当相机捕捉到新的帧时,ImageAnalysis.Analyzer
的analyze()
办法会被触发。在analyze()
办法中,咱们经过BarcodeScanner
实例的process()
办法对当时帧进行二维码辨认。由于这个办法是在异步线程中履行的,因而即便相机不断捕捉新的帧,也不会阻塞 UI 线程。如果在当时帧中检测到了二维码,咱们就能够在回调中获取到相应的辨认成果,并将成果显现在 UI 界面上。这样,只要相机不断捕捉新的帧,并且帧中包括二维码,就能够一直进行二维码的实时辨认。
结语
写完发现自己讲的还不是很细致,有些东西仍是没有说明白,但大致也经过这则示例展现出来了,依靠一导入,后边内容就是CameraX库的运用和MLKit库的运用了,结合在一起就完结了扫码功用,在此基础上,是将剖析好的成果如何做下一步处理都是需求的问题了,附加一句,咱们自己的开发项目用的是Zxing库完结的,看了一遍,是自定义View去做的,处理剖析成果的代码也挺杂乱,所以感觉运用CameraX库+Google MLKit库的办法就显得格外轻松了。
欢迎掘友们纠正!