1. Demand background

As the saying goes, what is the use of learning source code analysis? All the problems we encountered could be solved by analyzing the source code; Seemingly unable to achieve the function, can find ideas through source analysis…… . These are all concepts that have been brainwashed countless times before, so let’s take a look at the actual development requirements, and I’ll take you to the actual practice a few times. When we were still in the news, we were working on an audio live broadcast project. Later, due to the failure of this business, our boss asked us to make a 3D gameplay in the project, which is to adopt Unity + Android development mode. Unity exports about 200 MB of resources, direct integration into Android will definitely increase the package size. And package volume is too large, will affect our installation speed and start speed and so on, this in the previous analysis of the source code principle, not our focus. Our focus is to achieve the requirements without increasing the package size. The result we made later is that the package size only increases by 50K. I was rated as an excellent employee of the company for realizing the interaction between Unity and Android project from 0 to 1 and realizing the dynamic loading of Unity resources. Later, the department merged after the demand was finished, and we were scattered and lost our passion for business. Then in the interview resume is also simple to write a pen, dazed into Tencent, happiness is too suddenly. In fact, big companies are sad too, but ordinary people I feel embarrassed to tell him.

2. Requirements analysis

The resources exported by Unity are roughly divided into three parts, one part is about 50K JAR package, the second part is about 30M so library, and the third part is about 100M assets. The first is the JAR package. The Activity we write needs to inherit from the UnityPlayerActivity in the JAR, and the jar package is not large, so we should not do dynamic loading. Secondly, assets, which is also easy to deal with; The difficulty lies in the dynamic loading of so.

Static {system.load (" download so directory full path "); }Copy the code

The problem is that the unity exported JAR is written like this

static { (new k()).a(); o = false; o = loadLibraryStatic("main"); } protected static boolean loadLibraryStatic(String var0) { try { System.loadLibrary(var0); return true; } catch (UnsatisfiedLinkError var1) { com.unity3d.player.e.Log(6, "Unable to find " + var0); return false; } catch (Exception var2) { com.unity3d.player.e.Log(6, "Unknown error " + var2); return false; }}Copy the code

Libmain. so will load the other two so libraries in the C++ layer. I didn’t get a good night’s sleep. I couldn’t sleep at night, so I started looking through the source code of the so loading process.

3. Source code analysis

public static void loadLibrary(String libname) { Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), libname); } synchronized void loadLibrary0(ClassLoader loader, String libname) { String libraryName = libname; if (loader ! Filename = loader.findLibrary(libraryName); if (filename == null) { throw new UnsatisfiedLinkError(loader + " couldn't find \"" + System.mapLibraryName(libraryName) + "\" "); } String error = nativeLoad(filename, loader); if (error ! = null) { throw new UnsatisfiedLinkError(error); } return; }... } @Override public String findLibrary(String name) { return pathList.findLibrary(name); } public String findLibrary(String libraryName) { String fileName = System.mapLibraryName(libraryName); / / by nativeLibraryPathElements traversal search returns for (Element Element: nativeLibraryPathElements) { String path = element.findNativeLibrary(fileName); if (path ! = null) { return path; } } return null; }Copy the code

Source is actually quite simple, the final so file is to find the returned by DexPathList traversal nativeLibraryPathElements, So if we can insert an Element into nativeLibraryPathElements the front? Obviously this is possible, and we’ve been doing this for three years in videos, dynamically loading the repair class, and it’s not that hard.

4. Version adaptation

After wrapping and writing the code, I began to eagerly show it off and then handed it over to my colleagues for integration:

I realized I was a novice on the road, so I went through all the Android 4.0-9.0 source code.

6.0 source private final Element [] nativeLibraryPathElements; static class Element { private final File dir; private final boolean isDirectory; private final File zip; private final DexFile dexFile; private ZipFile zipFile; public Element(File dir, boolean isDirectory, File zip, DexFile dexFile) { this.dir = dir; this.isDirectory = isDirectory; this.zip = zip; this.dexFile = dexFile; }} 8.0 source private final NativeLibraryElement [] nativeLibraryPathElements; static class NativeLibraryElement { private final String zipDir; private boolean initialized; public NativeLibraryElement(File dir) { this.path = dir; this.zipDir = null; } public NativeLibraryElement(File zip, String zipDir) { this.path = zip; this.zipDir = zipDir; if (zipDir == null) { throw new IllegalArgumentException(); Private final File[] nativeLibraryDirectories;Copy the code

In the process of development, many students may subconsciously think of some third-party frameworks of Big factories, but in fact, they may not have ready-made implementation of many functions, secondly, we may not be able to use many things, and the most important thing is that they may not be able to write their own.

Video address: pan.baidu.com/s/1COarOAlm…

Video password: 8lr0