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

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文件即可

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

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

```

123

```

```

解析代码如下

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;

}

}

```

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容