原文链接:http://www.apkbus.com/blog-561682-62706.html
写此文的目的在于最近发现了不同平台下的so文件存在着不同的坑,特别是百度地图的so文件!
关于so动态链接库文件的坑,这里有几篇不错的文章,在这里推荐下!
so文件的长年大坑剖析:
https://zhuanlan.zhihu.com/p/21359984
极光平台与百度地图平台不会互斥的方法:
http://blog.csdn.net/wuqilianga/article/details/51509853
armeabi-v7a armeabi arm64-v8a 三个主要芯片平台的区别:
http://blog.csdn.net/mao520741111/article/details/50328669
安卓动态加载so文件方法:
http://www.jianshu.com/p/9609e1fb8756
http://www.cnblogs.com/sevenyuan/p/4202834.html
http://baladuu.com/2016/09/13/20160913/
===========================Start========================================
这里简单的做几个总结(主要以百度地图,百度导航、百度定位、极光,bugly,mob短信推送):
1.关于so文件,我们一般第一想到的就是要放 armeabi-v7a armeabi arm64-v8a这三个平台,因为这三个平台基本上支持了百分80的安卓主流机型,而只有intel、联发科等早期芯片才会出现x86架构!
2.而 mips、mips64基本上已被淘汰,可以不计入范围!
3.由于百度平台的动态链接库文件开始做统一平台,因此导致了它不再区分不同芯片(armeabi-v7a armeabi arm64-v8a等),主要代表有百度地图,百度导航,以及百度定位!
这会带来一个什么问题?
显而易见,肯定是与其它平台的库文件不兼容咯!
那我们应该怎么解决呢?
.以eclipse平台为例!
我们先从库文件的目录入手,如下图所示,为现如今的库文件存放方法
这是目前集成了百度地图,百度导航,百度定位,极光推送,mob短信推送,以及腾讯bugly的so文件存放
其中百度so文件就占了18个之多(红框标注),可见百度地图的so文件是多么繁杂?
这么放有什么问题?
我们可以联想的到,极光平台只放了一个armeabi,这是对老型号芯片平台,缺少浮点数计算的手机所设计的,那么当今大多数手机都是高通,联发科,大多数芯片是支持浮点计算的,那么就必须我们放armeabi-v7a平台吗?
不!so文件在安卓平台里有个兼容趋势,即64位兼容32位,32位又可以横向兼容,只有少部分比较特别的机型会不支持横向兼容,而一半如果支持armeabi-v7a的就一定可以支持armeabi!
但阿杰发现,在极光的so文件无论放了几个平台,也无法适应努比亚z11mini机型, 这在其它手机型号上是无法看到的现象!即便我用了动态加载so文件的方法,还是不行,然而其余的so文件却可以!所以这有可能是极光自己的坑!
如果有些机型无法横向兼容,那该怎么办?
用动态加载so文件方法啊,不能兼容是因为,so文件没被找到,它找到了 armeabi-v7a就不再继续找了,那你就动态的去找到这个so文件去加载,至于怎么动态加载,以上文章已有详细的方法,
基本上步骤就是,
把so文件存在本地或者app内部资源文件夹、
然后把so文件加载到应用内部的lib目录、
再用system.load()的方法去load那个文件!
[代码]java代码:
package com.intrecar.utils; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import android.content.Context; public class SoFileInitUtil { public void initAssetsFile(Context mContext) { boolean needCopy = false ; String libType = "armeabi" ; // 要加在的库文件平台,32位还是64位 // 先判断CPU类型来加载so文件 // if // (CheckCPUType.getArchType(mContext).equals(CheckCPUType.CPU_ARCHITECTURE_TYPE_32)) // { // LogUtils.PrintJay5("cpu is 32---"); // libType = "armeabi"; // } else if // (CheckCPUType.getArchType(mContext).equals(CheckCPUType.CPU_ARCHITECTURE_TYPE_64)) // { // LogUtils.PrintJay5("cpu is 64---"); // libType = "arm64-v8a"; // } // if (CheckCPUType.isLibc64()) { // libType = "arm64-v8a"; // } else { // libType = "armeabi"; // } // 创建data/data目录 File soFile = mContext.getDir( "libs" , Context.MODE_PRIVATE); String soPath = soFile.toString() + "/" ; // 遍历assets目录下所有的文件,是否在data/data目录下都已经存在 try { String[] fileNames = mContext.getAssets().list(libType); for ( int i = 0 ; fileNames != null && i < fileNames.length; i++) { if (!isFileExit(soPath + fileNames[i])) { needCopy = true ; break ; } } } catch (IOException e) { e.printStackTrace(); } if (needCopy) { copyFilesFassets(mContext, libType, soPath); } } private void copyFilesFassets(Context context, String oldPath, String newPath) { try { // 获取assets目录下的所有文件及目录名 String fileNames[] = context.getAssets().list(oldPath); // 如果是目录名,则将重复调用方法递归地将所有文件 if (fileNames.length > 0 ) { File file = new File(newPath); file.mkdirs(); for (String fileName : fileNames) { copyFilesFassets(context, oldPath + "/" + fileName, newPath + "/" + fileName); } } // 如果是文件,则循环从输入流读取字节写入 else { if (oldPath.contains( ".so" )) { 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 ) { fos.write(buffer, 0 , byteCount); } fos.flush(); is.close(); fos.close(); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } private boolean isFileExit(String path) { if (path == null ) { return false ; } else { try { File f = new File(path); if (f.exists()) { return true ; } } catch (Exception e) { e.printStackTrace(); } return false ; } } public void InitSo(Context mContext, String soFilaName) { File soFile = mContext.getDir( "libs" , Context.MODE_PRIVATE); String soPath = soFile.toString() + "/" ; if ( new File(soPath + soFilaName).exists()) { LogUtils.PrintJay5( "load so--" + soPath + soFilaName); System.load(soPath + soFilaName); } } public void InitBaiduNaviSo(Context mContext) { // InitSo(mContext, "libapp_BaiduNaviApplib.so"); // InitSo(mContext, "libaudiomessage-jni.so"); // InitSo(mContext, "libbd_etts.so"); // InitSo(mContext, "libbds.so"); // InitSo(mContext, "libBDSpeechDecoder_V1.so"); // InitSo(mContext, "libbdtts.so"); // InitSo(mContext, "libcurl.so"); // InitSo(mContext, "libetts_domain_data_builder.so"); // InitSo(mContext, "libgnustl_shared.so"); // InitSo(mContext, "libapp_BaiduVIlib.so"); // InitSo(mContext, "liblocnaviSDK.so"); } } |
如果是AS平台,so文件我们要怎么设置?
在AS平台下的so文件,放置平台问题相对于安卓会比较简单,因为它可以指定程序要去加载哪个平台的so文件,而不至于芯片自动索引会出现索引so文件出错的现象;
==========================End=========================