Android升级64位遇到的问题和解决方案

Android升级64是今年Google强制执行的一项规定,国内应用市场也应该快实施了,所以升级64位是必须执行的。其实Android中升级64位主要是SO升级。

1.动态加载so

Android其实从5.0以后就支持64位,但是现在市场上的app大多不支持64,只放入32位的so,主要支持多个cpu架构so的体积过大。当app只有32位so,app就会以32模式运行,当app有64位so,app就会以64位运行,所以动态加载so的时候需要加载对应cpu架构的so。Android中动态加载so的方法是System.load, 此方法在加载32位so的时候没有问题,但是在加载64位so的时候,部分低版本手机机型出现UnsatisfiedLinkError错误。其实查阅了很多资料也没有找到根本的问题,只能想其他方案实现,过程中也一直没有找到新的方法,后来灵光一闪,可以参考插件化加载方案,加载so流程。直接将so路径放置到系统路径里面,通过System.loadLibrary(fileName)加载so。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
private static void install(ClassLoader classLoader, File folder) throws Throwable {
Field pathListField = ReflectUtil.findField(classLoader, "pathList");
Object dexPathList = pathListField.get(classLoader);
Field nativeLibraryDirectories = ReflectUtil.findField(dexPathList, "nativeLibraryDirectories");

List<File> libDirs = (List<File>) nativeLibraryDirectories.get(dexPathList);
//去重
if (libDirs == null) {
libDirs = new ArrayList<>(2);
}
final Iterator<File> libDirIt = libDirs.iterator();
while (libDirIt.hasNext()) {
final File libDir = libDirIt.next();
if (folder.equals(libDir) || folder.equals(lastSoDir)) {
libDirIt.remove();
Log.d(TAG, "dq libDirIt.remove()" + folder.getAbsolutePath());
break;
}
}

libDirs.add(0, folder);
//system/lib
Field systemNativeLibraryDirectories = ReflectUtil.findField(dexPathList, "systemNativeLibraryDirectories");
List<File> systemLibDirs = (List<File>) systemNativeLibraryDirectories.get(dexPathList);

//判空
if (systemLibDirs == null) {
systemLibDirs = new ArrayList<>(2);
}
Log.d(TAG, "dq systemLibDirs,size=" + systemLibDirs.size());

Method makePathElements = ReflectUtil.findMethod(dexPathList, "makePathElements", List.class);
libDirs.addAll(systemLibDirs);

Object[] elements = (Object[]) makePathElements.invoke(dexPathList, libDirs);
Field nativeLibraryPathElements = ReflectUtil.findField(dexPathList, "nativeLibraryPathElements");
nativeLibraryPathElements.setAccessible(true);
nativeLibraryPathElements.set(dexPathList, elements);
}

2.Webview闪退问题

我们app升级64位上线后,莫名其妙出现了很多webview navtive的一些闪退,猜测大概率是升级64位导致的。查阅资料说是webview缓存导致,清除webview cpu缓存可以解决
data/data/com.sammekl.myapp/app_webview/GPUCache 删除路径文件,但是删除完成后发现无效,需要删除app_webview整个目录。

1
2
3
4
5
6
7
8
backtrace:
#00 pc 000000000076eb50 /vendor/lib/libllvm-glnext.so (ShaderObjects::loadProgramBinary(CompilerContext*, void*, unsigned int, QGLC_LINKPROGRAM_RESULT*)+855)
#01 pc 00000000006ddba5 /vendor/lib/libllvm-glnext.so (CompilerContext::loadProgramBinary(void*, unsigned int, QGLC_LINKPROGRAM_RESULT*)+108)
#02 pc 000000000077fb73 /vendor/lib/libllvm-glnext.so (QGLCLoadProgramBinary(void*, void*, unsigned int, QGLC_LINKPROGRAM_RESULT*)+54)
#03 pc 00000000001612b1 /vendor/lib/egl/libGLESv2_adreno.so (EsxShaderCompiler::LoadProgramBinaryBlob(EsxContext*, EsxProgram*, void const*, unsigned int, EsxInfoLog*)+164)
#04 pc 0000000000140191 /vendor/lib/egl/libGLESv2_adreno.so (EsxProgram::LoadProgramBinary(EsxContext*, unsigned int, void const*, int)+186)
#05 pc 00000000000aff67 /vendor/lib/egl/libGLESv2_adreno.so (EsxContext::GlProgramBinary(unsigned int, unsigned int, void const*, int)+230)
#06 pc 00000000000991d9 /vendor/lib/egl/libGLESv2_adreno.so (glProgramBinary+40)

参考资料