(1)库层次关系
java:
System.loadLibrary("xxx_jni");
JNI native 实现:
libxxx_jni.so
xxx本地实现:
libxxx.so
(2)API映射过程(以android.media.MediaPlayer java class为例)
java加载libmedia_jni.so native库
//MediaPlayer.java
public class MediaPlayer
{
...
static {
System.loadLibrary("media_jni");
native_init();
}
...
}
-----------------------下一步-------------------->
自动调用libmedia_jni.so库中的JNI_OnLoad函数,开始API映射
//android_media_MediaPlayer.cpp
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("ERROR: GetEnv failed\n");
goto bail;
}
assert(env != NULL);
if (register_android_media_MediaPlayer(env) < 0) {//注册MediaPlayer映射关系
LOGE("ERROR: MediaPlayer native registration failed\n");
goto bail;
}
if (register_android_media_MediaRecorder(env) < 0) {
LOGE("ERROR: MediaRecorder native registration failed\n");
goto bail;
}
if (register_android_media_MediaScanner(env) < 0) {
LOGE("ERROR: MediaScanner native registration failed\n");
goto bail;
}
if (register_android_media_MediaMetadataRetriever(env) < 0) {
LOGE("ERROR: MediaMetadataRetriever native registration failed\n");
goto bail;
}
if (register_android_media_AmrInputStream(env) < 0) {
LOGE("ERROR: AmrInputStream native registration failed\n");
goto bail;
}
if (register_android_media_ResampleInputStream(env) < 0) {
LOGE("ERROR: ResampleInputStream native registration failed\n");
goto bail;
}
if (register_android_media_MediaProfiles(env) < 0) {
LOGE("ERROR: MediaProfiles native registration failed");
goto bail;
}
/* success -- return valid version number */
result = JNI_VERSION_1_4;
bail:
return result;
}
-----------------------下一步-------------------->
调用注册函数AndroidRuntime::registerNativeMethods
// This function only registers the native methods
static int register_android_media_MediaPlayer(JNIEnv *env)
{
return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaPlayer", gMethods, NELEM(gMethods));//"android/media/MediaPlayer"为java class所在包的路径,gMethods为真正的API映射关系}
registerNativeMethods的参数gMethods为JNINativeMethod 结构体,它的3个成员依次为:
被映射java class的函数名、函数形参类型和返回值类型等信息、映射JNI层native函数指针:
static JNINativeMethod gMethods[] = {
{"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource},
{"setDataSource", "(Ljava/lang/String;Ljava/util/Map;)V",(void *)android_media_MediaPlayer_setDataSourceAndHeaders},
{"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
{"_setVideoSurface", "()V", (void *)android_media_MediaPlayer_setVideoSurface},
{"prepare", "()V", (void *)android_media_MediaPlayer_prepare},
{"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync},
{"_start", "()V", (void *)android_media_MediaPlayer_start},
{"_stop", "()V", (void *)android_media_MediaPlayer_stop},
{"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth},
{"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight},
{"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo},
{"_pause", "()V", (void *)android_media_MediaPlayer_pause},
{"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying},
{"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition},
{"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration},
{"_release", "()V", (void *)android_media_MediaPlayer_release},
{"_reset", "()V", (void *)android_media_MediaPlayer_reset},
{"setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType},
{"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping},
{"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping},
{"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},
{"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt},
{"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
{"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter},
{"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata},
{"native_init", "()V", (void *)android_media_MediaPlayer_native_init},
{"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
{"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
{"native_suspend_resume", "(Z)I", (void *)android_media_MediaPlayer_native_suspend_resume},
{"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id},
{"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id},
{"setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
{"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect},
};
(3)命名规律
java函数映射到JNI后,JNI函数名一般为“包名_类名_函数名”,如MediaPlayer java类位于android.media这个包中,
则其JNI映射函数为android_media_MediaPlayer_函数名
此外,其JNI实现所在文件的的文件名一般为“包名_类名.cpp”,如android_media_MediaPlayer.cpp