Android Studio Couldn't Find "libiconv.so"
Asked Answered
M

2

7

I am having an issue with my barcode scanning application, the code runs perfectly until I test the Scan button, at this point it crashes, and I receive the following error:

01-28 23:15:51.314    2261-2261/com.example.sage.appp E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.sage.appp, PID: 2261
java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.sage.appp-2/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libiconv.so"
        at java.lang.Runtime.loadLibrary(Runtime.java:366)
        at java.lang.System.loadLibrary(System.java:989)
        at com.example.sage.appp.ZBarScannerActivity.<clinit>(ZBarScannerActivity.java:28)
        at java.lang.reflect.Constructor.newInstance(Native Method)
        at java.lang.Class.newInstance(Class.java:1572)
        at android.app.Instrumentation.newActivity(Instrumentation.java:1065)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2199)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
        at android.app.ActivityThread.access$800(ActivityThread.java:144)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5221)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

These are the classes I am using:

MainActivity.java

package com.example.sage.appp;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Toast;

import net.sourceforge.zbar.Symbol;


public class MainActivity extends Activity
{

private static final int ZBAR_SCANNER_REQUEST = 0;
private static final int ZBAR_QR_SCANNER_REQUEST = 1;

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
}

public void launchScanner(View v)
{
    if (isCameraAvailable())
    {
        Intent intent = new Intent(this, ZBarScannerActivity.class);
        startActivityForResult(intent, ZBAR_SCANNER_REQUEST);
    }
    else
    {
        Toast.makeText(this, "Rear Facing Camera Unavailable", Toast.LENGTH_SHORT).show();
    }
}

public void launchQRScanner(View v)
{
    if (isCameraAvailable())
    {
        Intent intent = new Intent(this, ZBarScannerActivity.class);
        intent.putExtra(ZBarConstants.SCAN_MODES, new int[]{Symbol.QRCODE});
        startActivityForResult(intent, ZBAR_SCANNER_REQUEST);
    }
    else
    {
        Toast.makeText(this, "Rear Facing Camera Unavailable", Toast.LENGTH_SHORT).show();
    }
}

public boolean isCameraAvailable()
{
    PackageManager pm = getPackageManager();
    return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    switch (requestCode)
    {
        case ZBAR_SCANNER_REQUEST:
        case ZBAR_QR_SCANNER_REQUEST:

            if (resultCode == RESULT_OK)
            {
                Toast.makeText(this, "Scan Result = " + data.getStringExtra(ZBarConstants.SCAN_RESULT), Toast.LENGTH_SHORT).show();
            }
            else if(resultCode == RESULT_CANCELED && data != null)
            {
                String error = data.getStringExtra(ZBarConstants.ERROR_INFO);
                if(!TextUtils.isEmpty(error))
                {
                    Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
                }
            }
            break;
    }
}

}

ZBarScannerActivity.java

package com.example.sage.appp;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.view.Window;
import android.view.WindowManager;
import net.sourceforge.zbar.Config;
import net.sourceforge.zbar.Image;
import net.sourceforge.zbar.ImageScanner;
import net.sourceforge.zbar.Symbol;
import net.sourceforge.zbar.SymbolSet;
public class ZBarScannerActivity extends Activity implements
Camera.PreviewCallback, ZBarConstants {
private static final String TAG = "ZBarScannerActivity";
private CameraPreview mPreview;
private Camera mCamera;
private ImageScanner mScanner;
private Handler mAutoFocusHandler;
private boolean mPreviewing = true;

static {
    System.loadLibrary("iconv");
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if(!isCameraAvailable()) {
        // Cancel request if there is no rear-facing camera.
        cancelRequest();
        return;
    }

    // Hide the window title.
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

    mAutoFocusHandler = new Handler();

    // Create and configure the ImageScanner;
    setupScanner();

    // Create a RelativeLayout container that will hold a SurfaceView,
    // and set it as the content of our activity.
    mPreview = new CameraPreview(this, this, autoFocusCB);
    setContentView(mPreview);
}

public void setupScanner() {
    mScanner = new ImageScanner();
    mScanner.setConfig(0, Config.X_DENSITY, 3);
    mScanner.setConfig(0, Config.Y_DENSITY, 3);

    int[] symbols = getIntent().getIntArrayExtra(SCAN_MODES);
    if (symbols != null) {
        mScanner.setConfig(Symbol.NONE, Config.ENABLE, 0);
        for (int symbol : symbols) {
            mScanner.setConfig(symbol, Config.ENABLE, 1);
        }
    }
}

@Override
protected void onResume() {
    super.onResume();

    // Open the default i.e. the first rear facing camera.
    mCamera = Camera.open();
    if(mCamera == null) {
        // Cancel request if mCamera is null.
        cancelRequest();
        return;
    }

    mPreview.setCamera(mCamera);
    mPreview.showSurfaceView();

    mPreviewing = true;
}

@Override
protected void onPause() {
    super.onPause();

    // Because the Camera object is a shared resource, it's very
    // important to release it when the activity is paused.
    if (mCamera != null) {
        mPreview.setCamera(null);
        mCamera.cancelAutoFocus();
        mCamera.setPreviewCallback(null);
        mCamera.stopPreview();
        mCamera.release();

        // According to Jason Kuang on https://mcmap.net/q/1494830/-how-to-recover-camera-preview-from-sleep,
        // there might be surface recreation problems when the device goes to sleep. So lets just hide it and
        // recreate on resume
        mPreview.hideSurfaceView();

        mPreviewing = false;
        mCamera = null;
    }
}

public boolean isCameraAvailable() {
    PackageManager pm = getPackageManager();
    return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA);
}

public void cancelRequest() {
    Intent dataIntent = new Intent();
    dataIntent.putExtra(ERROR_INFO, "Camera unavailable");
    setResult(Activity.RESULT_CANCELED, dataIntent);
    finish();
}

public void onPreviewFrame(byte[] data, Camera camera) {
    Camera.Parameters parameters = camera.getParameters();
    Camera.Size size = parameters.getPreviewSize();

    Image barcode = new Image(size.width, size.height, "Y800");
    barcode.setData(data);

    int result = mScanner.scanImage(barcode);

    if (result != 0) {
        mCamera.cancelAutoFocus();
        mCamera.setPreviewCallback(null);
        mCamera.stopPreview();
        mPreviewing = false;
        SymbolSet syms = mScanner.getResults();
        for (Symbol sym : syms) {
            String symData = sym.getData();
            if (!TextUtils.isEmpty(symData)) {
                Intent dataIntent = new Intent();
                dataIntent.putExtra(SCAN_RESULT, symData);
                dataIntent.putExtra(SCAN_RESULT_TYPE, sym.getType());
                setResult(Activity.RESULT_OK, dataIntent);
                finish();
                break;
            }
        }
    }
}
private Runnable doAutoFocus = new Runnable() {
    public void run() {
        if(mCamera != null && mPreviewing) {
            mCamera.autoFocus(autoFocusCB);
        }
    }
};

// Mimic continuous auto-focusing
Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
    public void onAutoFocus(boolean success, Camera camera) {
        mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
    }
};

}

CameraPreview.java

package com.example.sage.appp;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import java.io.IOException;
import java.util.List;
public class CameraPreview extends ViewGroup implements SurfaceHolder.Callback
{
 private final String TAG = "CameraPreview";

SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
PreviewCallback mPreviewCallback;
AutoFocusCallback mAutoFocusCallback;

CameraPreview(Context context, PreviewCallback previewCallback, AutoFocusCallback autoFocusCb) 
{
    super(context);

    mPreviewCallback = previewCallback;
    mAutoFocusCallback = autoFocusCb;
    mSurfaceView = new SurfaceView(context);
    addView(mSurfaceView);

    // Install a SurfaceHolder.Callback so we get notified when the
    // underlying surface is created and destroyed.
    mHolder = mSurfaceView.getHolder();
    mHolder.addCallback(this);
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

public void setCamera(Camera camera) 
{
    mCamera = camera;
    if (mCamera != null)
    {
        mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
        requestLayout();
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // We purposely disregard child measurements because act as a
    // wrapper to a SurfaceView that centers the camera preview instead
    // of stretching it.
    final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
    final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
    setMeasuredDimension(width, height);

    if (mSupportedPreviewSizes != null) {
        mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
    }
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    if (changed && getChildCount() > 0) {
        final View child = getChildAt(0);

        final int width = r - l;
        final int height = b - t;

        int previewWidth = width;
        int previewHeight = height;
        if (mPreviewSize != null) {
            previewWidth = mPreviewSize.width;
            previewHeight = mPreviewSize.height;
        }

        // Center the child SurfaceView within the parent.
        if (width * previewHeight > height * previewWidth) {
            final int scaledChildWidth = previewWidth * height / previewHeight;
            child.layout((width - scaledChildWidth) / 2, 0,
                    (width + scaledChildWidth) / 2, height);
        } else {
            final int scaledChildHeight = previewHeight * width / previewWidth;
            child.layout(0, (height - scaledChildHeight) / 2,
                    width, (height + scaledChildHeight) / 2);
        }
    }
}

public void hideSurfaceView() {
    mSurfaceView.setVisibility(View.INVISIBLE);
}

public void showSurfaceView() {
    mSurfaceView.setVisibility(View.VISIBLE);
}

public void surfaceCreated(SurfaceHolder holder) {
    // The Surface has been created, acquire the camera and tell it where
    // to draw.
    try {
        if (mCamera != null) {
            mCamera.setPreviewDisplay(holder);
        }
    } catch (IOException exception) {
        Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
    }
}

public void surfaceDestroyed(SurfaceHolder holder) {
    // Surface will be destroyed when we return, so stop the preview.
    if (mCamera != null) {
        mCamera.cancelAutoFocus();
        mCamera.stopPreview();
    }
}


private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio = (double) w / h;
    if (sizes == null) return null;

    Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    // Try to find an size match aspect ratio and size
    for (Size size : sizes) {
        double ratio = (double) size.width / size.height;
        if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
        if (Math.abs(size.height - targetHeight) < minDiff) {
            optimalSize = size;
            minDiff = Math.abs(size.height - targetHeight);
        }
    }

    // Cannot find the one match the aspect ratio, ignore the requirement
    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }
    return optimalSize;
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    if (holder.getSurface() == null){
      // preview surface does not exist
      return;
    }

    if (mCamera != null) {
        // Now that the size is known, set up the camera parameters and begin
        // the preview.
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
        requestLayout();

        mCamera.setParameters(parameters);
        mCamera.setPreviewCallback(mPreviewCallback);
        mCamera.startPreview();
        mCamera.autoFocus(mAutoFocusCallback);
    }
}

}

File Structure : https://i.sstatic.net/JoTnq.jpg

Matronymic answered 29/1, 2015 at 7:30 Comment(3)
What is libiconv.so supposed to be? (You're the one who told Android to try and load libiconv.so)Dreamworld
It's part of the ZBar library, I'm not entirely sure what it does.Matronymic
Did you manage to solve this ?Proxy
C
5

With Gradle 0.7.2+ you can put your native libraries directly into src/main/jniLibs and it will work automatically. https://mcmap.net/q/609004/-jni-folder-in-android-studio https://mcmap.net/q/661552/-how-to-change-libs-directory-in-gradle

Cymograph answered 18/3, 2015 at 22:33 Comment(1)
What if you specify jniLibs.srcDir manually in build.gradle?Hemia
P
1

Even I have faced the same problem. Use the proper library to solve this problem. Below I am giving a link it will help you. just copy the library files into your program library directory.

https://github.com/ababavali23/barcodeScanner-Libs

Pozzy answered 28/3, 2016 at 5:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.