ZXing 源码分析(简阅)

时间:2021-10-19 16:47:38

导读

  • 虽然有句话在程序员中说:”别人造好的*,不要重复发明*”,但是只会用别人的东西,对自己个人技术的提升也是不可能的0.0 那么最好的方式就是看源码.
  • 本篇文章就是个人在使用ZXing后看官方Demo源码的读后感,有不对的地方欢迎评论指出,一起讨论.

源码操作:


官方源码Demo结构图:

ZXing 源码分析(简阅)

由图可知官方Demo里面有两个项目:
1. CaptureActivity 官方的”二维码扫描器”项目
2. ZXingTestActivity 测试CaptureActivity用的,有兴趣的同学自己看下,以后有时间再补充


com.google.zxing.client.android 包

与CaptureActivity直接相关的核心组件。包含了发生震动管理器,闪光灯等等

  • AmbientLightManager implements SensorEventListener 光线管理器(环境光亮屏幕自动变暗,反之)

使用 (当我们闪光灯模式选择自动时会调用):
1. CaptureActivity onCreate() 实例化AmbientLightManager ambientLightManager = new AmbientLightManager(this);
2. 在要使用的方法启动ambientLightManager.start(cameraManager)或关闭ambientLightManager.start()

  • BeepManager implements MediaPlayer.OnErrorListener, Closeable 扫描成功后的手机震动和提示音管理器

使用:
1. CaptureActivity onCreate() 中 BeepManager beepManager = new BeepManager(this);
2. CaptureActivity onResume() 中 beepManager.updatePrefs();
3. CaptureActivity onPause() 中 beepManager.close();
4. 在要使用的方法启动 beepManager.playBeepSoundAndVibrate();

  • CaptureActivity “条形码扫描器”主页面,主要逻辑

  • CaptureActivityHandler 消息处理类

几个消息说明:
1. DecodeHandler 的 decode_succeeded 解码成功
2. DecodeHandler 的 decode_failed 解码失败
3. CaptureActivity 的 restart_preview 启动扫描
4. CaptureActivity 的 return_scan_result 返回条形码结果内容界面
5. CaptureActivity 的 launch_product_query 查询商品(打开浏览器)

  • Contents 常量类(扫码类型)

  • DecodeFormatManger 配置”解码类型”管理类:

主要方法:
通过parseDecodeFormats() ,返回我们扫描后得到的 “解码格式” (一维码,二维码,其他)
1. DecodeFormatManager.parseDecodeFormats(intent);
2. DecodeFormatManager.parseDecodeFormats(inputUri);

  • DecodeHandler 解码消息处理类:

主要方法:
DecodeHandler.decode(byte[] data, int width, int height) 解码取景器矩形中的数据以及所需时间 解码的核心类
DecodeHandler类被DececodeThread线程中实例化 Handler handler = new DecodeHandler(activity, hints);

  • DecodeHintManager 解码线索管理类 (根据传进来的参数(Uri,intent),返回线索)

小说明:
1. “hints 线索”: 用于通过条形码阅读器,更快或准确的解码
2. 传线索给 CaptrueActivity ,交给DecodeThread 处理

主要方法 (在CaptureActivity onResume() 中被调用):
1. DecodeHintManager.parseDecodeHints(intent);
2. decodeHints = DecodeHintManager.parseDecodeHints(inputUri);

  • DecodeThread 这个线程处理所有图像的解码

主要处理从 CaptureActivity 拿到的hints 线索

  • FinishListenr implements DialogInterface.OnClickListener,DialogInterface.OnCancelListener

Dialog 监听器(用于出现bug时退出Activity)

*使用:(结合 AlertDialog.Builder)*
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.app_name));
builder.setMessage(getString(R.string.msg_camera_framework_bug));
builder.setPositiveButton(R.string.button_ok, new FinishListener(this));
builder.setOnCancelListener(new FinishListener(this));
builder.show();
  • HelpActivity 帮助页面(webView查看帮助文档)

  • HttpHelper 网络请求工具类:

小说明:
1. HttpConnection 安全的网络请求(处理了可能出现的异常)
2. 访问特定的主机名或者以外的主机名
3. 能请求不同的网络数据类型 (html,xml,json,text)
4. 请求数据成功,把数据存到StringBuilder 缓冲区

主要方法(搜索图书资源用):
1. downloadViaHttp(String uri, ContentType type) 下载全部资源
2. downloadViaHttp(String uri, ContentType type, int maxChars) 下载自定大小资源
3. unredirect(Uri uri) 未定向访问网络 (如果访问的uri不包含上面的Host,就访问默认的uri)

 使用:
CharSequence content = HttpHelper.downloadViaHttp(uri,HttpHelper.ContentType.JSON);

如:
HttpHelper.downloadViaHttp("https://www.googleapis.com/books/v1/volues?q=isbn:" + isbn,HttpHelper.ContentType.JSON);
  • InactivityTimer 一段时间不操作(5分钟 ),关闭该应用(工具类)

使用在生命周期方法中:
1. 在onCreate() 初始化该对象 InactivityTimer = new InactivityTimer(this);
2. 在onResume() ; inactivityTimer.onResume()
3. 在onPause() ; inactivityTimer.onPause();
4. 在onDestroy() ; inactivityTimer.shutdown();
5. 在处理解码的handleDecode() 初始化该方法 ; inactivityTimer.onActivity() 启动里面的线程方法,让应用在解码时不执行InactivityTimer

  • Intents 这个类提供了在发送条形码扫描器的意图所使用的常量。

  • IntentSource 枚举类

1. NATIVE_APP_INTENT
本地app向条码扫描器(Barcode Scanner)发起的启动指令
* 比如在androidtest项目中,利用整合的android-integration对条码扫描器发起调用指令
* :com.google.zxing.client.android.SCAN
* 条码扫描器中该启动命令对应的Source类型便是NATIVE_APP_INTENT

2. PRODUCT_SEARCH_LINK , ZXING_LINK
打开条码扫描器的时候传入查询商品的url,与最终扫描到的product id结合进行查询 两种url的形式不同

3. NONE
直接打开条码扫描器
  • LocaleManager 处理任何特定地区的设备逻辑(适配设备语言的工具类)

  • PreferencesActivity “设置”里面的一些常量

    用PreferencesFragment replace PreferencesActivity

  • PreferencesFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener “设置”页面实现

  1. 布局在 res/xml/Preferences
  2. 一般结合PreferencesActivity 一起使用
  3. 里面有很多的Preference对象调用
  4. “自定义搜索网址”单独实现
  5. “条码类型”,设置几个双选框选项,最少选择一项
  • ScanFromWebPageManager 工具类:

传一个html的url,通过占位符{CODE},{RAWCODE},{META},{FORMAT},{TYPE}返回一个对应的,我们能处理的url
1. 让我们可以从一个网页调用ZXing进行扫描,通过回调URL的方式,返回结果到我们的网站
2. 如扫到 01234,链接到 http://foo.com/products/01234/description 网页
3. {CODE}是一种返回代码值的占位符

  • ViewfinderView SurferView相机预览界面(取景器矩形和部分透明,激光扫描仪点动画和结果)

  • ViewfinderResultPointCallback SurferView相机预览回调


com.google.zxing.client.android.book 包

如果查询的结果是图书信息,用户可以选择查询该书的更进一步的详细信息,该包即包含了搜索与展示书籍的相关类。

  • BrowseBookListener SearrchBookContentsActivity 中的Item按键监听器

  • SearchBookContentsActivity 联网”搜索图书”页面

  • SearchBookContentsAdapter Adapter适配器

  • SearchBookContentsListItem 显示图书搜索结果的页码和摘要的列表项

  • SearchBookContentsResult 图书搜索结果数据bean类


com.google.zxing.client.android.camera 包

  • AutoFocusManager implements Camera.AutoFocusCallback 自动对焦
 *在CameraManager中被使用*
AutoFocusManager implements Camera.AutoFocusCallback 自动对焦
使用:(在Camera中被使用)

OpenCamera theCamera = camera;

AutoFocusManager autoFocusManager = new AutoFocusManager(context, theCamera.getCamera());

1. autoFocusManager.start();
2. autoFocusManager.stop();
  • CameraConfigurationManager 设置相机的参数信息类

主要方法:
1. initFromCameraParameters(OpenCamera camera) 计算了屏幕分辨率和当前最适合的相机像素
2. setDesiredCameraParameters(OpenCamera camera, boolean safeMode) 读取配置设置相机的对焦模式、闪光灯模式等等
3. getPreviewSizeOnScreen()
4. getCameraResolution()
5. getScreenResolution()
6. getCWNeededRotation()
7. getTorchState(Camera camera)
8. setTorch(Camera camera, boolean newSetting)

*第二个方法setDesiredCameraParameters(...)扩展*
1. 可以在这个方法里加 CameraConfigurationUtils.setZoom(parameters, 2.0); 直接固定焦距

2. 可以在setDesiredCameraParameters(Camera camera, boolean safeMode) 方法最后加上:
camera.setDisplayOrientation(90); 设置相机预览为竖屏

3. 修改为竖屏后,由于像素点没有对调会造成扭曲变形,在 initFromCameraParameters(Camera camera) 方法中:

在Log.d(TAG, "Screen resolution: " + screenResolution);后加上如下的代码:

/** 因为换成了竖屏显示,所以不替换屏幕宽高得出的预览图是变形的 */
Point screenResolutionForCamera = new Point();
screenResolutionForCamera.x = screenResolution.x;
screenResolutionForCamera.y = screenResolution.y;
// preview size is always something like 480*320, other 320*480
if (screenResolution.x < screenResolution.y) {
screenResolutionForCamera.x = screenResolution.y;
screenResolutionForCamera.y = screenResolution.x;
}

最后,将screenResolution替换为screenResolutionForCamera:

cameraResolution = findBestPreviewSizeValue(parameters, screenResolutionForCamera);


  • CameraConfigurationUtils 主要为CameraConfigurationManager服务的工具类

1.findBestPreviewSizeValue(Camera.Parameters parameters, Point screenResolution) 获取最佳的相机预览分辨率

  • CameraManager 摄像头管理类(打开,关闭)

camera/camera.open包的核心类:

  1. 闪光灯开关,CameraManager.setTorch(true),方法父类是CameraConfigurationManager ,闪光灯开启同时启动自动对焦
  2. 打开摄像头驱动 CameraManager.openDriver(SurfaceHolder)
  3. 设置扫码框显示位置 getFramingRectInPreview()
  4. 设置扫码框矩形的大小(根据屏幕分辨率) getFramingRect()
  5. 设置扫码框矩形的大小(自定义 setManualFramingRect(int width, int height))
  • FrontLightMode 闪光灯枚举(开,关,自动)

  • PreviewCallback 当预览界面出来的时候PreviewCallback.onPreviewFrame()向DecodeHandler 发送一个decode消息,DecodeHandler收到后执行decode方法解码


com.google.zxing.client.android.camera.open 包

  • CameraFacing 打开前置或后置摄像头 枚举(BACK,FRONT)

  • OpenCamera bean类(获取摄像头部分参数index,camera,facing,orientation )

  • OpenCameraInterface 打开摄像头的接口类

这个类被CameraManager 的 OpenDirver() 调用:
OpenCamera theCamera = OpenCameraInterface.open(OpenCameraInterface.NO_REQUESTED_CAMERA);


com.google.zxing.client.android.clipboard 包

  • ClipboardInterface 用于调用Android系统自带的ClipboardManager

com.google.zxing.client.android.encode

编码功能的各个组件集合。核心类为QRCodeEncoder,最终实施编码的是MultiFormatWriter类

  • ContactEncoder 根据联系人信息实现编码方案,如名片或mecard

  • EncodeActivity 生成二维码,全屏显示的类

  • Formatter 封装了一些简单的格式化逻辑,协助重构{ @link ContactEncoder }。

  • MECARDContactEncoder 根据MECARD格式编码的联系人信息。

  • QRCodeEncoder 这个类负责在条形码编码时,解码用户的请求和提取所有数据

重要方法:
encodeASBitmap() 生成二维码

  • VCardContactEncoder 根据名片格式编码的联系信息。

  • VCardFieldFormatter 名片范围格式化逻辑

  • VCardTelDisplayFormatter 名片电话展示格式化逻辑


com.google.zxing.client.android.history 包

  • DBHelper 创建数据库,更新数据库

  • HistoryActivity “历史记录” 页面,以及逻辑实现

  • HistoryItem 单条”历史记录” 要显示的内容 bean类

  • HistoryItemAdapter 历史记录 显示数据用到的适配器

  • HistoryManager “历史记录” 数据库数据操作 (history包核心类)

  1. 添加”历史记录”
  2. 保存”历史记录”到本地
  3. 删除所有”历史记录” 方法
  4. 删除某一条”历史记录” 方法
  5. CaptureActivity 初始化 HistoryManager 时要删除的 history ID ,trimHistory()方法
  6. 查询 某一条 “历史记录”
  7. 查询 所有 “历史记录 “

com.google.zxing.client.android.result 包

条码扫描的结果被分为不同的类型,所有的类型都定义在com.google.zxing.client.result.ParsedResultType中,对于不同的类型都有对应的处理方法:xxxResultHandler,所有的ResultHandler都包含在此包中。不同的xxxResultHandler还提供了扫描结果页面要展示几个button,每个button的文本以及需要绑定的事件等等。

  • AddressBookResultHandler 处理地址簿条目

  • CalendarResultHandler 处理日历条目 QR码的编码

  • EmailAddressResultHandler 处理电子邮件地址

  • GeoResultHandler 处理地理坐标(地理编码:url)

  • ProductResultHandler 处理不是书的产品

  • ResultButtonListener 处理条形码解码的结果在Android平台的背景下,通过intent打开GMail等其他Activity,地图等

  • ResultHandler 针对android的条形码的基类处理程序。这允许应用程序使用多态的方式

建议适当的行动为每个数据类型。
这个类还包含一些实用方法采取共同行动就像打开一个URL。
他们可以很容易地进入一个辅助对象,但它不能是静态的,因为Activity实例需要启动一个意图。

  • ResultHandleFactory (Result包的核心类)

基于条码内容的类型,生产针对android的处理程序解析扫描二维码结果,返回对应类型的xxxHandler

这个类的makeResultHandler会调用parseResult方法,parseResult会
调用core类的核心方法,parseResult这个方法是用来解析扫描二维码得到的结果是属于那 种类型的数据,调用后返回ParsedResult类,
makeResultHandler方法就用到了getType()来判断扫描的结果是那一种类型的数据, 类型数据解析完成之后又回到CaptureActivity的handleDecode方法完成对数据的处理。

调用:
ResultHandler resultHandler = ResultHandlerFactory.makeResultHandler(this, rawResult); ZXing在CaptureActivity的handleDecode(..)

  • SMSResultHandle 处理短信地址,提供一个选择的组合一个新的SMS或MMS消息。

  • TelResultHandler 提供了电话号码的相关行为。

  • TextResultHandler 这个类处理TextParsedResult以及未知格式。这是回退处理程序。

  • URIResultHandler 提供了URLS的相关行为

  • WifiResultHandler 处理wifi访问信息


com.google.zxing.client.android.result.supplement 包

对已经扫描并解码的结果做额外处理的工具集

  • BookResultInfoRetriever 网页搜索图书

  • ProductResultInfoRetriever 从谷歌产品搜索检索产品信息

  • TitleRetriever 检索一个web页面的标题作为补充信息。

  • URIResultInfoRetriever 网页跳转,重定向用的

  • SupplementalInfoRetriever 这个包中为其他类的父类


com.google.zxing.client.android.share 包

分享二维码功能,亦是编码功能的入口所在

  • AppInfo 获取安装在设备上app相关信息的bean类

  • AppPickerActivity 获取安装在设备上app相关信息的类

  • BookmarkAdapter 获取浏览器书签的适配器

  • BookmarkPickerActivity 获取浏览器书签 方法类

  • LoadPackagesAsyncTask: 异步加载在设备上安装包的列表

  • ShareActivity 分享功能 界面类


com.google.zxing.client.android.wifi 包

是WifiResultHandler的辅助类集合。如果扫描到的二维码是对wifi信息的编码,那么最终扫描结果页会展示一个“连接到网络”的按钮,点击此按钮就会自动尝试连接。该包中所包含的类则是链接网络所需的工具类。

  • NetworkType wifi网络类型类型枚举(WEP,WPA,NO_PASSWORD)

  • WifiConfigManager

几个方法:
1. changeNetworkCommon 用来处理没有密码的 wifi连接
2. changeNetworkWEP 用来处理WEP的 wifi连接
3. changeNetworkWPA 用来处理WPA的 wifi连接
4. theWifiResult.getNetworkEncryption(); 得到wifi的类型


判断wifi连接状态,解析得到相应的wifi类型,然后连接

相关类:
1.WifiParsedResult 解析wifi类型的扫描结果
2.WifiResultHandler 用来存储解析后的结果

调用:

WifiParsedResult wifiResult = (WifiParsedResult) getResult();

WifiManager wifiManager = (WifiManager) getActivity().getSystemService(Context.WIFI_SERVICE);
...

new WifiConfigManager(wifiManager).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, wifiResult);

扫码流程:

  1. 配置Camera并启动Camera

  2. 构建preview与扫描窗口

    • 扫描窗口是在CaptureActivityHandler.restartPreviewAndDecode中,通过调用activity.drawViewfinder()来实现的。
    • 这里有个画扫描窗口的类叫ViewfinderView,该类也是想要改变扫描窗口风格所必须重构的一个类
  3. 捕捉画面并解码

    • Camera.PreviewCallback监听preView界面是否已经显示
    • PreviewCallback.onPreviewFrame做的事便是当preview界面展示出来的时候向DecodeHandler发送一个decode消息
    • DecodeHandler收到该消息后会执行decode方法来解码。
    • Camera.setOneShotPreviewCallback() 检测并触发捕获画面动作的,该函数被调用后,如果预览界面已经打开,就会将包含当前preview frame的byte数组传给回调函数,此时再向DecodeHandler发送decode消息。
  4. 将解码结果交给不同ResultHandler去处理

    • DecodeHandler.decode完成解码后会向CaptureActivityHandler发消息。如果编码成功则调用CaptureActivity.handleDecode方法对扫描到的结果进行分类处理
    • 获取ResultHandle,
// 解析rawResult,根据不同类型result生成对应的ResultHandler
ResultHandler resultHandler = ResultHandlerFactory.makeResultHandler(this, rawResult);
  • 调用handleDecodeInternally和handleDecodeExternally对ResultHandler进行处理

总结

这篇文章仅仅是简阅,可能存在许多不足地方,也研究的不够深入(如.ZXingTestActivity 一边测试,一边研究没做0.0 …),如果有错误的地方欢迎评论指出,一起共同进步…!

精简版的ZXing网上有很多,这里就不提供了,后续有时间自己再封装一个适合自己项目吧…0.0