包含* .jar的* .so库涉及UnsatisfiedLinkError [英] *.so library from included *.jar involves UnsatisfiedLinkError

查看:143
本文介绍了包含* .jar的* .so库涉及UnsatisfiedLinkError的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用原生共享库( libnativeext.so )编写了android应用程序。

I've wrote android app with native shared library ( libnativeext.so ).

在app中的java类中我加载 libnativeext.so
System.loadLibrary(nativeext)。
一切都很棒。
本机代码编译, libnativeext.so 位于 / libs / armeabi / 文件夹中。
所以最终的first.apk文件包含 /lib/armeabi/libnativeext.so ,在设备上安装,一切正常。

Inside java class in app I load libnativeext.so with System.loadLibrary("nativeext"). All works great. Native code compiles, and libnativeext.so places in /libs/armeabi/ folder. So final first.apk file contains /lib/armeabi/libnativeext.so, installs on device and all work ok.

然后我在 javaext.jar 中导出项目。

此时 javaext.jar 包含 libnativeext。所以 / libs / armeabi /

At this point javaext.jar contains libnativeext.so in /libs/armeabi/.

在新项目(second-proj)中,我包含 javaext。 jar 并在java构建路径中添加 javaext.jar 的路径。
项目仅使用警告构建 javaext.jar 中的本机库。
我在eclipse偏好设置中禁用警告。

In the new project (second-proj) I include javaext.jar and add path to javaext.jar in java build path. Project builds with only warning about native library in javaext.jar. I disable warning in eclipse preferences.

但在我得到的设备上:java.lang.UnsatisfiedLinkError:无法加载nativeext:findLibrary返回null

But on device I got: java.lang.UnsatisfiedLinkError: Couldn't load nativeext: findLibrary returned null

奇怪,因为second.apk里面有 /libs/armeabi/libnativeext.so 。我打电话找出手机上的文件夹 / data / data / myapp / lib / 是EMPTY!并且当然System.loadLibrary找不到 libnativeext.so

Strange, because second.apk have /libs/armeabi/libnativeext.so inside. I go to phone and figure out than folder on phone /data/data/myapp/lib/ is EMPTY! And ofcourse System.loadLibrary can't find libnativeext.so.

我找到了自己的解决方案,但它看起来很难看,我想要找到更好的方法。

I find solution for myself, but it looks very ugly, and I want to find better way.

我在现有的 second-proj / libs / 文件夹 armeabi 中创建并放置libnativeext。在里面。

I create inside existing second-proj/libs/ folder armeabi and place libnativeext.so inside.

second-proj:

/libs/armeabi/libnativeext.so

/libs/javaext.jar

second-proj:
/libs/armeabi/libnativeext.so
/libs/javaext.jar

当我构建项目时,我会查看second.apk:

When I build project, I look inside second.apk:

/lib/armeabi/libnativeext.so< - 新的

/libs/armeabi/libnativeext.so

/lib/armeabi/libnativeext.so <--- new one
/libs/armeabi/libnativeext.so

此版本在手机上运行良好。

And this version work perfect on the phone.

所以我假设,在安装期间/ libs / armeabi /中的库被忽略,并且手机上只安装了来自/ lib / armeabi /的库。

So I assume, that during installation libraries from /libs/armeabi/ is ignored, and only libraries from /lib/armeabi/ is installed on the phone.

所以问题是:如何强制apk bulder将* .so从* .jar复制到右* .apk文件夹?

So question is: How to force apk bulder to copy *.so from *.jar to right *.apk folder?

推荐答案

如果没有办法将* .so库从包含的* .jar包装到最终* .apk中,我自己解决了这个问题。

In case there are no way to pack *.so library from included *.jar into final *.apk I solve this problem for myself.

我写了LibraryLoader,其中:

I write LibraryLoader, which:


  1. 试图用System.loadLibrary()加载库。

  1. Tries to load library with System.loadLibrary().

如果失败,请在应用程序存储中加载搜索库,如果失败使用System.load()查找加载它。

If it fails, loader search library in application storage, and if find loads it with System.load().

如果在应用程序存储中找不到库,则会找到.apk文件,serch,以及加载程序找到库 - 将其复制到应用程序存储,然后使用System.load()加载它。

If no library was found in the app storage, it find .apk file, serch there, and if loader find library - copies it to app storage, then loads it with System.load().

在此处发布代码 - 可能对某人有帮助。

Post code here - may be it helps somebody.

    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.Enumeration;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipFile;

    import android.content.Context;
    import android.util.Log;

    public class SharedLibraryLoader
    {
        private static Context context;
        private static String libDir = "lib";
        private static String shortLibName;
        private static String fullLibName;

        static public boolean loadLibrary(String libName, Context ctx)
        {
    context = ctx;
    shortLibName = libName;
    fullLibName = "lib" + libName + ".so";

    try
    {
        Log.d("SharedLibraryLoader", "Trying to load library");
        System.loadLibrary(shortLibName);
        Log.d("SharedLibraryLoader", "Library was loaded from default location");
        return true;
    }
    catch(UnsatisfiedLinkError e)
    {
        Log.d("SharedLibraryLoader","Lib wasn't found at default location. Trying to find in application private storage");
        String path = null;
        path = findInAppStorage(fullLibName);
        if(path != null)
        {
            Log.d("SharedLibraryLoader","Lib was found in application private storage. Loading lib...");
            System.load(path);
            return true;
        }
        else
        {
            Log.d("SharedLibraryLoader","Lib was not found in application private storage. Trying to find in apk...");
            path = findInApkAndCopyToAppStorage(fullLibName);

            if(path != null)
            {
                Log.d("SharedLibraryLoader","Lib was found in apk and copied to application private storage. Loading lib...");
                System.load(path);
                return true;
            }
            else
            {
                Log.d("SharedLibraryLoader", "FAILED TO LOAD LIBRARY");
                return false;
            }
        }
    }
        }

        static private String findInAppStorage(String libName)
        {

    Log.d("SharedLibraryLoader","enter findInAppStorage()");
    String basePath = context.getApplicationInfo().dataDir;
    File dataDir = new File(basePath);

    String[] listFiles;
    String  lib = null;
    listFiles = dataDir.list();


    for(int i=0; i < listFiles.length; i++)
    {
        lib = findInStorage(basePath + "/" +listFiles[i], libName);

        if(lib != null)
        {
            return lib;
        }
            }

    Log.d("SharedLibraryLoader", "Lib wasn't found.");
    return null;
        }

        static private String findInStorage(String path, String nameOfLib)
        {
    File file = new File(path);
    if(file.isDirectory())
    {
        Log.d("SharedLibraryLoader","Strorage__dir: " + path + "/");
        String[]    list = file.list();
        String      target = null; 
        for(int i = 0; i < list.length; i++)
        {
            target = findInStorage(path + "/" + list[i], nameOfLib);
            if(target != null)
            {
                return target;
            }
        }
    }
    else
    {
        Log.d("SharedLibraryLoader","Strorage_file: " + path);
        if(path.contains(nameOfLib))
        {
            Log.d("SharedLibraryLoader","Lib was found in: " + path);
            return path;
        }
    }
    return null;
        }

        static private String findInApkAndCopyToAppStorage(String libName)
        {
            Log.d("SharedLibraryLoader", "Enter findInApkAndCopyToStorage()");

            // ---------------- ZIP - find path to .so  inside .apk ------------------
    String apkPath = context.getPackageResourcePath();
    Log.d("SharedLibraryLoader", String.format("Path to Package resource is: %s", apkPath));

    try
    {
        ZipFile zf = new ZipFile(apkPath);

        Enumeration<ZipEntry> zipFiles = (Enumeration<ZipEntry>) zf.entries();
        ZipEntry    soZipEntry = null;
        ZipEntry    tempZipEntry;
        String      tmpString;
        for ( ; zipFiles.hasMoreElements();)
        {
            tempZipEntry = zipFiles.nextElement(); 
            tmpString = tempZipEntry.getName();

            if(tmpString.contains(libName))
            {
                Log.d("SharedLibraryLoader", "Library " + fullLibName + " was found in: " + tmpString);
                soZipEntry = tempZipEntry;
            }
        }

        //----------now copy library---------------
        Log.d("SharedLibraryLoader", "soZipEntry = " + soZipEntry.toString());

        if(soZipEntry != null)
        {
            InputStream soInputStream = zf.getInputStream(soZipEntry);

            File fileDir;
            File soFile;
            OutputStream outStream;
            fileDir = context.getApplicationContext().getDir(libDir, Context.MODE_PRIVATE); // but "app_lib" was created!
            String fullSoFilePath = fileDir.getAbsolutePath() + "/" + libName;
            Log.d("SharedLibraryLoader", "New libpath is "+ fullSoFilePath);
            soFile = new File(fullSoFilePath);

            Log.d("SharedLibraryLoader", "Is file already exists? - " + soFile.exists());

            outStream = new BufferedOutputStream(new FileOutputStream(soFile));

            Log.d("SharedLibraryLoader", "Start copying library...");
            byte[] byteArray = new byte[256];
            int copiedBytes = 0;

            while((copiedBytes = soInputStream.read(byteArray)) != -1)
            {
                outStream.write(byteArray, 0, copiedBytes);
            }

            Log.d("SharedLibraryLoader", "Finish copying library");
            outStream.close();

            soInputStream.close();
            return fullSoFilePath;
        }
        else
        {
            Log.d("SharedLibraryLoader", "Library not Found in APK");
            return null;
        }
    }
    catch (IOException e)
    {
        e.printStackTrace();
        return null;
    }
        }
            }

这篇关于包含* .jar的* .so库涉及UnsatisfiedLinkError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆