经过我的测试,在ZXing项目中直接导入core-2.2的Jar包是无法正常运行的,所以我们只能通过将core-2.2的源码加入到ZXing项目中来实现。下载好以上两个文件后,先解压core-2.2-sources.jar文件,解压之后的目录结构如下图所示:

                                     Android二维码功能实现_二维码

然后解压ZXing-2.2这个压缩包,里面可以看到各种平台下的ZXing项目源码,我们进入到android文件夹的src目录下,将core-2.2-sources中的源码拷贝进来。拷贝之后android文件夹下的目录结构如下图所示:

                           Android二维码功能实现_二维码扫描_02

这样准备工作已经完成了,现在我们新建一个Android项目ScannerTest,项目使用Android 4.0的API。

然后将上图中src目录下的所有文件全部复制,粘贴到我们ScannerTest项目的src目录下,完成后目录结构如下图所示:

                            Android二维码功能实现_二维码扫描_03

拷贝完了代码,现在该拷贝资源了,展开ZXing项目android文件夹下的res目录,将drawable文件夹、layout文件夹、menu文件夹、raw文件夹、values文件夹以及xml文件夹中的内容都拷贝到ScannerTest项目的res目录下,注意有冲突的部分要小心解决,比如两个values文件夹中都有string.xml文件,要将它们的内容进行合并,不能只是简单地覆盖。

然后我们还需要将AndroidManifest中的内容进行合并,注意ZXing Android项目下的AndroidManifest在声明Activity时用的都是简写,而现在由于项目包名变了,再使用简写会出现找不到活动的情况,因此所有的简写都要改成完整类名,例如.CaptureActivity要改成com.google.zxing.client.android.CaptureActivity。另外ZXing Android项目下的主活动是CaptureActivity,这里我们需要将主活动的声明删除掉,因为ScannerTest项目中主活动是MainActivity。合并后的AndroidManifest中的代码如下所示:




[html]​view plain​ ​​​copy​​​​print​​​​?​


  1. <?xmlversion="1.0"encoding="utf-8"?> 
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     package="com.example.scannertest" 
  4.     android:versionCode="1" 
  5.     android:versionName="1.0"> 
  6.  
  7.     <uses-permissionandroid:name="android.permission.CAMERA"/> 
  8.     <uses-permissionandroid:name="android.permission.INTERNET"/> 
  9.     <uses-permissionandroid:name="android.permission.VIBRATE"/> 
  10.     <uses-permissionandroid:name="android.permission.FLASHLIGHT"/> 
  11.     <uses-permissionandroid:name="android.permission.READ_CONTACTS"/> 
  12.     <uses-permissionandroid:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"/> 
  13.     <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
  14.     <uses-permissionandroid:name="android.permission.CHANGE_WIFI_STATE"/> 
  15.     <uses-permissionandroid:name="android.permission.ACCESS_WIFI_STATE"/> 
  16.  
  17.     <uses-sdk 
  18.         android:minSdkVersion="14" 
  19.         android:targetSdkVersion="17"/> 
  20.  
  21.     <uses-feature 
  22.         android:name="android.hardware.camera" 
  23.         android:required="false"/> 
  24.     <uses-feature 
  25.         android:name="android.hardware.camera.front" 
  26.         android:required="false"/> 
  27.     <uses-feature 
  28.         android:name="android.hardware.camera.autofocus" 
  29.         android:required="false"/> 
  30.     <uses-feature 
  31.         android:name="android.hardware.camera.flash" 
  32.         android:required="false"/> 
  33.     <uses-featureandroid:name="android.hardware.screen.landscape"/> 
  34.     <uses-feature 
  35.         android:name="android.hardware.wifi" 
  36.         android:required="false"/> 
  37.     <uses-featureandroid:name="android.hardware.touchscreen"/> 
  38.  
  39.     <supports-screens 
  40.         android:anyDensity="true" 
  41.         android:largeScreens="true" 
  42.         android:normalScreens="true" 
  43.         android:smallScreens="true" 
  44.         android:xlargeScreens="true"/> 
  45.  
  46.     <application 
  47.         android:allowBackup="true" 
  48.         android:icon="@drawable/ic_launcher" 
  49.         android:label="@string/app_name" 
  50.         android:theme="@style/AppTheme"> 
  51.         <activity 
  52.             android:name="com.example.scannertest.MainActivity" 
  53.             android:label="@string/app_name"> 
  54.             <intent-filter> 
  55.                 <actionandroid:name="android.intent.action.MAIN"/> 
  56.  
  57.                 <categoryandroid:name="android.intent.category.LAUNCHER"/> 
  58.             </intent-filter> 
  59.         </activity> 
  60.         <activity 
  61.             android:name="com.google.zxing.client.android.CaptureActivity" 
  62.             android:clearTaskOnLaunch="true" 
  63.             android:configChanges="orientation|keyboardHidden" 
  64.             android:screenOrientation="landscape" 
  65.             android:stateNotNeeded="true" 
  66.             android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 
  67.             android:windowSoftInputMode="stateAlwaysHidden"> 
  68.             <intent-filter> 
  69.                 <actionandroid:name="com.google.zxing.client.android.SCAN"/> 
  70.                 <categoryandroid:name="android.intent.category.DEFAULT"/> 
  71.             </intent-filter> 
  72.             <intent-filter> 
  73.                 <actionandroid:name="android.intent.action.VIEW"/> 
  74.                 <categoryandroid:name="android.intent.category.DEFAULT"/> 
  75.                 <categoryandroid:name="android.intent.category.BROWSABLE"/> 
  76.                 <data 
  77.                     android:host="zxing.appspot.com" 
  78.                     android:path="/scan" 
  79.                     android:scheme="http"/> 
  80.             </intent-filter> 
  81.             <intent-filter> 
  82.                 <actionandroid:name="android.intent.action.VIEW"/> 
  83.                 <categoryandroid:name="android.intent.category.DEFAULT"/> 
  84.                 <categoryandroid:name="android.intent.category.BROWSABLE"/> 
  85.                 <data 
  86.                     android:host="www.google.com" 
  87.                     android:path="/m/products/scan" 
  88.                     android:scheme="http"/> 
  89.             </intent-filter> 
  90.             <intent-filter> 
  91.                 <actionandroid:name="android.intent.action.VIEW"/> 
  92.                 <categoryandroid:name="android.intent.category.DEFAULT"/> 
  93.                 <categoryandroid:name="android.intent.category.BROWSABLE"/> 
  94.                 <data 
  95.                     android:host="www.google.co.uk" 
  96.                     android:path="/m/products/scan" 
  97.                     android:scheme="http"/> 
  98.             </intent-filter> 
  99.             <intent-filter> 
  100.                 <actionandroid:name="android.intent.action.VIEW"/> 
  101.                 <categoryandroid:name="android.intent.category.DEFAULT"/> 
  102.                 <categoryandroid:name="android.intent.category.BROWSABLE"/> 
  103.                 <data 
  104.                     android:host="scan" 
  105.                     android:path="/" 
  106.                     android:scheme="zxing"/> 
  107.             </intent-filter> 
  108.         </activity> 
  109.         <activity 
  110.             android:name="com.google.zxing.client.android.PreferencesActivity" 
  111.             android:label="@string/preferences_name" 
  112.             android:stateNotNeeded="true"> 
  113.         </activity> 
  114.         <activity 
  115.             android:name="com.google.zxing.client.android.encode.EncodeActivity" 
  116.             android:stateNotNeeded="true"> 
  117.             <intent-filter> 
  118.                 <actionandroid:name="com.google.zxing.client.android.ENCODE"/> 
  119.                 <categoryandroid:name="android.intent.category.DEFAULT"/> 
  120.             </intent-filter> 
  121.             <intent-filter> 
  122.                 <actionandroid:name="android.intent.action.SEND"/> 
  123.                 <categoryandroid:name="android.intent.category.DEFAULT"/> 
  124.                 <dataandroid:mimeType="text/x-vcard"/> 
  125.             </intent-filter> 
  126.             <intent-filter> 
  127.                 <actionandroid:name="android.intent.action.SEND"/> 
  128.                 <categoryandroid:name="android.intent.category.DEFAULT"/> 
  129.                 <dataandroid:mimeType="text/plain"/> 
  130.             </intent-filter> 
  131.         </activity> 
  132.         <activity 
  133.             android:name="com.google.zxing.client.android.book.SearchBookContentsActivity" 
  134.             android:configChanges="orientation|keyboardHidden" 
  135.             android:label="@string/sbc_name" 
  136.             android:screenOrientation="landscape" 
  137.             android:stateNotNeeded="true"> 
  138.             <intent-filter> 
  139.                 <actionandroid:name="com.google.zxing.client.android.SEARCH_BOOK_CONTENTS"/> 
  140.                 <categoryandroid:name="android.intent.category.DEFAULT"/> 
  141.             </intent-filter> 
  142.         </activity> 
  143.         <activity 
  144.             android:name="com.google.zxing.client.android.share.ShareActivity" 
  145.             android:screenOrientation="user" 
  146.             android:stateNotNeeded="true" 
  147.             android:theme="@android:style/Theme.Light"> 
  148.             <intent-filter> 
  149.                 <actionandroid:name="com.google.zxing.client.android.SHARE"/> 
  150.                 <categoryandroid:name="android.intent.category.DEFAULT"/> 
  151.             </intent-filter> 
  152.         </activity> 
  153.         <activity 
  154.             android:name="com.google.zxing.client.android.history.HistoryActivity" 
  155.             android:label="@string/history_title" 
  156.             android:stateNotNeeded="true"> 
  157.             <intent-filter> 
  158.                 <actionandroid:name="android.intent.action.VIEW"/> 
  159.                 <categoryandroid:name="android.intent.category.DEFAULT"/> 
  160.             </intent-filter> 
  161.         </activity> 
  162.         <activity 
  163.             android:name="com.google.zxing.client.android.share.BookmarkPickerActivity" 
  164.             android:label="@string/bookmark_picker_name" 
  165.             android:stateNotNeeded="true"> 
  166.             <intent-filter> 
  167.                 <actionandroid:name="android.intent.action.PICK"/> 
  168.                 <categoryandroid:name="android.intent.category.DEFAULT"/> 
  169.             </intent-filter> 
  170.         </activity> 
  171.         <activity 
  172.             android:name="com.google.zxing.client.android.share.AppPickerActivity" 
  173.             android:configChanges="orientation" 
  174.             android:label="@string/app_picker_name" 
  175.             android:stateNotNeeded="true"> 
  176.             <intent-filter> 
  177.                 <actionandroid:name="android.intent.action.PICK"/> 
  178.                 <categoryandroid:name="android.intent.category.DEFAULT"/> 
  179.             </intent-filter> 
  180.         </activity> 
  181.         <activity 
  182.             android:name="com.google.zxing.client.android.HelpActivity" 
  183.             android:screenOrientation="user"> 
  184.             <intent-filter> 
  185.                 <actionandroid:name="android.intent.action.VIEW"/> 
  186.                 <categoryandroid:name="android.intent.category.DEFAULT"/> 
  187.             </intent-filter> 
  188.         </activity> 
  189.     </application> 
  190.  
  191. </manifest> 
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.scannertest"
android:versionCode="1"
android:versionName="1.0" >

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="17" />

<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-feature
android:name="android.hardware.camera.front"
android:required="false" />
<uses-feature
android:name="android.hardware.camera.autofocus"
android:required="false" />
<uses-feature
android:name="android.hardware.camera.flash"
android:required="false" />
<uses-feature android:name="android.hardware.screen.landscape" />
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" />

<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:xlargeScreens="true" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.scannertest.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.google.zxing.client.android.CaptureActivity"
android:clearTaskOnLaunch="true"
android:configChanges="orientation|keyboardHidden"
android:screenOrientation="landscape"
android:stateNotNeeded="true"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:windowSoftInputMode="stateAlwaysHidden" >
<intent-filter>
<action android:name="com.google.zxing.client.android.SCAN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="zxing.appspot.com"
android:path="/scan"
android:scheme="http" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="www.google.com"
android:path="/m/products/scan"
android:scheme="http" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="www.google.co.uk"
android:path="/m/products/scan"
android:scheme="http" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="scan"
android:path="/"
android:scheme="zxing" />
</intent-filter>
</activity>
<activity
android:name="com.google.zxing.client.android.PreferencesActivity"
android:label="@string/preferences_name"
android:stateNotNeeded="true" >
</activity>
<activity
android:name="com.google.zxing.client.android.encode.EncodeActivity"
android:stateNotNeeded="true" >
<intent-filter>
<action android:name="com.google.zxing.client.android.ENCODE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/x-vcard" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity
android:name="com.google.zxing.client.android.book.SearchBookContentsActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/sbc_name"
android:screenOrientation="landscape"
android:stateNotNeeded="true" >
<intent-filter>
<action android:name="com.google.zxing.client.android.SEARCH_BOOK_CONTENTS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="com.google.zxing.client.android.share.ShareActivity"
android:screenOrientation="user"
android:stateNotNeeded="true"
android:theme="@android:style/Theme.Light" >
<intent-filter>
<action android:name="com.google.zxing.client.android.SHARE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="com.google.zxing.client.android.history.HistoryActivity"
android:label="@string/history_title"
android:stateNotNeeded="true" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="com.google.zxing.client.android.share.BookmarkPickerActivity"
android:label="@string/bookmark_picker_name"
android:stateNotNeeded="true" >
<intent-filter>
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="com.google.zxing.client.android.share.AppPickerActivity"
android:configChanges="orientation"
android:label="@string/app_picker_name"
android:stateNotNeeded="true" >
<intent-filter>
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="com.google.zxing.client.android.HelpActivity"
android:screenOrientation="user" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>

</manifest>

完成到这一步之后,你会发现项目中还是有很多的错误。不用担心,剩下的错误全部都是由于找不到R文件所造成的。这是因为ZXing项目中所引用的R文件都是com.google.zxing.client.android包下的R,而现在我们拷贝到ScannerTest项目之后,应该引用com.example.scannertest包下的R文件。我们需要将有错误的文件一个个地修改过来,虽然工作量不少,但都是傻瓜式操作,只要大家有耐心,就一定可以完成。

现在ScannerTest项目中应该已经没有任何错误了,然后我们还需要对ZXing的代码进行稍微的定制。

打开CaptureActivity,这个类就是用于扫描二维码的最主要的一个类,其中有一个handleDecode()方法,当二维码扫描完成之后会把结果回调到这个方法中,我们现在不想使用默认的处理方式,于是修改handleDecode()中的代码,如下所示:




[java]​view plain​ ​​​copy​​​​print​​​​?​


  1. public void handleDecode(Result rawResult, Bitmap barcode,float scaleFactor) { 
  2.     String result = rawResult.getText(); 
  3.     if (!TextUtils.isEmpty(result)) { 
  4.         Intent intent = new Intent(); 
  5.         intent.putExtra("scan_result", rawResult.getText()); 
  6.         setResult(RESULT_OK, intent); 
  7.     } else { 
  8.         setResult(RESULT_CANCELED); 
  9.     } 
  10.     finish(); 
public void handleDecode(Result rawResult, Bitmap barcode, float scaleFactor) {
String result = rawResult.getText();
if (!TextUtils.isEmpty(result)) {
Intent intent = new Intent();
intent.putExtra("scan_result", rawResult.getText());
setResult(RESULT_OK, intent);
} else {
setResult(RESULT_CANCELED);
}
finish();
}

这里我们将扫描出来的结果借助Intent进行返回。

然后打开或新建activity_main.xml文件做为ScannerTest项目的主布局,在其中添加如下代码:




[html]​view plain​ ​​​copy​​​​print​​​​?​


  1. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" 
  2.     android:layout_width="match_parent" 
  3.     android:layout_height="match_parent" 
  4.     android:orientation="vertical"> 
  5.  
  6.     <Button 
  7.         android:id="@+id/scan_button" 
  8.         android:layout_width="match_parent" 
  9.         android:layout_height="wrap_content" 
  10.         android:text="扫一扫"/> 
  11.  
  12.     <TextView 
  13.         android:id="@+id/scan_result" 
  14.         android:layout_width="wrap_content" 
  15.         android:layout_height="wrap_content"/> 
  16.  
  17. </LinearLayout> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<Button
android:id="@+id/scan_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="扫一扫" />

<TextView
android:id="@+id/scan_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</LinearLayout>

这个布局文件很简单,一个按钮用于开启二维码扫描功能,一个TextView用于显示扫描结果。

最后打开或新建MainActivity做为ScannerTest项目的主Activity,代码如下所示:




[java]​view plain​ ​​​copy​​​​print​​​​?​


  1. public class MainActivityextends Activity { 
  2.  
  3.     public staticfinal int SCAN_CODE =1; 
  4.  
  5.     @Override 
  6.     protected void onCreate(Bundle savedInstanceState) { 
  7.         super.onCreate(savedInstanceState); 
  8.         setContentView(R.layout.activity_main); 
  9.         Button button = (Button) findViewById(R.id.scan_button); 
  10.         button.setOnClickListener(new OnClickListener() { 
  11.             @Override 
  12.             public void onClick(View v) { 
  13.                 Intent intent = new Intent(MainActivity.this, CaptureActivity.class); 
  14.                 startActivityForResult(intent, SCAN_CODE); 
  15.             } 
  16.         }); 
  17.     } 
  18.  
  19.     @Override 
  20.     protected void onActivityResult(int requestCode,int resultCode, Intent data) { 
  21.         switch (requestCode) { 
  22.         case SCAN_CODE: 
  23.             TextView scanResult = (TextView) findViewById(R.id.scan_result); 
  24.             if (resultCode == RESULT_OK) { 
  25.                 String result = data.getStringExtra("scan_result"); 
  26.                 scanResult.setText(result); 
  27.             } else if (resultCode == RESULT_CANCELED) { 
  28.                 scanResult.setText("扫描出错"); 
  29.             } 
  30.             break; 
  31.         default: 
  32.             break; 
  33.         } 
  34.     } 
  35.  
public class MainActivity extends Activity {

public static final int SCAN_CODE = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.scan_button);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, CaptureActivity.class);
startActivityForResult(intent, SCAN_CODE);
}
});
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case SCAN_CODE:
TextView scanResult = (TextView) findViewById(R.id.scan_result);
if (resultCode == RESULT_OK) {
String result = data.getStringExtra("scan_result");
scanResult.setText(result);
} else if (resultCode == RESULT_CANCELED) {
scanResult.setText("扫描出错");
}
break;
default:
break;
}
}

}

这个类也很简单,点击按钮时,我们通过startActivityForResult()方法启动CaptureActivity,开始执行二维码扫描,扫描的结果将回调到onActivityResult()方法中,然后在这个方法中取出扫描的结果,并展示在TextView上。

这样我们所有的编码工作就已经完成了,可以尝试运行一下了。首先看到程序的主界面如下图所示:

            Android二维码功能实现_ide_04

点击扫一扫后可以进行二维码扫描,见下图:

Android二维码功能实现_xml_05

扫描完成后会将结果返回到主界面,如下图所示:

            Android二维码功能实现_xml_06