Android Studio 扫码实战:ZXing 集成与避坑指南
简介这份资源面向 Android 开发初学者与需要快速集成扫码能力的开发者聚焦在 Android Studio 中实现手机扫描二维码这一常见需求帮助读者理解相机权限申请、第三方扫码库接入与页面跳转的完整流程。资源包共 1 个文件为 PDF 格式大小约 44KB内容以图文与代码片段结合的方式呈现便于对照阅读和本地留存。讲解覆盖 Android 6.0 及以上动态获取相机权限、在 build.gradle 中引入 zxing-library 依赖、activity_main.xml 中放置触发按钮以及 MainActivity 中判断系统版本、申请权限并跳转 CaptureActivity 的核心逻辑同时简要说明 ZXingLibrary 解析二维码的基本原理。目前已有 2819 人学习适合作为扫码功能入门参考或课程设计、小工具开发时的实现思路来源。1. 从零在 Android Studio 里跑通扫码这份资源到底能省你多少事如果你手上正好有一个「扫一扫」的需求比如进销存 App 扫商品条码、门禁系统扫访客码、活动签到扫核销码那这份 Android Studio 实现手机扫描二维码功能的资源包基本就是拿来即用的起点。它解决的不是「二维码是什么」这种概念问题而是把相机预览、图像解码、权限申请、结果回调这一整条链路在 Android Studio 里真正跑起来。适合两类人一是刚接触 Android 相机开发、被 Camera2 和权限搞晕的新手二是想快速验证扫码方案、不想从零造轮子的熟手。下面我按「资源是什么 → 怎么用 → 坑在哪」的顺序把这份资源拆开讲透让你照着就能复现。2. 扫码方案选型ZBar、ZXing 还是 ML Kit先想清楚再动手2.1 三种主流解码库的边界与取舍在 Android Studio 里做扫码绕不开三个名字ZXing、ZBar、Google ML Kit。这份资源默认走的是 ZXing 的 Android 封装路线原因很实际——纯 Java 实现、不依赖 Google Play 服务、离线可用、社区资料多。ZBar 解码速度快但对中文和复杂二维码的识别率不如 ZXing而且 C 库集成要配 NDK新手容易在 so 文件上翻车。ML Kit 识别率最高、支持多码同扫但它是 Google 的服务国内设备没有 GMS 时直接罢工这一点在真机测试时是血泪经验。选型时我一般看三个维度是否需要离线、是否依赖 GMS、包体积能接受多大。ZXing 的 core 包约 500KB加上相机预览封装整体增量在 1MB 左右对大多数 App 可接受。如果你的场景是固定扫一种码、对速度极敏感可以考虑 ZBar如果是复杂光照、多码场景且能接受 GMS 依赖ML Kit 更省心。这份资源选 ZXing是稳妥且通用的选择。2.2 依赖引入与 Gradle 配置资源包里通常已经配好了依赖但你要知道每一行是干什么的出问题才能改。核心是zxing-android-embedded这个封装库它把相机预览和解码线程都包好了比直接用zxing-core少写几百行。// app/build.gradle android { compileSdk 34 defaultConfig { minSdk 21 // ZXing embedded 最低支持 21 targetSdk 34 } } dependencies { // 带相机预览的封装库自动处理 Camera1/Camera2 兼容 implementation com.journeyapps:zxing-android-embedded:4.3.0 // 核心解码库一般由上面间接引入显式声明便于锁定版本 implementation com.google.zxing:core:3.5.2 }minSdk设 21 是因为 embedded 4.x 不再支持更低版本如果你项目要兼容 Android 4.x得降到 3.x 版本但那样相机兼容性会差很多。targetSdk设 34 时要注意 Android 13 的相机权限和通知权限变化后面避坑章节会细说。依赖加完记得 Sync如果卡在下载检查一下仓库地址国内环境常见做法是加阿里云镜像。2.3 权限声明与运行时申请扫码必须用相机Android 6.0 以后相机是危险权限必须运行时申请。资源里一般会在 Manifest 声明再在 Activity 里动态请求。!-- AndroidManifest.xml -- uses-permission android:nameandroid.permission.CAMERA / !-- 声明相机硬件特性非必需但能让无相机设备不安装 -- uses-feature android:nameandroid.hardware.camera android:requiredfalse /// 运行时申请Android 6.0 必须 if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) ! PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQ_CAMERA); }uses-feature里requiredfalse很关键设成 true 会让没有相机的平板、模拟器无法安装你的 App调试时容易误判。运行时申请的回调里要判断用户是否勾了「不再询问」勾了就得引导去设置页否则扫码按钮点了没反应用户以为 App 坏了。3. 扫码核心实现从启动相机到拿到解码结果3.1 用 CaptureActivity 一行启动扫码ZXing embedded 最省事的地方是自带一个CaptureActivity你直接用它就能扫连布局都不用写。// 方式一最简单直接启动内置扫码页 IntentIntegrator integrator new IntentIntegrator(this); integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE); // 只扫二维码 integrator.setPrompt(把二维码放进框里); // 底部提示文字 integrator.setCameraId(0); // 0 后置1 前置 integrator.setBeepEnabled(true); // 扫中响一声 integrator.setOrientationLocked(false); // 不锁横竖屏 integrator.initiateScan();setDesiredBarcodeFormats只留 QR_CODE 能提升识别速度因为解码线程不用遍历所有格式。setCameraId(0)是后置摄像头扫码场景基本都用后置。setOrientationLocked(false)让屏幕能旋转但要注意旋转后预览方向可能错乱这是 embedded 库的老问题后面避坑会讲。3.2 接收扫码结果与解析启动扫码页后结果通过onActivityResult回来这是必须处理的回调。Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { IntentResult result IntentIntegrator.parseActivityResult(requestCode, resultCode, data); if (result ! null) { if (result.getContents() null) { // 用户按了返回没扫到 Toast.makeText(this, 已取消, Toast.LENGTH_SHORT).show(); } else { // 拿到二维码内容 String content result.getContents(); String format result.getFormatName(); // 码类型如 QR_CODE handleScanResult(content, format); } } else { super.onActivityResult(requestCode, resultCode, data); } }parseActivityResult是库提供的静态方法帮你把 Intent 里的内容解出来不用自己抠 key。getContents()返回 null 表示用户主动取消这个分支一定要处理否则空指针。getFormatName()在只扫二维码时恒为 QR_CODE但如果你放开了多种格式它能告诉你扫到的是 EAN_13 还是 CODE_128做业务分流时有用。3.3 自定义扫码界面把扫码框嵌进自己的布局内置 CaptureActivity 够用但样式固定很多项目要求扫码框嵌在自定义页面里。这时用DecoratedBarcodeView自己搭。!-- activity_custom_scan.xml -- com.journeyapps.barcodescanner.DecoratedBarcodeView android:idid/barcode_view android:layout_widthmatch_parent android:layout_heightmatch_parent app:zxing_scanner_layoutlayout/custom_scanner_overlay /// 自定义 Activity 里绑定 private DecoratedBarcodeView barcodeView; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_custom_scan); barcodeView findViewById(R.id.barcode_view); barcodeView.setStatusText(对准二维码自动识别); // 设置解码回调 barcodeView.decodeContinuous(new BarcodeCallback() { Override public void barcodeResult(BarcodeResult result) { if (result.getText() ! null) { barcodeView.pause(); // 先暂停相机避免重复回调 handleScanResult(result.getText(), result.getBarcodeFormat().name()); } } Override public void possibleResultPoints(ListResultPoint resultPoints) { // 预览里画识别点一般不用 } }); } Override protected void onResume() { super.onResume(); barcodeView.resume(); // 必须否则回来黑屏 } Override protected void onPause() { super.onPause(); barcodeView.pause(); // 必须否则相机不释放 }decodeContinuous是连续解码相机一直开着扫到就回调。回调里第一件事是pause()否则同一张码会连续触发多次业务上会重复下单或重复签到。onResume/onPause里必须成对调用resume/pause这是相机资源管理的铁律漏了就是黑屏或耗电。custom_scanner_overlay是你自己画的扫码框布局中间镂空、四角画线纯 XML 就能做。4. 避坑与排查扫码翻车的五个真实场景4.1 现象扫码页一片黑相机没启动原因通常是权限没给或者onResume里忘了调resume()。还有一种情况是模拟器没有真实相机用的是虚拟场景预览是黑的但能扫静态图。解决先确认权限回调里grantResults是PERMISSION_GRANTED再检查onResume是否调了resume。真机测试优先模拟器扫码本来就不靠谱。4.2 现象扫到了但回调触发好几次原因就是回调里没暂停相机连续解码模式下同一张码每帧都可能命中。解决在barcodeResult第一行调barcodeView.pause()处理完业务再决定要不要resume()。如果是内置 CaptureActivity它自己处理了去重一般不会重复。4.3 现象横竖屏切换后预览方向错乱这是 embedded 库在部分机型上的老毛病相机传感器方向和屏幕方向没对齐。解决扫码页锁定竖屏setOrientationLocked(true)或者在自己的 Activity 里android:screenOrientationportrait。扫码场景锁竖屏体验反而更稳用户不会边转手机边扫。4.4 现象Android 13 上相机权限申请了还是打不开Android 13 对权限做了细分但相机权限本身没变问题多半出在targetSdk升到 33 后某些厂商 ROM 对权限回调的处理有差异。解决申请前先shouldShowRequestPermissionRationale判断被拒后引导去Settings.ACTION_APPLICATION_DETAILS_SETTINGS手动开。另外别在onCreate里直接申请等用户点扫码按钮再申请通过率更高。4.5 现象Release 包扫码正常Debug 包反而报错常见于混淆配置。ZXing 的某些类被混淆后反射失败。解决在proguard-rules.pro里加保留规则。# ZXing 保留规则 -keep class com.google.zxing.** { *; } -keep class com.journeyapps.barcodescanner.** { *; } -dontwarn com.google.zxing.**Debug 包一般不混淆所以问题常出现在 Release。反过来如果 Debug 报错 Release 正常那多半是依赖冲突用./gradlew app:dependencies看有没有重复的 zxing 版本。5. 进阶技巧把扫码结果用对比扫得快更重要扫码本身跑通只是第一步真正决定体验的是拿到结果之后怎么处理。我一般会在handleScanResult里做三件事格式校验、内容清洗、防重复。格式校验是判断getFormatName()是不是你预期的码类型防止用户扫了别的码进来。内容清洗是去掉首尾空白和不可见字符二维码里带换行是常事直接拿去请求接口会 400。防重复是加一个时间戳或内容缓存同一内容 2 秒内只处理一次。private String lastContent ; private long lastTime 0; private void handleScanResult(String content, String format) { if (content null) return; content content.trim(); // 清洗 long now System.currentTimeMillis(); if (content.equals(lastContent) now - lastTime 2000) { return; // 2 秒内重复丢弃 } lastContent content; lastTime now; // 业务分流URL 走浏览器纯文本走搜索自定义协议走内部路由 if (content.startsWith(http)) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(content))); } else { tvResult.setText(content); } }验证方法很简单拿同一张码连续扫看日志里handleScanResult是不是只进了一次拿一张带换行的码扫看trim后内容是否干净。我还会用一张模糊的码测识别率ZXing 对模糊码的容忍度一般如果业务场景光线差可以考虑加个手电筒开关barcodeView.setTorchOn()一行就能开。从那以后我每次集成扫码都强制走一遍「真机 弱光 重复扫 横竖屏」这四个用例少一个都可能在上线后收到用户反馈。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →