美文网首页
插件化无法获取或找到.so文件

插件化无法获取或找到.so文件

作者: 清辉_ | 来源:发表于2021-01-13 10:16 被阅读0次

    java.lang.UnsatisfiedLinkError: dalvik.system.DexClassLoader[DexPathList[[zip file "/data/user/0/com.xxx.xxx/myfile/sdkjar.apk"],nativeLibraryDirectories=[/data/user/0/com.xxx.xxx/myfile/lib, /system/lib64, /system/product/lib64]]] couldn't find "libtobEncrypt.so"

    问题的所在因为插件化的时候没有吧so文件拷贝到/data/user/0/com.xxx.xxx/myfile/lib 文件夹下 ,注意不是/data/user/0/com.xxx.xxx/lib、而是/data/user/0/com.xxx.xxx/myfile/lib 第一个的区别在自己的lib/jinLibs目录下忘记添加so 文件了

    第二个是因为插件化问题 类加载器加载的缘故导致so读取的路径变了 变成/myfile/lib下

    这里做法都是大同小异

    直接将所缺的so文件放进assets文件夹中

    然后安转的时候将so文件拷贝到data/user/0/com.xxx.xxx/myfile/lib 目录下

    这个操作要打开应用之后判断这个目录是否存在 里面是否有对应系统架构的so文件即可

    如果遇到是拷贝文件进去 遇到没有读写权限 需要操作之前申请权限,是强制性的,

    拿到权限之后 拷贝还是失败,那是拷贝的姿势有问题了 

    解析代码如下

    ApplicationInfo info = context.getApplicationInfo();

    //1.如果解压之后有对应的包名/lib之下有so文件 先拷贝到/myfile/lib下面 改操作的好处是系统直接默认选好是使用哪个系统架构的so文件,不需要我们再另行判断哪个系统架构

            String PathOne ="/data/user/0/"+getPackageName(context)+"/lib";

    String PathA ="/data/data/"+info.packageName+"/lib";

    //上面的成功之后可以不执行下面第二部 可以判断data/user/0/com.xxx.xxx/myfile/lib/xxx.so文件是否存在 存在则不执行第二部

    //  2.如果解压之后有对应的包名/lib之下没有so文件 则再从Assets/lib对应系统架构的so文件拷贝到/myfile/lib下面 该处需要我们另行判断系统架构

            String PathTwo ="/data/user/0/"+getPackageName(context)+"/myfile/lib";

    String PathB ="/data/data/"+info.packageName+"/myfile/lib";

    Log.e("info.packageName","info.packageName=====" +info.packageName);

    Log.e("PathOne","PathOnee=====" +PathOne);

    Log.e("PathTwo","PathTwo=====" +PathTwo);

    Log.e("PathA","PathA=====" +PathA);

    Log.e("PathB","PathB=====" +PathB);

    //從assets拷貝文件到包名,,,。/data/user/0/com.gzzwyx.bzfgx.zhiwan/myfile/lib之下

            String systemArchitecture =DriverTypeUtils.getCPUABI();

    Log.d("copylibFile","2isLibc64()=======查询当前的系统架构是======="+systemArchitecture);//查詢是x64還是x86

            Log.e("allPathC"," 当前拷贝的so文件的路径为:=====" +"lib/"+systemArchitecture+"/libEncryptorP.so");

    CopySoFileToLib.copyFilesFromAssets(context,"lib/"+systemArchitecture,PathTwo);

    CopySoFileToLib.copyFilesFromAssets(context,"lib/"+systemArchitecture,PathB);

    // 获取acitivty所在的应用包名

    public static String getPackageName(Context context) {

    ApplicationInfo appInfo = context.getApplicationInfo();

    String packageName = appInfo.packageName;// 获取当前游戏安装包名

        return packageName;

    }

    //拷贝工具类

    import android.content.Context;

    import android.util.Log;

    import java.io.File;

    import java.io.FileInputStream;

    import java.io.FileNotFoundException;

    import java.io.FileOutputStream;

    import java.io.IOException;

    import java.io.InputStream;

    import java.io.OutputStream;

    public class CopySoFileToLib {

    /**

        * 复制文件夹及其中的文件 該作用主要是 /data/user/0/com.gzzwyx.bzfgx.zhiwan/huosdkv8/lib為空時 從/data/user/0/com.gzzwyx.bzfgx.zhiwan/lib處拷貝過去

        *

        * @param oldPath String 原文件夹路径 如:data/user/0/com.test/files

        * @param newPath String 复制后的路径 如:data/user/0/com.test/cache

        * @return <code>true</code>if and only if the directory and files were copied;

        * <code>false</code>otherwise

    */

        public static boolean copyFolder(String oldPath, String newPath) {

    try {

    File newFile =new File(newPath);

    if (!newFile.exists()) {

    if (!newFile.mkdirs()) {

    Log.e("--Method--","copyFolder: cannot create directory.");

    return false;

    }

    }

    File oldFile =new File(oldPath);

    String[] files = oldFile.list();

    File temp;

    for (String file : files) {

    if (oldPath.endsWith(File.separator)) {

    temp =new File(oldPath + file);

    }else {

    temp =new File(oldPath + File.separator + file);

    }

    if (temp.isDirectory()) {//如果是子文件夹

                        copyFolder(oldPath +"/" + file, newPath +"/" + file);

    }else if (!temp.exists()) {

    Log.e("--Method--","copyFolder:  oldFile not exist.");

    return false;

    }else if (!temp.isFile()) {

    Log.e("--Method--","copyFolder:  oldFile not file.");

    return false;

    }else if (!temp.canRead()) {

    Log.e("--Method--","copyFolder:  oldFile cannot read.");

    return false;

    }else {

    FileInputStream fileInputStream =new FileInputStream(temp);

    FileOutputStream fileOutputStream =new FileOutputStream(newPath +"/" + temp.getName());

    byte[] buffer =new byte[1024];

    int byteRead;

    while ((byteRead = fileInputStream.read(buffer)) != -1) {

    fileOutputStream.write(buffer,0, byteRead);

    }

    fileInputStream.close();

    fileOutputStream.flush();

    fileOutputStream.close();

    }

    }

    return true;

    }catch (Exception e) {

    e.printStackTrace();

    return false;

    }

    }

    /**

        *  从assets目录中复制整个文件夹内容到新的路径下

        *  @param  context  Context 使用CopyFiles类的Activity

        *  @param  oldPath  String  原文件路径  如:Data(assets文件夹下文件夹名称)

        *  @param  newPath  String  复制后路径  如:data/data/(手机内部存储路径名称)

        */

        public static Boolean copyFilesFromAssets(Context context, String oldPath, String newPath) {

    try {

    String fileNames[] = context.getAssets().list(oldPath);//获取assets目录下的所有文件及目录名

                if (fileNames.length >0) {//如果是目录

                    File file =new File(newPath);

    file.mkdirs();//如果文件夹不存在,则递归

                    for (String fileName : fileNames) {

    copyFilesFromAssets(context,oldPath +"/" + fileName,newPath+"/"+fileName);

    }

    }else {//如果是文件

                    InputStream is = context.getAssets().open(oldPath);

    FileOutputStream fos =new FileOutputStream(new File(newPath));

    byte[] buffer =new byte[1024];

    int byteCount=0;

    while((byteCount=is.read(buffer))!=-1) {//循环从输入流读取 buffer字节

                        fos.write(buffer,0, byteCount);//将读取的输入流写入到输出流

                    }

    fos.flush();//刷新缓冲区

                    is.close();

    fos.close();

    }

    return true;

    }catch (Exception e) {

    // TODO Auto-generated catch block

                e.printStackTrace();

    return  false;

    ////如果捕捉到错误则通知UI线程

    //MainActivity.handler.sendEmptyMessage(COPY_FALSE);

            }

    }

        //拷貝整個文件夾到某個路徑上

        public static void CopyAssets(Context context, String assetDir, String dir) {

    String[] files;

    try {

    files = context.getResources().getAssets().list(assetDir);

    }catch (IOException e1) {

    return;

    }

    File mWorkingPath =new File(dir);

    // if this directory does not exists, make one.

            if (!mWorkingPath.exists()) {

    if (!mWorkingPath.mkdirs()) {

    }

    }

    for (int i =0; i < files.length; i++) {

    try {

    String fileName = files[i];

    // we make sure file name not contains '.' to be a folder.

                    if (!fileName.contains(".")) {

    if (0 == assetDir.length()) {

    CopyAssets(context, fileName, dir + fileName +"/");

    }else {

    CopyAssets(context, assetDir +"/" + fileName, dir+ fileName +"/");

    }

    continue;

    }

    File outFile =new File(mWorkingPath, fileName);

    if (outFile.exists())

    outFile.delete();

    InputStream in =null;

    if (0 != assetDir.length())

    in = context.getAssets().open(assetDir +"/" + fileName);

    else

                        in = context.getAssets().open(fileName);

    OutputStream out =new FileOutputStream(outFile);

    // Transfer bytes from in to out

                    byte[] buf =new byte[1024];

    int len;

    while ((len = in.read(buf)) >0) {

    out.write(buf,0, len);

    }

    in.close();

    out.close();

    }catch (FileNotFoundException e) {

    e.printStackTrace();

    }catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    }

    //手机系统架构判断工具类

    import android.text.TextUtils;

    import android.util.Log;

    import java.io.BufferedReader;

    import java.io.File;

    import java.io.FileInputStream;

    import java.io.InputStreamReader;

    /*

    *該工具類主要作用是查詢設備是x64還是x86

    */

    public class DriverTypeUtils {

    public static final StringCPU_ARCHITECTURE_TYPE_32 ="32";

    public static final StringCPU_ARCHITECTURE_TYPE_64 ="64";

    /** ELF文件头 e_indent[]数组文件类标识索引 */

        private static final int EI_CLASS =4;

    /** ELF文件头 e_indent[EI_CLASS]的取值:ELFCLASS32表示32位目标 */

        private static final int ELFCLASS32 =1;

    /** ELF文件头 e_indent[EI_CLASS]的取值:ELFCLASS64表示64位目标 */

        private static final int ELFCLASS64 =2;

    /** The system property key of CPU arch type */

        private static final StringCPU_ARCHITECTURE_KEY_64 ="ro.product.cpu.abilist64";

    /** The system libc.so file path */

        private static final StringSYSTEM_LIB_C_PATH ="/system/lib/libc.so";

    private static final StringSYSTEM_LIB_C_PATH_64 ="/system/lib64/libc.so";

    private static final StringPROC_CPU_INFO_PATH ="/proc/cpuinfo";

    private static boolean LOGENABLE =false;

    /**

    * Check if system libc.so is 32 bit or 64 bit

    */

        public static boolean isLibc64() {

    File libcFile =new File(SYSTEM_LIB_C_PATH);

    if (libcFile !=null && libcFile.exists()) {

    byte[] header =readELFHeadrIndentArray(libcFile);

    if (header !=null && header[EI_CLASS] ==ELFCLASS64) {

    if (LOGENABLE) {

    Log.d("#####isLibc64()",SYSTEM_LIB_C_PATH +" is 64bit");

    }

    return true;

    }

    }

    File libcFile64 =new File(SYSTEM_LIB_C_PATH_64);

    if (libcFile64 !=null && libcFile64.exists()) {

    byte[] header =readELFHeadrIndentArray(libcFile64);

    if (header !=null && header[EI_CLASS] ==ELFCLASS64) {

    if (LOGENABLE) {

    Log.d("####isLibc64()",SYSTEM_LIB_C_PATH_64 +" is 64bit");

    }

    return true;

    }

    }

    return false;

    }

    /**

        * ELF文件头格式是固定的:文件开始是一个16字节的byte数组e_indent[16]

        * e_indent[4]的值可以判断ELF是32位还是64位

        */

        private static byte[] readELFHeadrIndentArray(File libFile) {

    if (libFile !=null && libFile.exists()) {

    FileInputStream inputStream =null;

    try {

    inputStream =new FileInputStream(libFile);

    if (inputStream !=null) {

    byte[] tempBuffer =new byte[16];

    int count = inputStream.read(tempBuffer,0,16);

    if (count ==16) {

    return tempBuffer;

    }else {

    if (LOGENABLE) {

    Log.e("readELFHeadrIndentArray","Error: e_indent lenght should be 16, but actual is " + count);

    }

    }

    }

    }catch (Throwable t) {

    if (LOGENABLE) {

    Log.e("readELFHeadrIndentArray","Error:" + t.toString());

    }

    }finally {

    if (inputStream !=null) {

    try {

    inputStream.close();

    }catch (Exception e) {

    e.printStackTrace();

    }

    }

    }

    }

    return null;

    }

    /*

        * 该方法的作用是判断手机使用哪种架构的 、Android获取CPU架构* */

        public static StringCPUABI =null;

    public static String getCPUABI() {

    if (CPUABI ==null) {

    try {

    String os_cpuabi =new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec("getprop ro.product.cpu.abi").getInputStream())).readLine();

    if (os_cpuabi.contains("x86")) {

    CPUABI ="x86";

    return "x86";

    }else if (os_cpuabi.contains("armeabi-v7a") || os_cpuabi.contains("arm64-v8a")) {

    CPUABI ="armeabi-v7a";

    return "armeabi-v7a";

    }else {

    CPUABI ="armeabi";

    return "armeabi";

    }

    }catch (Exception e) {

    CPUABI ="armeabi";

    return "armeabi";

    }

    }

    if (CPUABI ==null || TextUtils.isEmpty(CPUABI)) {

    Boolean isLib64CPU =isLibc64();

    if (isLib64CPU){

    CPUABI="armeabi";

    }else {

    CPUABI="x86";

    }

    }

    return CPUABI;

    }

    }

    相关文章

      网友评论

          本文标题:插件化无法获取或找到.so文件

          本文链接:https://www.haomeiwen.com/subject/kaaeaktx.html