`
xinlanzero
  • 浏览: 252975 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

条码扫描二维码扫描——ZXing android 源码简化

 
阅读更多

前言

  最近公司的Android项目需要用到摄像头做条码或二维码的扫描,Google一下,发现一个以Apache License 2.0 开源的 ZXing项目。Zxing项目里的Android实现太过复杂多余东西太多,得对其进行简化。

前提条件

  下载源代码:点击这里

  编译核心库:Zxing的主页上有介绍具体步骤,大家也可以参照这篇博文:android 条码识别软件开发全解析(续2详解绝杀!)

导入项目

  打开Eclipse 导入 源码中的 Android 项目,然后右击项目 选择“Build path”——》"Add External Archives" 把核心库 core.jar文件加入到项目中。

此时编译一下项目,会发现报错,“ Multiple substitutions specified in non-positional format; did you mean to add the formatted="false" attribute?”之类的。打开raw 下的Values 发现错误是在一个<String>上。这里把 “preferences_custom_product_search_summary” 里的  %s  %f  全部都改成  %1$s  %1$f(因为我们用不到多国语言,建议只保留默认的Value ,其他全部删除)。

  原因:由于新的SDK采用了新版本的aapt(Android项目编译器),这个版本的aapt编译起来会比老版本更加的严格,然后在Android最新的开发文档的描述String的部分,已经说明如何去设置 %s 等符号

  “If you need to format your strings using String.format(String, Object...) , then you can do so by putting your format arguments in the string resource. For example, with the following resource:

  <string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>

  In this example, the format string has two arguments: %1$s is a string and %2$d is a decimal number. You can format the string with arguements from your application...“

  经过以上步骤后项目应该就可以运行了。

  但是ZXing的android项目东西太多了,有很多是我们不需要的,得新建另一个项目简化它。

简化

  在开始前大致介绍一下简化ZXing需要用到各个包 、类的职责。

  • CaptureActivity。这个是启动Activity 也就是扫描器(如果是第一安装,它还会跳转到帮助界面)。
  • CaptureActivityHandler 解码处理类,负责调用另外的线程进行解码。
  • DecodeThread 解码的线程。
  • com.google.zxing.client.android.camera 包,摄像头控制包。
  • ViewfinderView 自定义的View,就是我们看见的拍摄时中间的框框了。

新建另一个项目

  新建另一个项目将启动的Activity命名为CaptureActivity,并导入核心库。项目新建完成后我们打开 CaptureActivity 的布局文件,我这里为main。把里面的XML修改为:

1 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:layout_width="fill_parent" android:layout_height="fill_parent"> 3 <SurfaceView android:id="@+id/preview_view" 4 android:layout_width="fill_parent" android:layout_height="fill_parent" 5 android:layout_centerInParent="true" /> 6 7 <com.Zxing.Demo.view.ViewfinderView 8 android:id="@+id/viewfinder_view" android:layout_width="fill_parent" 9 android:layout_height="fill_parent" android:background="@android:color/transparent" /> 10 <TextView android:layout_width="wrap_content" 11 android:id="@+id/txtResult" 12 android:layout_height="wrap_content" android:text="@string/hello" /> 13 14  </FrameLayout>

  可以看到在XML里面用到了 ViewfinderView 自定义view 。所以新建一个View 的包,然后把:ViewfinderView 和 ViewfinderResultPointCallback 靠到里面(记得对应修改XML里面的包)。

打开 CaptureActivity 覆盖 onCreate 方法:

1 @Override 2 public void onCreate(Bundle savedInstanceState) { 3 super.onCreate(savedInstanceState); 4 setContentView(R.layout.main); 5 //初始化 CameraManager 6   CameraManager.init(getApplication()); 7 8 viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view); 9 txtResult = (TextView) findViewById(R.id.txtResult); 10 hasSurface = false; 11 inactivityTimer = new InactivityTimer(this); 12 }

  这里调用到的 CameraManager 类是控制摄像头的包里的类。新建一个camera包把:com.google.zxing.client.android.camera 里面的类全部拷入,另外我把PlanarYUVLuminanceSource也拷入到这个包里面。根据错误的提示来修正代码,主要是修改正包结构。(整个简化的流程都是如此:“根据错误提示,修改代码”)。

  在修改的过程中,有很多是关于R 资源的问题,在此我们需要将Values  里面的两个xml资源文件拷入项目中:colos.xml 和ids.xml 。 ctrl+b 一下看看error 是不是少了很多。在CameraManager中有些地方需要用到项目的配置,这里需要把配置直接写入代码中:

// SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); //是否使用前灯 // if (prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false)) { // FlashlightManager.enableFlashlight(); // } FlashlightManager.enableFlashlight();

   使用摄像头需要加入相应的权限:

<uses-permission android:name="android.permission.CAMERA"></uses-permission> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /> <uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.FLASHLIGHT"/>

  当View 和 camera 包里的错误修正完成后,我们继续来看CaptureActivity。

覆盖onResume方法初始化摄像头:

@Override protected void onResume() { super.onResume(); SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view); SurfaceHolder surfaceHolder = surfaceView.getHolder(); if (hasSurface) { initCamera(surfaceHolder); } else { surfaceHolder.addCallback(this); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } decodeFormats = null; characterSet = null; playBeep = true; AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE); if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) { playBeep = false; } initBeepSound(); vibrate = true; }
initCamera
1 private void initCamera(SurfaceHolder surfaceHolder) { 2 try { 3 CameraManager.get().openDriver(surfaceHolder); 4 } catch (IOException ioe) { 5 return; 6 } catch (RuntimeException e) { 7 return; 8 } 9 if (handler == null) { 10 handler = new CaptureActivityHandler(this, decodeFormats, 11 characterSet); 12 } 13 }
SurfaceHolder接口实现
@Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { if (!hasSurface) { hasSurface = true; initCamera(holder); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { hasSurface = false; }

initCamera () 方法用于初始化摄像头,如果排除了所有的error ,运行项目时就可以看到大致扫描界面了。 surfaceHolder.addCallback(this);表示让CaptureActivity实现其callback接口。

handler = new CaptureActivityHandler(this, decodeFormats, characterSet) 用于进行扫描解码处理。

解码

  上面的步骤主要都是用于对摄像头的控制,而解码的真正工作入口是在CaptureActivityHandler 里面的。新建一个Decoding包把以下文件拷入包中:

  • CaptureActivityHandler
  • DecodeFormatManager
  • DecodeHandler
  • DecodeThread
  • FinishListener
  • InactivityTimer
  • Intents

由于我们的包结构和Zxing 项目的有所不同所以需要注意一下类的可访问性

同样开始ctrl+B 编译一下,然后开始修正错误。

  在CaptureActivityHandler 里 把 handleMessage 里的部分方法先注释掉如:“decode_succeeded ”分支,这是解码成功时调用 CaptureActivity 展示解码的结果。

在DecodeThread 类里,修改部分涉及Preference配置的代码:

DecodeThread(CaptureActivity activity, Vector<BarcodeFormat> decodeFormats, String characterSet, ResultPointCallback resultPointCallback) { this.activity = activity; handlerInitLatch = new CountDownLatch(1); hints = new Hashtable<DecodeHintType, Object>(3); // // The prefs can't change while the thread is running, so pick them up once here. // if (decodeFormats == null || decodeFormats.isEmpty()) { // SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity); // decodeFormats = new Vector<BarcodeFormat>(); // if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_1D, true)) { // decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS); // } // if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_QR, true)) { // decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS); // } // if (prefs.getBoolean(PreferencesActivity.KEY_DECODE_DATA_MATRIX, true)) { // decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS); // } // } if (decodeFormats == null || decodeFormats.isEmpty()) { decodeFormats = new Vector<BarcodeFormat>(); decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS); decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS); decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS); } hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats); if (characterSet != null) { hints.put(DecodeHintType.CHARACTER_SET, characterSet); } hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, resultPointCallback); }

这里是设置 解码的类型,我们现在默认将所有类型都加入。

错误类型基本上都是:包结构、PreferencesActivity 的配置 、类可访问性的问题。根据错误提示耐心把错误解决。

返回解码结果

   还记得在 CaptureActivityHandler 的 messagehandler 里注销掉的Case分支吗?现在CaptureActivity 里实现它。

public void handleDecode(Result obj, Bitmap barcode) { inactivityTimer.onActivity(); viewfinderView.drawResultBitmap(barcode); playBeepSoundAndVibrate(); txtResult.setText(obj.getBarcodeFormat().toString() + ":" + obj.getText()); }

最后

  ZXing的简化已基本完成,有几位是可以运行成功的?呵呵。

下面是CaptureActivity的源码:

CaputreActivity
public class CaptureActivity extends Activity implements Callback { private CaptureActivityHandler handler; private ViewfinderView viewfinderView; private boolean hasSurface; private Vector<BarcodeFormat> decodeFormats; private String characterSet; private TextView txtResult; private InactivityTimer inactivityTimer; private MediaPlayer mediaPlayer; private boolean playBeep; private static final float BEEP_VOLUME = 0.10f; private boolean vibrate; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //初始化 CameraManager CameraManager.init(getApplication()); viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view); txtResult = (TextView) findViewById(R.id.txtResult); hasSurface = false; inactivityTimer = new InactivityTimer(this); } @Override protected void onResume() { super.onResume(); SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view); SurfaceHolder surfaceHolder = surfaceView.getHolder(); if (hasSurface) { initCamera(surfaceHolder); } else { surfaceHolder.addCallback(this); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } decodeFormats = null; characterSet = null; playBeep = true; AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE); if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) { playBeep = false; } initBeepSound(); vibrate = true; } @Override protected void onPause() { super.onPause(); if (handler != null) { handler.quitSynchronously(); handler = null; } CameraManager.get().closeDriver(); } @Override protected void onDestroy() { inactivityTimer.shutdown(); super.onDestroy(); } private void initCamera(SurfaceHolder surfaceHolder) { try { CameraManager.get().openDriver(surfaceHolder); } catch (IOException ioe) { return; } catch (RuntimeException e) { return; } if (handler == null) { handler = new CaptureActivityHandler(this, decodeFormats, characterSet); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { if (!hasSurface) { hasSurface = true; initCamera(holder); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { hasSurface = false; } public ViewfinderView getViewfinderView() { return viewfinderView; } public Handler getHandler() { return handler; } public void drawViewfinder() { viewfinderView.drawViewfinder(); } public void handleDecode(Result obj, Bitmap barcode) { inactivityTimer.onActivity(); viewfinderView.drawResultBitmap(barcode); playBeepSoundAndVibrate(); txtResult.setText(obj.getBarcodeFormat().toString() + ":" + obj.getText()); } private void initBeepSound() { if (playBeep && mediaPlayer == null) { // The volume on STREAM_SYSTEM is not adjustable, and users found it // too loud, // so we now play on the music stream. setVolumeControlStream(AudioManager.STREAM_MUSIC); mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setOnCompletionListener(beepListener); AssetFileDescriptor file = getResources().openRawResourceFd( R.raw.beep); try { mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength()); file.close(); mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME); mediaPlayer.prepare(); } catch (IOException e) { mediaPlayer = null; } } } private static final long VIBRATE_DURATION = 200L; private void playBeepSoundAndVibrate() { if (playBeep && mediaPlayer != null) { mediaPlayer.start(); } if (vibrate) { Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); vibrator.vibrate(VIBRATE_DURATION); } } /** * When the beep has finished playing, rewind to queue up another one. */ private final OnCompletionListener beepListener = new OnCompletionListener() { public void onCompletion(MediaPlayer mediaPlayer) { mediaPlayer.seekTo(0); } };

简化过的包结构图:

 

 简化后的ZXing 更加方便我们了解ZXing项目 是如何解码的。只要仔细查看源码,进行单点跟踪调试,相信大家很容易能理解。

顾客是上帝

   很多人留言要源码, 其实我这不是什么源码,我只是把ZXing的东西简化了一下而已。事实上我也不喜欢直接放源码项目,这样大家就不想读ZXing的源码了。

下面是我简化的版本:Zxing简化

<script type="text/javascript"></script>

  • 大小: 14.1 KB
分享到:
评论
19 楼 李晓进 2012-07-06  
安装后之后点了扫描之后解码不出信息来呀????????O(∩_∩)O哈哈~
18 楼 meiyulaishi428 2012-03-26  
核心库
hexiaoxiao_love 写道
楼主真是好人啊,可是。。。我没有core.jar这个jar包,hexiaoxiao_love@163.com求好心人发一份。。。拜谢!

楼言主,core.jar这个包没有呀,发一份给我吧。285620308@qq.com
17 楼 meiyulaishi428 2012-03-23  
楼主,请问你的代码是采用的哪版API?我在新建工程的时候选create from existing source,选择下载下来的代码,会出现错误,[2012-03-23 14:47:02 - CaptureActivity] AndroidManifest.xml file missing!。
16 楼 newbeehi 2012-03-22  
扫描出来中文有乱码问题,楼主遇到过吗?
15 楼 hexiaoxiao_love 2012-03-17  
楼主真是好人啊,可是。。。我没有core.jar这个jar包,hexiaoxiao_love@163.com求好心人发一份。。。拜谢!
14 楼 幸运降临阿根 2012-03-16  
楼主,怎么jar包呀。。能不能共享下,能的话,给我发邮箱ligen_1007@sina.com 谢谢
13 楼 suiyuan17 2012-02-28  
11 楼 suiyuan17 2 小时前   引用

楼主,运行不起来啊,可不可以给我发到邮箱里啊,谢谢哦

我邮箱601966049@qq.com
12 楼 wuhanliupeng 2012-02-28  
我想模仿一下微信那样的布局实现。 结果失败了的。  不知道怎么弄, 就是把你这个给反过来 正着显示。   我的QQ  79144876   
11 楼 suiyuan17 2012-02-28  
楼主,运行不起来啊,可不可以给我发到邮箱里啊,谢谢哦
10 楼 zhoujiamail 2011-12-15  
谢谢,研究下
9 楼 ihopethatwell 2011-12-15  
楼主,运行的时候扫描中间出现了一道红线,不知道怎么去掉[img][/img]
8 楼 cfm1989 2011-12-10  
解析UTF-8的二维码会乱码啊。。
像这个生成的二维码解析不了http://www.qrcn.net/index.php/action-channel-name-qrcode
我查查,快拍二维码就可以解析~我快哭了
7 楼 liveths 2011-12-06  
楼主是强人,并且是一个好心肠的强人,这个二维码搞了我好几天了,遇到楼主这个好东东就立马解决了,大感谢啊。
6 楼 陈文景 2011-12-05  
liaozxbj 写道
在模拟器里能运行么?我怎么运行不成功啊

模拟器没法模拟摄像头
5 楼 liaozxbj 2011-11-18  
在模拟器里能运行么?我怎么运行不成功啊
4 楼 zhenglimeng1983 2011-11-01  
非常感谢楼主细心的讲解,真是不错啊,非常感谢
3 楼 surfing1982 2011-10-26  
好人啦,非常感谢。。。。
2 楼 wanghonghui023 2011-10-22  
借用了楼主的代码和核心包,放在自己项目里了,不知道楼主介意不?
1 楼 jkjfddf 2011-08-30  

相关推荐

    条形码、二维码扫描、生成Demo 完整源码

    Google的ZXing(Zebra Crossing)是一个开源项目,它提供了跨平台的条形码和二维码生成及扫描功能。下面将详细阐述ZXing的工作原理以及如何利用其开发一个完整的条形码、二维码生成与扫描的Demo。 首先,让我们了解...

    安卓Android源码——ZXing示例源码和核心core包.zip

    在安卓Android平台上,ZXing被广泛用于扫描和解码各种类型的条形码和二维码,为开发者提供了便捷的扫码功能。这个压缩包包含了ZXing的核心库`core-2.2.jar`和针对Android平台的示例源码。 `core-2.2.jar`是ZXing的...

    zxing.delphi是最新3.9.5版,支持到delphi 12,好用的条形码与二维码扫描源代码ZXing.Delphi-v

    ZXing.Delphi是一款专为Delphi开发者设计的开源库,用于实现条形码和二维码的扫描与生成。这个版本是3.9.5,它已经更新以支持最新的Delphi 12版本,这意味着开发者可以利用这个强大的工具在Delphi 12环境下构建具有...

    Google ZXing制作的条形码、二维码的生成、扫描Demo 源码.zip

    总之,Google ZXing提供的源码Demo是一个宝贵的教育资源,可以帮助开发者深入了解条形码和二维码的生成与扫描原理,以及如何在实际项目中高效地利用ZXing库。通过深入研究这个源码,你不仅可以掌握ZXing的基本用法,...

    android 二维码扫描Zxing

    在Android开发中,二维码扫描是一项常见的功能,用于读取和生成包含信息的二维条形码。ZXing(Zebra Crossing)是Google开发的一个开源项目,它提供了跨平台的二维码和条形码处理库。本文将详细介绍如何在Android...

    Android zxing生成 扫描二维码(依赖形式)

    在Android开发中,ZXing(Zebra Crossing)库是一个广泛使用的开源项目,它提供了二维码和条形码的生成与扫描功能。ZXing库为开发者提供了一个便捷的方式,将二维码扫描集成到自己的应用中,无需从零开始实现这些...

    Autojs调用zxing实现条形码与二维码

    总结来说,通过AutoJS调用ZXing库,我们可以为Android设备创建一个轻量级的条形码和二维码扫描器,无需依赖第三方应用,提升了用户体验。这种技术在自动化测试、数据录入、信息获取等场景中有很大的应用潜力。对于...

    安卓Android源码——zxing 生成二维码名片.zip

    【标题】中的“安卓Android源码——zxing 生成二维码名片”表明了这是一个关于在Android平台上使用ZXing库来生成二维码名片的项目源码。ZXing(Zebra Crossing)是Google开发的一个开源项目,用于读取和生成多种条形...

    基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果

    在Android开发中,实现二维码和条形码扫描功能是一项常见的需求。Google的Zxing(ZXing,发音为“zebra crossing”)库提供了一个全面的解决方案,它支持多种类型的条形码和二维码的生成与扫描。这个教程将指导你...

    android zxing条码扫描源码

    了解Zxing源码的工作原理后,开发者可以将其应用到各种场景,例如商品扫码、电子票务、信息交换等,提升应用的实用性和用户体验。 总之,Android版Zxing条码扫描源码提供了一个强大且灵活的条码处理框架。通过深入...

    Android生成和扫描二维码之ZXing

    在Android平台上,生成和扫描二维码是一项常见的功能,ZXing(Zebra Crossing)是一个开源项目,提供了跨平台的条形码和二维码处理库。本篇文章将深入探讨如何在Android应用中利用ZXing实现二维码的生成与扫描。 ...

    安卓Android源码——zxing生成二维码名片.zip

    ZXing是Google开发的一个开源项目,支持多种条形码和二维码的读取与生成。在Android应用中,我们可以直接引用ZXing的Android端库——`com.google.zxing:core`和`com.google.zxing:android-integration`,这两个库...

    使用zxing识别一幅包含多个二维码的图片

    ZXing(Zebra Crossing),又称“条形码解码库”,是一个开源项目,提供了多种格式的一维和二维条码读取功能,包括二维码。本篇文章将深入探讨如何使用ZXing来识别一幅包含多个二维码的图片。 首先,我们需要理解...

    安卓Android源码——ZXingDemo.zip

    在Android开发中,ZXing通常用于实现扫描和生成条形码或二维码的功能。ZXingDemo是基于ZXing库的一个示例应用,它展示了如何在Android项目中集成并使用ZXing进行条码扫描。 1. **ZXing 库的结构与功能** - **核心...

    二维码扫描——精简zxing 3.1.1,仅保留扫描和解码部分,增加n种特性

    ZXing(Zebra Crossing)是Google开发的一个开源项目,用于处理各种条形码和二维码的扫描与解码。ZXing库功能强大,但其全功能版本可能包含许多应用程序并不需要的所有组件,这可能会导致体积过大,影响应用性能。...

    Android 二维码扫描 ZXing源码

    ZXing,全称为“Zebra Crossing”,是一款开源的、跨平台的条形码和二维码读取库。在Android平台上,ZXing(又称“二维码扫一扫”)被广泛用于实现二维码扫描功能。本文将深入探讨ZXing源码,解析其在Android应用中...

    Zxing条形码和二维码扫描

    《Zxing:打造高效能的条形码与二维码扫描应用》 Zxing,全称“ZXing,意为“zebra crossing”(斑马线),是一个开源的、跨平台的条形码和二维码读取库。它允许开发者轻松地集成条码和二维码扫描功能到他们的应用...

    XE10 Android Zxing 实现竖屏扫二维码.docx

    1. **ZXing (Zebra Crossing)**: ZXing是一个开源的、多平台的一维和二维条码图像处理库,支持多种格式的编码和解码,如QR码、条形码等。在Android平台上,ZXing常用于实现二维码扫描功能。 2. **在Delphi XE10中...

    扫描二维码(zxing)

    二维码(Quick Response Code,简称QR码)是一种二维条形码,可以存储丰富的信息,如网址、文本、联系人信息等。ZXing(Zebra Crossing)是Google开发的一个开源的、跨平台的条码读取库,支持多种类型的条码和二维码...

    android 扫描二维码源码及实例

    通过分析"ZXingDemo"源码,我们可以学习如何将ZXing库集成到Android项目中,理解二维码扫描的完整流程,这对于开发自己的二维码应用非常有帮助。同时,这也能提升我们对Android相机、权限管理、UI设计以及第三方库...

Global site tag (gtag.js) - Google Analytics