Mapbox源码分析之库加载

简介:

通过源码,我们来一步步分析Mapbox地图引擎原生库加载的流程,这里是基于5.3.0的版本.

当在代码中调用System.loadLibrary函数时,该函数会找到对应的动态库,然后找到”JNI_OnLoad”函数,如果该函数存在,则调用它,这里我们看到原生库下有一个main.cpp文件中包含这个方法,即这是库加载的入口

1
2
3
4
5
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) {
assert(vm != nullptr);
mbgl::android::registerNatives(vm);
return JNI_VERSION_1_6;
}

这里我们看到它调用了registerNatives函数,我们在它包含的jni.cpp中找到该函数

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
void registerNatives(JavaVM *vm) {
theJVM = vm;
jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
// For the DefaultFileSource
static mbgl::util::RunLoop mainRunLoop;
FileSource::registerNative(env);
// Basic types
java::registerNatives(env);
java::util::registerNative(env);
PointF::registerNative(env);
RectF::registerNative(env);
// GeoJSON
geojson::Feature::registerNative(env);
geojson::FeatureCollection::registerNative(env);
geojson::Geometry::registerNative(env);
geojson::LineString::registerNative(env);
geojson::MultiLineString::registerNative(env);
geojson::MultiPoint::registerNative(env);
geojson::MultiPolygon::registerNative(env);
geojson::Point::registerNative(env);
geojson::Polygon::registerNative(env);
geojson::Position::registerNative(env);
// Geometry
LatLng::registerNative(env);
LatLngBounds::registerNative(env);
LatLngQuad::registerNative(env);
ProjectedMeters::registerNative(env);
// GSon
gson::JsonArray::registerNative(env);
gson::JsonElement::registerNative(env);
gson::JsonObject::registerNative(env);
gson::JsonPrimitive::registerNative(env);
//Annotation
Marker::registerNative(env);
Polygon::registerNative(env);
Polyline::registerNative(env);
// Map
MapRenderer::registerNative(env);
MapRendererRunnable::registerNative(env);
NativeMapView::registerNative(env);
// Http
RegisterNativeHTTPRequest(env);
// Bitmap
Bitmap::registerNative(env);
BitmapFactory::registerNative(env);
// Style
TransitionOptions::registerNative(env);
registerNativeLayers(env);
registerNativeSources(env);
Light::registerNative(env);
Position::registerNative(env);
Stop::registerNative(env);
CategoricalStops::registerNative(env);
ExponentialStops::registerNative(env);
IdentityStops::registerNative(env);
IntervalStops::registerNative(env);
// Map
CameraPosition::registerNative(env);
Image::registerNative(env);
// Connectivity
ConnectivityListener::registerNative(env);
// Offline
OfflineManager::registerNative(env);
OfflineRegion::registerNative(env);
OfflineRegionDefinition::registerNative(env);
OfflineTilePyramidRegionDefinition::registerNative(env);
OfflineRegionError::registerNative(env);
OfflineRegionStatus::registerNative(env);
// Snapshotter
MapSnapshotter::registerNative(env);
MapSnapshot::registerNative(env);
}

这里我们看到,它对底层相关类进行了注册,这里我们随便找一个类看一下,例如FileSource类,我们找到file_source.cpp文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void FileSource::registerNative(jni::JNIEnv& env) {
//Register classes
FileSource::javaClass = *jni::Class<FileSource>::Find(env).NewGlobalRef(env).release();
FileSource::ResourceTransformCallback::javaClass = *jni::Class<FileSource::ResourceTransformCallback>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
// Register the peer
jni::RegisterNativePeer<FileSource>(
env, FileSource::javaClass, "nativePtr",
std::make_unique<FileSource, JNIEnv&, jni::String, jni::String, jni::Object<AssetManager>>,
"initialize",
"finalize",
METHOD(&FileSource::getAccessToken, "getAccessToken"),
METHOD(&FileSource::setAccessToken, "setAccessToken"),
METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"),
METHOD(&FileSource::setResourceTransform, "setResourceTransform"),
METHOD(&FileSource::resume, "activate"),
METHOD(&FileSource::pause, "deactivate")
);
}

看到这里我们就看到了很多不熟悉的方法了,例如*jni.Class<>,Find(),NewGlobalRel(),RegisterNativePeer<>等,但即时如此,我们大概能看出这是找到对应类,并进行注册,我们看到这些方法都来自一个jni.hpp这个包里,我们在mason_packages包下面的headers包找到这些第三方引入的包,其中便有jni.hpp,那什么时候导入这个包的呢,这里我们返回根目录找到platform.android包下config.cmake文件,其中便有这么一行

1
mason_use(jni.hpp VERSION 3.0.0 HEADER_ONLY)

我们找到jni.hpp包下面的readme文件查看介绍,这是一个用c++14封装的新的类型安全,仅包含头部文件的jni库,比较方便的进行c++与java之间的调用等,下面是jni.hpp的github地址,相关使用这个库的细节,这里就不一一介绍了.
https://github.com/mapbox/jni.hpp/