Integrating the ZXing library directly into my Android application

159,085

Solution 1

UPDATE! - SOLVED + GUIDE

I've managed to figure it out :) And down below you can read step-by-step guide so it hopefully can help others with the same problem as I had ;)

  1. Install Apache Ant - (See this YouTube video for config help)
  2. Download the ZXing source from ZXing homepage and extract it
  3. With the use of Windows Commandline (Run->CMD) navigate to the root directory of the downloaded zxing src.
  4. In the commandline window - Type ant -f core/build.xml press enter and let Apache work it's magic [having issues?]
  5. Enter Eclipse -> new Android Project, based on the android folder in the directory you just extracted
  6. Right-click project folder -> Properties -> Java Build Path -> Library -> Add External JARs...
  7. Navigate to the newly extracted folder and open the core directory and select core.jar ... hit enter!

Now you just have to correct a few errors in the translations and the AndroidManifest.xml file :) Now you can happily compile, and you will now have a working standalone barcode scanner app, based on the ZXing source ;)

Happy coding guys - I hope it can help others :)

Solution 2

Here is a step-by-step guide on how to generate and display QR code using ZXing library without having to install the third-party application. Note: you don't have to build ZXing with ANT or any other build tool. The file core.jar is available in the released zip archive (read below).

  1. Download the latest release of ZXing. -- (ZXing-*.zip)
  2. Extract this zip archive and find core.jar under core/ directory.
  3. If you are using Eclipse IDE, drag and drop core.jar to the libs directory of your Android project. When asked, select Copy.
  4. Copy the two classes given below (Contents.java & QRCodeEncoder.java) to the main package of your Android project.
  5. Create an ImageView item in your Activity to display the generated QR code in if you don't have one already. An example is given below:
  6. Use the code snippet below to generate the QR code in Bitmap format and display it in an ImageView.

Here is an ImageView element to add to your Activity layout XML file:

<ImageView 
    android:id="@+id/qrCode"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="50dp"
    android:layout_centerHorizontal="true"/>

Code snippet:

// ImageView to display the QR code in.  This should be defined in 
// your Activity's XML layout file
ImageView imageView = (ImageView) findViewById(R.id.qrCode);

String qrData = "Data I want to encode in QR code";
int qrCodeDimention = 500;

QRCodeEncoder qrCodeEncoder = new QRCodeEncoder(qrData, null,
        Contents.Type.TEXT, BarcodeFormat.QR_CODE.toString(), qrCodeDimention);

try {
    Bitmap bitmap = qrCodeEncoder.encodeAsBitmap();
    imageView.setImageBitmap(bitmap);
} catch (WriterException e) {
    e.printStackTrace();
}

Here is Contents.java

//
// * Copyright (C) 2008 ZXing authors
// * 
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// * 
// * http://www.apache.org/licenses/LICENSE-2.0
// * 
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// 

import android.provider.ContactsContract;

public final class Contents {
    private Contents() {
    }

    public static final class Type {

     // Plain text. Use Intent.putExtra(DATA, string). This can be used for URLs too, but string
     // must include "http://" or "https://".
        public static final String TEXT = "TEXT_TYPE";

        // An email type. Use Intent.putExtra(DATA, string) where string is the email address.
        public static final String EMAIL = "EMAIL_TYPE";

        // Use Intent.putExtra(DATA, string) where string is the phone number to call.
        public static final String PHONE = "PHONE_TYPE";

        // An SMS type. Use Intent.putExtra(DATA, string) where string is the number to SMS.
        public static final String SMS = "SMS_TYPE";

        public static final String CONTACT = "CONTACT_TYPE";

        public static final String LOCATION = "LOCATION_TYPE";

        private Type() {
        }
    }

    public static final String URL_KEY = "URL_KEY";

    public static final String NOTE_KEY = "NOTE_KEY";

    // When using Type.CONTACT, these arrays provide the keys for adding or retrieving multiple phone numbers and addresses.
    public static final String[] PHONE_KEYS = {
            ContactsContract.Intents.Insert.PHONE, ContactsContract.Intents.Insert.SECONDARY_PHONE,
            ContactsContract.Intents.Insert.TERTIARY_PHONE
    };

    public static final String[] PHONE_TYPE_KEYS = {
            ContactsContract.Intents.Insert.PHONE_TYPE,
            ContactsContract.Intents.Insert.SECONDARY_PHONE_TYPE,
            ContactsContract.Intents.Insert.TERTIARY_PHONE_TYPE
    };

    public static final String[] EMAIL_KEYS = {
            ContactsContract.Intents.Insert.EMAIL, ContactsContract.Intents.Insert.SECONDARY_EMAIL,
            ContactsContract.Intents.Insert.TERTIARY_EMAIL
    };

    public static final String[] EMAIL_TYPE_KEYS = {
            ContactsContract.Intents.Insert.EMAIL_TYPE,
            ContactsContract.Intents.Insert.SECONDARY_EMAIL_TYPE,
            ContactsContract.Intents.Insert.TERTIARY_EMAIL_TYPE
    };
}

And QRCodeEncoder.java

/*
 * Copyright (C) 2008 ZXing authors
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import android.provider.ContactsContract;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.telephony.PhoneNumberUtils;

import java.util.Collection;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.Map;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;

public final class QRCodeEncoder {
    private static final int WHITE = 0xFFFFFFFF;
    private static final int BLACK = 0xFF000000;

    private int dimension = Integer.MIN_VALUE;
    private String contents = null;
    private String displayContents = null;
    private String title = null;
    private BarcodeFormat format = null;
    private boolean encoded = false;

    public QRCodeEncoder(String data, Bundle bundle, String type, String format, int dimension) {
        this.dimension = dimension;
        encoded = encodeContents(data, bundle, type, format);
    }

    public String getContents() {
        return contents;
    }

    public String getDisplayContents() {
        return displayContents;
    }

    public String getTitle() {
        return title;
    }

    private boolean encodeContents(String data, Bundle bundle, String type, String formatString) {
        // Default to QR_CODE if no format given.
        format = null;
        if (formatString != null) {
            try {
                format = BarcodeFormat.valueOf(formatString);
            } catch (IllegalArgumentException iae) {
                // Ignore it then
            }
        }
        if (format == null || format == BarcodeFormat.QR_CODE) {
            this.format = BarcodeFormat.QR_CODE;
            encodeQRCodeContents(data, bundle, type);
        } else if (data != null && data.length() > 0) {
            contents = data;
            displayContents = data;
            title = "Text";
        }
        return contents != null && contents.length() > 0;
    }

    private void encodeQRCodeContents(String data, Bundle bundle, String type) {
        if (type.equals(Contents.Type.TEXT)) {
            if (data != null && data.length() > 0) {
                contents = data;
                displayContents = data;
                title = "Text";
            }
        } else if (type.equals(Contents.Type.EMAIL)) {
            data = trim(data);
            if (data != null) {
                contents = "mailto:" + data;
                displayContents = data;
                title = "E-Mail";
            }
        } else if (type.equals(Contents.Type.PHONE)) {
            data = trim(data);
            if (data != null) {
                contents = "tel:" + data;
                displayContents = PhoneNumberUtils.formatNumber(data);
                title = "Phone";
            }
        } else if (type.equals(Contents.Type.SMS)) {
            data = trim(data);
            if (data != null) {
                contents = "sms:" + data;
                displayContents = PhoneNumberUtils.formatNumber(data);
                title = "SMS";
            }
        } else if (type.equals(Contents.Type.CONTACT)) {
            if (bundle != null) {
                StringBuilder newContents = new StringBuilder(100);
                StringBuilder newDisplayContents = new StringBuilder(100);

                newContents.append("MECARD:");

                String name = trim(bundle.getString(ContactsContract.Intents.Insert.NAME));
                if (name != null) {
                    newContents.append("N:").append(escapeMECARD(name)).append(';');
                    newDisplayContents.append(name);
                }

                String address = trim(bundle.getString(ContactsContract.Intents.Insert.POSTAL));
                if (address != null) {
                    newContents.append("ADR:").append(escapeMECARD(address)).append(';');
                    newDisplayContents.append('\n').append(address);
                }

                Collection<String> uniquePhones = new HashSet<String>(Contents.PHONE_KEYS.length);
                for (int x = 0; x < Contents.PHONE_KEYS.length; x++) {
                    String phone = trim(bundle.getString(Contents.PHONE_KEYS[x]));
                    if (phone != null) {
                        uniquePhones.add(phone);
                    }
                }
                for (String phone : uniquePhones) {
                    newContents.append("TEL:").append(escapeMECARD(phone)).append(';');
                    newDisplayContents.append('\n').append(PhoneNumberUtils.formatNumber(phone));
                }

                Collection<String> uniqueEmails = new HashSet<String>(Contents.EMAIL_KEYS.length);
                for (int x = 0; x < Contents.EMAIL_KEYS.length; x++) {
                    String email = trim(bundle.getString(Contents.EMAIL_KEYS[x]));
                    if (email != null) {
                        uniqueEmails.add(email);
                    }
                }
                for (String email : uniqueEmails) {
                    newContents.append("EMAIL:").append(escapeMECARD(email)).append(';');
                    newDisplayContents.append('\n').append(email);
                }

                String url = trim(bundle.getString(Contents.URL_KEY));
                if (url != null) {
                    // escapeMECARD(url) -> wrong escape e.g. http\://zxing.google.com
                    newContents.append("URL:").append(url).append(';');
                    newDisplayContents.append('\n').append(url);
                }

                String note = trim(bundle.getString(Contents.NOTE_KEY));
                if (note != null) {
                    newContents.append("NOTE:").append(escapeMECARD(note)).append(';');
                    newDisplayContents.append('\n').append(note);
                }

                // Make sure we've encoded at least one field.
                if (newDisplayContents.length() > 0) {
                    newContents.append(';');
                    contents = newContents.toString();
                    displayContents = newDisplayContents.toString();
                    title = "Contact";
                } else {
                    contents = null;
                    displayContents = null;
                }

            }
        } else if (type.equals(Contents.Type.LOCATION)) {
            if (bundle != null) {
                // These must use Bundle.getFloat(), not getDouble(), it's part of the API.
                float latitude = bundle.getFloat("LAT", Float.MAX_VALUE);
                float longitude = bundle.getFloat("LONG", Float.MAX_VALUE);
                if (latitude != Float.MAX_VALUE && longitude != Float.MAX_VALUE) {
                    contents = "geo:" + latitude + ',' + longitude;
                    displayContents = latitude + "," + longitude;
                    title = "Location";
                }
            }
        }
    }

    public Bitmap encodeAsBitmap() throws WriterException {
        if (!encoded) return null;

        Map<EncodeHintType, Object> hints = null;
        String encoding = guessAppropriateEncoding(contents);
        if (encoding != null) {
            hints = new EnumMap<EncodeHintType, Object>(EncodeHintType.class);
            hints.put(EncodeHintType.CHARACTER_SET, encoding);
        }
        MultiFormatWriter writer = new MultiFormatWriter();
        BitMatrix result = writer.encode(contents, format, dimension, dimension, hints);
        int width = result.getWidth();
        int height = result.getHeight();
        int[] pixels = new int[width * height];
        // All are 0, or black, by default
        for (int y = 0; y < height; y++) {
            int offset = y * width;
            for (int x = 0; x < width; x++) {
                pixels[offset + x] = result.get(x, y) ? BLACK : WHITE;
            }
        }

        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
        return bitmap;
    }

    private static String guessAppropriateEncoding(CharSequence contents) {
        // Very crude at the moment
        for (int i = 0; i < contents.length(); i++) {
            if (contents.charAt(i) > 0xFF) { return "UTF-8"; }
        }
        return null;
    }

    private static String trim(String s) {
        if (s == null) { return null; }
        String result = s.trim();
        return result.length() == 0 ? null : result;
    }

    private static String escapeMECARD(String input) {
        if (input == null || (input.indexOf(':') < 0 && input.indexOf(';') < 0)) { return input; }
        int length = input.length();
        StringBuilder result = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            char c = input.charAt(i);
            if (c == ':' || c == ';') {
                result.append('\\');
            }
            result.append(c);
        }
        return result.toString();
    }
}

Solution 3

The

compile 'com.google.zxing:core:2.3.0'

unfortunately didn't work for me.

This is what worked for me:

dependencies {
   compile 'com.journeyapps:zxing-android-embedded:3.0.1@aar'
   compile 'com.google.zxing:core:3.2.0'
}

Please find the link here: https://github.com/journeyapps/zxing-android-embedded

Solution 4

Since some of the answers are outdated, I would like to provide my own -

To integrate ZXing library into your Android app as suggested by their Wiki, you need to add 2 Java files to your project:

Then in Android Studio add the following line to build.gradle file:

dependencies {
    ....
    compile 'com.google.zxing:core:3.2.1'
}

Or if still using Eclipse with ADT-plugin add core.jar file to the libs subdirectory of your project (here fullscreen Windows and fullscreen Mac):

Windows screenshot

Finally add this code to your MainActivity.java:

public void scanQRCode(View v) {
    IntentIntegrator integrator = new IntentIntegrator(MainActivity.this);
    integrator.initiateScan(IntentIntegrator.QR_CODE_TYPES);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
    IntentResult result = 
        IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
    if (result != null) {
        String contents = result.getContents();
        if (contents != null) {
            showDialog(R.string.result_succeeded, result.toString());
        } else {
            showDialog(R.string.result_failed,
                getString(R.string.result_failed_why));
        }
    }
}

private void showDialog(int title, CharSequence message) {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(title);
    builder.setMessage(message);
    builder.setPositiveButton(R.string.ok_button, null);
    builder.show();
}

The resulting app will ask to install and start Barcode Scanner app by ZXing (which will return to your app automatically after scanning):

Barcode Scanner app

Additionally, if you would like to build and run the ZXing Test app as inspiration for your own app:

ZXing Test app

Then you need 4 Java files from GitHub:

  • BenchmarkActivity.java
  • BenchmarkAsyncTask.java
  • BenchmarkItem.java
  • ZXingTestActivity.java

And 3 Jar files from Maven repository:

  • core.jar
  • android-core.jar
  • android-integration.jar

(You can build the Jar files yourself with mvn package - if your check out ZXing from GitHub and install ant and maven tools at your computer).

Note: if your project does not recognize the Jar files, you might need to up the Java version in the Project Properties:

properties screenshot

Solution 5

Having issues building with ANT? Keep reading

If ant -f core/build.xml says something like:

Unable to locate tools.jar. Expected to find it in
C:\Program Files\Java\jre6\lib\tools.jar

then set your JAVA_HOME environment variable to the proper java folder. I found tools.jar in my (for Windows):

C:\Program Files\Java\jdk1.6.0_21\lib

so I set my JAVA_HOME to:

C:\Progra~1\Java\jdk1.6.0_25

the reason for the shorter syntax I found at some site which says:

"It is strongly advised that you choose an installation directory that does not include spaces in the path name (e.g., do NOT install in C:\Program Files). If Java is installed in such a directory, it is critical to set the JAVA_HOME environment variable to a path that does not include spaces (e.g., C:\Progra~1); failure to do this will result in exceptions thrown by some programs that depend on the value of JAVA_HOME."

I then relaunched cmd (important because DOS shell only reads env vars upon launching, so changing an env var will require you to use a new shell to get the updated value)

and finally the ant -f core/build.xml worked.

Share:
159,085
AppDev
Author by

AppDev

I've used StackOverflow a few times (actual only from google hits). I've sign up because i've grown quite fond of the site, and hopefully i can (in time) contribute to the forum so others can benefit from my ever expanding knowledge ;) Best regards, from Denmark.

Updated on April 17, 2020

Comments

  • AppDev
    AppDev about 4 years

    I'm writing this in mere desperation :) I've been assigned to make a standalone barcode scanner (as a proof of concept) to an Android 1.6 phone.

    For this i've discovered the ZXing library.

    I've googled, read related topics here on StackOverflow used common sence and so forth. Nothing seemed to have helped, and i just can't punch a hole on this mentale blockade :/

    I know it to be possible, to use the lib, and create your own standalone barcode scanner. I've read that using the "Barcode Scanner" provided by the Zxing folks, is by far the easiest solution (via Intent). Unfortunately this is not an option, and a standalone app is desired.

    So to sum up my problem :

    1. How to integrate ZXing source lib into my Android Code project through Eclipse?
    2. When integrated ... how to make use of the lib, to "load" the scanning function?
    3. A step to step guide is almost prefered because i just started working in Eclipse.

    I've tried to make my code project dependant of the Android folder from the ZXing source folder. When i do so, a handfull errors emerge, mostly concerning 'org.apache' (??)

    I just can't figure it out ... so a few hints would be most helpfull.

    In advance, thank you :)

  • AppDev
    AppDev over 13 years
    Sorry ... it was not quite the help i was looking for :) But today i had a breakthrough :P I managed to figure it out myself ;) A guide for other viewers, with the same problem, will be posted shotly :)
  • Mindey I.
    Mindey I. almost 13 years
    Great writeup! Can you add some detail on what you edited in the AndroidManifest.xml file? I don't see any errors in that file upon examination. Thanks!
  • Sean Owen
    Sean Owen almost 13 years
    There aren't errors in the AndroidManifest.xml file, nor the translations. There are compatibility problems in the latest Android SDK, however. If you use it you have to use later source code from SVN.
  • kumar
    kumar almost 13 years
    Hi, I was trying to develop another application for QR scanning as a standalone app without using any QR Droid or Barcode Scanner app. Are the steps you mentioned for doing just that or you still are using some other app via intents or anything?
  • Mario Fraiß
    Mario Fraiß about 12 years
    These steps are doing just that. I currently work on a solution to integrate ZXing as external library into an app.
  • Michał Klimczak
    Michał Klimczak about 12 years
    The zip package from code.google.com/p/zxing/downloads/list contains "core" directory as well as "android" and "android-integration". What is the reason why you used "core"?
  • Michał Klimczak
    Michał Klimczak about 12 years
    Alright, now i know why. If anyone wondered too, please see stackoverflow.com/questions/4854442/…
  • Shalini
    Shalini almost 12 years
    @MichałK thanks a lot. I got error for a while, now it clear by add core.jar as per your comment.
  • Admin
    Admin over 11 years
    i did the same as guided by you but now can you please tell me how to proceed furthur after making core.jar
  • Admin
    Admin over 11 years
    I use this code along with your code. Intent intent = new Intent("com.google.zxing.client.android.SCAN"); intent.putExtra("SCAN_MODE", "QR_CODE_MODE"); But it is giving me No Class Found that handle zxing
  • DiscDev
    DiscDev about 11 years
    If you are having trouble invoking the scanner or getting results back from the scanner when using this library from another project, see this question: stackoverflow.com/questions/14925276/…
  • capcom
    capcom almost 11 years
    Latest ZXing doesn't have core.jar there for some reason. I had to download 2.1 for it.
  • Nantoka
    Nantoka over 10 years
    core.jar is separately available in the Maven release repository, for version 2.2 the link is repo1.maven.org/maven2/com/google/zxing/core/2.2/core-2.2.ja‌​r
  • Dion Segijn
    Dion Segijn over 10 years
    For everyone wanting to encode EAN (barcode) instead of QR use: BarcodeFormat.EAN_13.toString() instead of BarcodeFormat.QR_CODE.toString(). And make sure your string contains 13 numbers. (Or 8 if you use EAN_8 instead of EAN_13). f.e: String qrData = "8718265745940";
  • Rui Marques
    Rui Marques over 10 years
  • KG6ZVP
    KG6ZVP over 10 years
    Your encodeAsBitmap() method returns null if unmodified or fails with a NullPointerException if I comment out the line which returns null. I'm new to this library. What am I doing wrong?
  • Shaon Hasan
    Shaon Hasan about 10 years
    @Wesam , It was really helpful. But can u also provide the code, where the reverse can be done. I mean, convert the QR code back to the String?
  • Shaon Hasan
    Shaon Hasan over 9 years
    @ErumHannan copy this class: code.google.com/p/zxing/source/browse/trunk/androidtest/src/‌​com/… and final ImageView imageView = (ImageView)findViewById(R.id.qrCodeImgVw);Bitmap btmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap();Lumina‌​nceSource source = new com.example.qrcodeproject.RGBLuminanceSource(btmap); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); Reader reader = new MultiFormatReader(); try { Result result = reader.decode(bitmap); String contents = result.getText(); }
  • Erum
    Erum over 9 years
    @ShaonHasan this code is if i provide image either in jpg/png it will read this image and will show its code right ? but either image is correct image or not it who will detect this ? either its a barcode image or not ?
  • Alexander Farber
    Alexander Farber almost 9 years
    This source code is obsolete - check my more up-to-date answer here: stackoverflow.com/questions/30515584/…
  • Paresh Mayani
    Paresh Mayani almost 9 years
    That's a fantastic answer!
  • funcoder
    funcoder almost 9 years
    Right! That's the real solution in 2015. Btw. the current version is 3.2.0
  • narancs
    narancs almost 9 years
    did this worked for anyone ? IntentIntegrator still could not be found
  • Alexander Farber
    Alexander Farber over 8 years
    You should copy the files IntentIntegrator.java and IntentResult.java manually into your Android Studio project.
  • Konstantin Konopko
    Konstantin Konopko over 8 years
    What about example of scanning QR and getting a string?
  • StarWind0
    StarWind0 over 8 years
    I am afraid this missed the point of the question :-( The point was to not rely on an external application. This shows how to.. use an external application? See in question title "directly in"
  • StarWind0
    StarWind0 over 8 years
    This answer is dwarfed by the other answers here. Most with screen shots and such. Thats a shame as this is the only answer that actually works! Pay attention to this one. What he didn't mention is the linked project is a branch where someone made this difficult library into a easy (and its actually easy) to use library. Just download the core jar from the normal ZXING project and you are good to go. Even has examples!!!!
  • StarWind0
    StarWind0 over 8 years
    I wish I could give more upvotes. You have no idea how many different times I have tried to figure this out on different projects over the years.
  • narancs
    narancs over 8 years
    I'm happy to serve guys :)
  • Lenik
    Lenik almost 8 years
    You can't install google play services in China, because Google is blocked.
  • Lenik
    Lenik almost 8 years
    If you have google play services luckily installed, you still can't use it in China, because Google is blocked.
  • Ramkesh Yadav
    Ramkesh Yadav almost 6 years
    How to get working this technique on macbook using, i've already installed apache ant and putted this path in enviornemt variable of Mac, what is the next step for android studio.Thanx.
  • kelalaka
    kelalaka about 5 years
    st_scanned_result is not defined here
  • Tara
    Tara about 5 years
    That is a global variable of type String. If you are not using scanned result out side of this onActivtyResult() then u can defined it locally. Like String st_scanned_result = result.getContents(); I have updated it plz chk.