部分手机不能加载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文件拷贝过去,如下图:
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories