转自:
http://blog.chinaunix.net/uid-20771867-id-3261874.html
最近学习了云中漫步关于JNI的讲解,见http://my.unix-center.net/~Simon_fu/?p=833。再加上平常工作中学习实现了一个通过JNI来获取 wifi interface name的实验工程,加深了对JNI的理解。
static代码块告诉程序所要调用的库文件名,这个库文件将会在下面实现。另外定义了一个get方法,当调用这个get方法的时候就会去调用库文件中的方法。
好了,现在需要把这个文件搬一个家。在工程中新建一个文件夹jni,并在里面建两个子文件夹include和src。这两个文件将分别用来存放头文件和源代码。将org_testjni_GetNetWork.h复制到include文件夹中。
在这个方法中还调用c的方法,所以还得用c语言实现property_get方法。在jni/include中新建一个头文件properties.h,在jni/src中新建一个c文件properties.c
在这里调用了__system_property_get方法,这是个系统方法,会根据key的值查找结果并存在value里面,在这个程序中查找出来的结果应该为"wlan0"。
执行这个文件需要电脑上装有ndk,没有的话可以去android的官方网站上去下载。然后在jni目录下执行ndk-build命令,如果这个命令没有加入到环境变量中要使用绝对路径,如我的电脑上执行~/android-ndk-r8/ndk-build。运行之后会自动生成libs和obj文件夹和里面的一堆文件。我们要使用的就是libs文件夹里面的libNetworkInterface.so文件。要注意的是名字前面的lib是系统自动加的,这是一个命名规则。
运行程序后输出的结果如下,这样表明程序成功地通过jni获取到了wifi interface name。
首先新建一个android工程,并在里面新建一个GetNetWork.java类,该类通过jni来调用由c++实现的方法。
点击(此处)折叠或打开
- package org.testjni;
- public class GetNetWork {
- static{
- System.loadLibrary("NetworkInterface");
- }
- public static native String get(String property);
- }
如果是在eclipse中编辑的,这时候就需要编译一下来生成class文件。然后进入到workspace中这个工程的
bin/classes目录下,如在我的电脑中就是/workspace/TestJNI/bin/classes。在这里运行命令 javah org.testjni.GetNetWork。运行完了之后会自动产生一个org_testjni_GetNetWork.h文件,打开文件,其头部有说明“
DO
NOT
EDIT THIS FILE
-
it
is
machine generated
”,所以说最好别修改这个文件。其实这个文件也可以自己写,只是那样会比较麻烦还容易出错,最好还是用javah命令生成吧。
点击(此处)折叠或打开
- /* DO NOT EDIT THIS FILE - it is machine generated */
- #include <jni.h>
- /* Header for class org_testjni_GetNetWork */
- #ifndef _Included_org_testjni_GetNetWork
- #define _Included_org_testjni_GetNetWork
- #ifdef __cplusplus
- extern "C" {
- #endif
- /*
- * Class: org_testjni_GetNetWork
- * Method: get
- * Signature: (Ljava/lang/String;)Ljava/lang/String;
- */
- JNIEXPORT jstring JNICALL Java_org_testjni_GetNetWork_get
- (JNIEnv *, jclass, jstring);
- #ifdef __cplusplus
- }
- #endif
- #endif
接下来就是用c++实现这个get方法。在jni/src目录下新建一个c++文件org_testjni_GetNetWork.cpp
点击(此处)折叠或打开
- #include "org_testjni_GetNetWork.h"
- #include "jni.h"
- #include "properties.h"
- JNIEXPORT jstring JNICALL Java_org_testjni_GetNetWork_get(JNIEnv *env, jclass,
- jstring keyJ) {
- int len;
- const char* key;
- char buf[92];
- jstring rvJ = env->NewStringUTF("");
- key = env->GetStringUTFChars(keyJ, 0);
- len = property_get(key, buf, "");
- if (len >= 0) {
- rvJ = env->NewStringUTF(buf);
- }
- env->ReleaseStringUTFChars(keyJ, key);
- return rvJ;
- }
点击(此处)折叠或打开
- #ifndef __CUTILS_PROPERTIES_H
- #define __CUTILS_PROPERTIES_H
- #ifdef __cplusplus
- extern "C" {
- #endif
- int property_get(const char *key, char *value, const char *default_value);
- #ifdef __cplusplus
- }
- #endif
- #endif
点击(此处)折叠或打开
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <errno.h>
- #include <assert.h>
- #include <properties.h>
- #include <sys/system_properties.h>
- #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
- int property_get(const char *key, char *value, const char *default_value)
- {
- int len;
- len = __system_property_get(key, value);
- if(len > 0) {
- return len;
- }
- if(default_value) {
- len = strlen(default_value);
- memcpy(value, default_value, len + 1);
- }
- return len;
- }
好了,现在应该写make文件来进行编译了。在jni目录下新建一个Android.mk文件,关于每一行的含义网上一搜有很多,就不罗嗦了。
点击(此处)折叠或打开
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_SRC_FILES := \
- src/org_testjni_GetNetWork.cpp \
- src/properties.c
- LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/include
- LOCAL_CFLAGS :=
- LOCAL_CPPFLAGS :=
- LOCAL_MODULE := NetworkInterface
- include $(BUILD_SHARED_LIBRARY)
如果没出什么问题的话可以说到这里就大功告成了,直接在程序中调用get方法就可以了:
点击(此处)折叠或打开
- package org.testjni;
- import android.app.Activity;
- import android.os.Bundle;
- import android.util.Log;
- public class TestJNIActivity extends Activity {
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- Log.d("test","get wifi interface name from jni:"+GetNetWork.get("wifi.interface"));
- }
- }
最后完整的工程目录如下: