首先通过NDK自带的例子来初步了解NDK的开发
1. Java类文件
HelloJni.class /* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.hellojni; import android.app.Activity; import android.widget.TextView; import android.os.Bundle; public class HelloJni extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); /* Create a TextView and set its content. * the text is retrieved by calling a native * function. */ TextView tv = new TextView(this); tv.setText( stringFromJNI() ); setContentView(tv); } /* * 调用libhello-jni.so库中的stringFromJNI()方法 * 注意声明的时候需要包含"native",表示是本地方法 */ public native String stringFromJNI(); /* * 加载libhello-jni.so库,省略了头lib和尾.so * static{}在程序加载的时候就调用 */ static { System.loadLibrary("hello-jni"); } }
2. 本地C代码部分
hello-jni.c#include <string.h> #include <jni.h> /* 函数命名规则: Java开头,接着是包名的每一段,然后是类名,最后是Java中调用的方法名,中间都用下划线隔开。 第一个参数JNIEnv* env和第二个参数jobject thiz都是必须的,后面的才是Java中传递进来的参数 */ jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz ) { return (*env)->NewStringUTF(env, "Hello from JNI !");//字符串的操作见NDK概述 }
3. 在工程目录编译jni文件夹生成so文件,则可以通过Eclipse加载工程调试了。
第二部分:进阶
通过上面的例子分析,我们知道了怎么调用动态库,怎么引用动态库中的方法,以及动态库中方法的命名。下面我们了解怎么在本地C代码中添加一个方法,给java调用。
我们以添加一个add方法为例,方法原型为:int addFromJNI(int a,int b)
A. 在本地C代码中添加add方法,并实现。
hello-jni.c #include <string.h> #include <jni.h> /* 函数的命名规则: Java开头,接着是包名的每一段,然后是类名,最后是Java中调用的方法名,中间都用下划线隔开。 第一个参数JNIEnv* env和第二个参数jobject thiz都是必须的,后面的才是Java中传递进来的参数。 */ jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz ) { return (*env)->NewStringUTF(env, "Hello from JNI !"); } jint Java_com_example_hellojni_HelloJni_addFromJNI( JNIEnv* env,jobject thiz,jint a,jint b) { return a + b; }
B. 编译mk文件,生成so文件
$NDK/ndk-build //$NDK环境变量设置的NDK目录
C. java 源代码
HelloJni.java package com.example.hellojni; import android.app.Activity; import android.widget.TextView; import android.os.Bundle; public class HelloJni extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); /* Create a TextView and set its content. * the text is retrieved by calling a native * function. */ TextView tv = new TextView(this); tv.setText( stringFromJNI() +"****" + addFromJNI(3, 4)); setContentView(tv); } /* * 调用libhello-jni.so库中的stringFromJNI()方法 * 注意声明的时候需要包含"native",表示是本地 */ public native String stringFromJNI(); /* * 调用新增加的addFromJNI方法 */ public native int addFromJNI(int a,int b); /* * 加载libhello-jni.so库,省略了头lib和尾.so * static{}在程序加载的时候就调用 */ static { System.loadLibrary("hello-jni"); } }
D. 加载运行,则看到刚添加的函数生效了