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 第一個的區(qū)別在自己的lib/jinLibs目錄下忘記添加so 文件了
第二個是因為插件化問題 類加載器加載的緣故導致so讀取的路徑變了 變成/myfile/lib下
這里做法都是大同小異
直接將所缺的so文件放進assets文件夾中
然后安轉(zhuǎn)的時候?qū)o文件拷貝到data/user/0/com.xxx.xxx/myfile/lib 目錄下
這個操作要打開應(yīng)用之后判斷這個目錄是否存在 里面是否有對應(yīng)系統(tǒng)架構(gòu)的so文件即可
如果遇到是拷貝文件進去 遇到?jīng)]有讀寫權(quán)限 需要操作之前申請權(quán)限,是強制性的,
拿到權(quán)限之后 拷貝還是失敗晨仑,那是拷貝的姿勢有問題了?
```
123
```
```
解析代碼如下
ApplicationInfo info = context.getApplicationInfo();
//1.如果解壓之后有對應(yīng)的包名/lib之下有so文件 先拷貝到/myfile/lib下面 改操作的好處是系統(tǒng)直接默認選好是使用哪個系統(tǒng)架構(gòu)的so文件,不需要我們再另行判斷哪個系統(tǒng)架構(gòu)
? ? ? ? String PathOne ="/data/user/0/"+getPackageName(context)+"/lib";
String PathA ="/data/data/"+info.packageName+"/lib";
//上面的成功之后可以不執(zhí)行下面第二部 可以判斷data/user/0/com.xxx.xxx/myfile/lib/xxx.so文件是否存在 存在則不執(zhí)行第二部
//? 2.如果解壓之后有對應(yīng)的包名/lib之下沒有so文件 則再從Assets/lib對應(yīng)系統(tǒng)架構(gòu)的so文件拷貝到/myfile/lib下面 該處需要我們另行判斷系統(tǒng)架構(gòu)
? ? ? ? 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()=======查詢當前的系統(tǒng)架構(gòu)是======="+systemArchitecture);//查詢是x64還是x86
? ? ? ? Log.e("allPathC"," 當前拷貝的so文件的路徑為:=====" +"lib/"+systemArchitecture+"/libEncryptorP.so");
CopySoFileToLib.copyFilesFromAssets(context,"lib/"+systemArchitecture,PathTwo);
CopySoFileToLib.copyFilesFromAssets(context,"lib/"+systemArchitecture,PathB);
// 獲取acitivty所在的應(yīng)用包名
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 {
/**
? ? * 復(fù)制文件夾及其中的文件 該作用主要是 /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 復(fù)制后的路徑 如: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目錄中復(fù)制整個文件夾內(nèi)容到新的路徑下
? ? *? @param? context? Context 使用CopyFiles類的Activity
? ? *? @param? oldPath? String? 原文件路徑? 如:Data(assets文件夾下文件夾名稱)
? ? *? @param? newPath? String? 復(fù)制后路徑? 如:data/data/(手機內(nèi)部存儲路徑名稱)
? ? */
? ? 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) {//循環(huán)從輸入流讀取 buffer字節(jié)
? ? ? ? ? ? ? ? ? ? fos.write(buffer,0, byteCount);//將讀取的輸入流寫入到輸出流
? ? ? ? ? ? ? ? }
fos.flush();//刷新緩沖區(qū)
? ? ? ? ? ? ? ? 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();
}
}
}
}
```
```
//手機系統(tǒng)架構(gòu)判斷工具類
import android.text.TextUtils;
import android.util.Log;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
/*
*該工具類主要作用是查詢設(shè)備是x64還是x86
*/
public class DriverTypeUtils {
public static final StringCPU_ARCHITECTURE_TYPE_32 ="32";
public static final StringCPU_ARCHITECTURE_TYPE_64 ="64";
/** ELF文件頭 e_indent[]數(shù)組文件類標識索引 */
? ? 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字節(jié)的byte數(shù)組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;
}
/*
? ? * 該方法的作用是判斷手機使用哪種架構(gòu)的 、Android獲取CPU架構(gòu)* */
? ? 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;
}
}
```