您的位置:首页 > 移动开发 > Android开发

部分手机不能加载so文件,couldn't find *.so

2016-01-29 11:44 579 查看

背景

当我们项目中使用到了.so库时,大部分手机能正常运行,但是部分手机在运行时,比如我们项目中使用到了mupdf这个开源的pdf查看器,里面需要使用到libmupdf.so,此时会报couldn’t find libmupdf.so错误,导致程序再浏览pdf文件时崩溃。

原因

一般情况下,当我们安装了应用时,项目中的.so库会安装到手机的/data/data/+包名+/lib 路径下,由于Android碎片化严重,很多厂商高度定制化,导致部分手机加载不成功。

解决方案

既然项目需要so文件,但是应用安装时没有成功加载so文件,那么我们是否可以手动完成将其拷贝到相应的路径下呢?这完全是可行的办法,而且经验证是个完美的解决方案。

public class SoRepairRunnable extends Runnable {

private static final String TAG = "SoRepairRunnable";
private Context context;

public SoRepairRunnable(Context context) {
this.context = context;
}

@Override
public void run() {
String apkLibPath = "/data/data/" + EnvironmentUtils.getPackageName() + "/lib";
String pdfSoPath = apkLibPath + "/libmupdf.so";
File pdfSoFile = new File(pdfSoPath);
boolean pdfSoExist = pdfSoFile.exists();
String apkPath = getApkPath();
File v7aFile = new File("/data/data/" + EnvironmentUtils.getPackageName() + "/libs/armeabi-v7a");
if(!v7aFile.exists()){
v7aFile.mkdirs();
}
try {
//获取apk压缩包
ZipFile apkFile = new ZipFile(apkPath);
//取得压缩包内so文件
ZipEntry pdfZipEntry = apkFile.getEntry("lib/armeabi-v7a/libmupdf.so");
//将so文件写入到手机目录下
writeSoToLibs(apkFile, pdfZipEntry);
} catch (IOException e) {
e.printStackTrace();
}
}
}

private String getApkPath(){
return context.getPackageCodePath();
}

private void writeSoToLibs(ZipFile zipFile, ZipEntry entry) throws IOException{
String entryName = entry.getName();
String fileName = "/data/data/" + EnvironmentUtils.getPackageName() + "/" + entryName.replaceFirst("lib/", "libs/");
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = zipFile.getInputStream(entry);
File file = new File(fileName  + ".tmp");
if (!file.exists()) {
file.createNewFile();
}
outputStream = new FileOutputStream(file);

int byteCount = 0;

byte[] bytes = new byte[8096];
while ((byteCount = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, byteCount);
}
outputStream.flush();
File newFile = new File(fileName);
file.renameTo(newFile);
file.delete();

}
catch (IOException e){
e.printStackTrace();
}finally {
if(null != inputStream) {
inputStream.close();
}
if(null != outputStream) {
outputStream.close();
}
}
}
}


这里为什么将so文件写入到另外一个libs文件夹下,而不是lib下,是因为lib文件夹是系统目录,我们没有权限读写,所以应用中在加载so文件时,也要相应的修改路径。

一般情况下,我们在应用中加载so文件是这样的,比如我的so库叫做libXXX,则加载时应该是(这是一个规则)

System.loadLibrary("XXX");


在我们的例子中应该有这样的一句静态语句块,在应用启动的时候去载入so文件

static {
System.loadLibrary("mupdf");
}


loadLibrary传入的是so库名称,它默认路径是/data/data/+包名+/lib,但是在部分手机下,它是不存在该so文件,经过我们上面的拷贝处理之后,so文件应该是在/data/data/+包名+/libs 路径下,所以这时候,我们应该载入的是在这个路径下的so文件,即应该这样处理:

System.load("/data/data/" + EnvironmentUtils.getPackageName() + "/libs/armeabi-v7a/libmupdf.so");


load方法,传入的是一个so文件的绝对路径。

完整的处理代码如下:

static {
//若自己拷贝的so文件存在证明该设备无法载入lib里的so文件,改为获取自己拷贝的so文件
String apkLibPath = "/data/data/" + EnvironmentUtils.getPackageName() + "/libs";
String pdfSoPath = apkLibPath + "/armeabi-v7a/libmupdf.so";
File pdfSoFile = new File(pdfSoPath);
boolean isExist = pdfSoFile.exists();
if(isExist){
System.load(pdfSoFile.getAbsolutePath());
}
else{
System.loadLibrary("mupdf");
}
}


2016-06-29 补充:

如果你在项目的libs存放了各个cpu型号的so文件,还是提示加载so文件不存在的问题的话, 你可以尝试在项目main文件夹下创建jniLibs文件夹,然后将so文件拷贝过去,如下图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息