【问题标题】:*.so library from included *.jar involves UnsatisfiedLinkError包含的 *.jar 中的 *.so 库涉及 UnsatisfiedLinkError
【发布时间】:2012-11-25 18:23:20
【问题描述】:

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

在应用程序的 java 类中,我加载 libnativeext.so System.loadLibrary("nativeext")。 一切都很好。 本机代码编译,libnativeext.so 放在 /libs/armeabi/ 文件夹中。 所以最终的 first.apk 文件包含 /lib/armeabi/libnativeext.so,安装在设备上并且一切正常。

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

此时 javaext.jar/libs/armeabi/ 中包含 libnativeext.so

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

但在设备上我得到:java.lang.UnsatisfiedLinkError: Couldn't load nativeext: findLibrary returned null

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

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

我在现有的 second-proj/libs/ 文件夹 armeabi 中创建并将 libnativeext.so 放入其中。

第二个项目:
/libs/armeabi/libnativeext.so
/libs/javaext.jar

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

/lib/armeabi/libnativeext.so 新的
/libs/armeabi/libnativeext.so

而且这个版本在手机上完美运行。

所以我假设,在安装过程中来自 /libs/armeabi/ 的库被忽略了,只有来自 /lib/armeabi/ 的库被安装在手机上。

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

【问题讨论】:

  • 您不应该在 jar 中分发 .so 文件 - 这就是警告存在的原因,如果您忽略它,后果自负。
  • 但是为什么呢?你可以在这里发布证明链接吗? (我在 code.google.com 上阅读了有关此警告的问题,似乎已添加此检查,因为某些开发人员在 *.jar 中分发的不是 android(而是 waindows / linux)*.so 库)。
  • 这是否意味着无法将所有必需的代码分发到一个 *.jar 库中?
  • 是的,至少没有办法做到与android eclipse插件兼容的事情。请停止尝试与工具链作斗争。

标签: android jar android-ndk shared-libraries


【解决方案1】:

如果无法将 *.so 库从包含的 *.jar 打包到最终的 *.apk 中,我会自己解决这个问题。

我写了LibraryLoader,其中:

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

  2. 如果失败,则在应用存储中加载搜索库,如果找到则使用 System.load() 加载。

  3. 如果在应用存储中没有找到库,它会找到 .apk 文件,在那里进行搜索,如果加载器找到库 - 将其复制到应用存储,然后使用 System.load() 加载它。

这里的邮政编码 - 可能对某人有帮助。

    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;
    }
        }
            }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-17
    • 2023-03-17
    相关资源
    最近更新 更多