*.so library from included *.jar involves UnsatisfiedLinkError

こ雲淡風輕ζ 提交于 2019-12-04 19:26:32

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

I write LibraryLoader, which:

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

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

  3. 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;
    }
        }
            }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!