简单介绍一下JNI:
JNI是Java Native Interface的缩写,中文为JAVA本地调用。从Java1.1开始,Java Native Interface(JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。
android jni 开发 使用NDK 开发工具。
参考:
http://blog.csdn.net/acanoe/article/details/8613714
转载请标明出处:
http://blog.csdn.net/ACanoe
这篇博文简单分析一下jni 开发所依赖的文件和程序简单说明:
下面是 hello-jni 目录结构
|-- AndroidManifest.xml
|-- default.properties
|-- jni
| |-- Android.mk # Android.mk 类似于Linux 下的Makefile
| `-- hello-jni.c
|-- libs
| `-- armeabi
| |-- gdb.setup
| |-- gdbserver
| `-- libhello-jni.so
|-- obj
| `-- local
| `-- armeabi
| |-- libhello-jni.so # 这个是编译后得到的.so 文件
| `-- objs-debug
| `-- hello-jni
| |-- hello-jni.o
| `-- hello-jni.o.d
|-- res
| `-- values
| `-- strings.xml
|-- src
| `-- com
| `-- example
| `-- hellojni
| `-- HelloJni.java
`-- tests
|-- AndroidManifest.xml
|-- default.properties
`-- src
`-- com
`-- example
`-- HelloJni
`-- HelloJniTest.java
主要代码为:jni/hello-jni.c 和 src/com/example/hellojni/HelloJni.java
HelloJni.java 代码:
/* * 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); } /* A native method that is implemented by the * 'hello-jni' native library, which is packaged * with this application. */ public native String stringFromJNI(); // 函数 stringFromJNI() 调用 lib 中 hello-jni.c 中的 // Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,jobject thiz ) // 函数名解析为: java 为语言 ,com_example_hellojni 为包目录,HelloJni也就是类名 , stringFormJNI,是你在 .java 中调用的真正函数名。/* This is another native method declaration that is *not* * implemented by 'hello-jni'. This is simply to show that * you can declare as many native methods in your Java code * as you want, their implementation is searched in the * currently loaded native libraries only the first time * you call them. * * Trying to call this function will result in a * java.lang.UnsatisfiedLinkError exception ! */ public native String unimplementedStringFromJNI(); /* this is used to load the 'hello-jni' library on application * startup. The library has already been unpacked into * /data/data/com.example.HelloJni/lib/libhello-jni.so at * installation time by the package manager. */ static { System.loadLibrary("hello-jni"); // 声明使用lib 的文件名, 去掉 libhello-jni.so 中的lib 和 .so 字符后就是程序所要声明的lib 名称 }}
hello-jni.c 代码为:
/* * 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. * */ #include <string.h> #include <jni.h> /* This is a trivial JNI example where we use a native method * to return a new VM String. See the corresponding Java source * file located at: * * apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java */ jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz ) { return (*env)->NewStringUTF(env, "Hello from JNI !"); }jni/Android.mk 代码为:
# 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. # LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello-jni #编译后的Module LOCAL_SRC_FILES := hello-jni.c #要编译的源码文件 include $(BUILD_SHARED_LIBRARY)
你可以尝试修改函数名,以及替换字符串。来验证.so 调用正确与否。
为了验证 hello-jni.c 中大函数是引用包目录,现在我新建一个android test 项目使用MainActivity默认的类名称,使用button 来获得libhello-jni.so 中的字符串。
新包目录结构为 button com.example.button
其中MainActivity.java 代码为:
package com.example.button; import android.os.Bundle; import android.app.Activity; import android.graphics.Color; import android.view.View; import android.widget.TextView; public class MainActivity extends Activity { TextView mtxtPeri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mtxtPeri = (TextView)findViewById(R.id.txtPeri); //下面的代码用于为按钮注册一个监听 findViewById(R.id.button).setOnClickListener(new OnClickListener() { //下面的代码用于处理按钮点击后的事件 public void onClick(View v) { //下面的代码用于使背景变色 mtxtPeri.setText( stringFromJNI() ); // setContentView(mtxtPeri); findViewById(R.id.button).setBackgroundColor(Color.BLUE);Log.v("Test_fclose", stringFromJNI()); // Log cat 打印操作 } }); } public native String stringFromJNI(); /* This is another native method declaration that is *not* * implemented by 'hello-jni'. This is simply to show that * you can declare as many native methods in your Java code * as you want, their implementation is searched in the * currently loaded native libraries only the first time * you call them. * * Trying to call this function will result in a * java.lang.UnsatisfiedLinkError exception ! */ public native String unimplementedStringFromJNI(); /* this is used to load the 'hello-jni' library on application * startup. The library has already been unpacked into * /data/data/com.example.HelloJni/lib/libhello-jni.so at * installation time by the package manager. */ static { System.loadLibrary("hello-jni"); } }
XML 文件修改
res/layout/activity_main.xml 代码为:<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <TextView android:id="@+id/txtPeri" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>这时编译运行的时候就会报错,应为对应的libs 对应的 包目录不对。 所以需要重新编译修改.so 文件。只需要将原有的hello-jni.c 的函数名修改为:
Java_com_example_button_MainActivity_stringFromJNI()
就像我前面所说的: Java 为语言, com.example.button 为包目录, MainActivity 为class 名,stringFromJNI 为class 类中实际调用的接口。(这一部分纯属我个人理解)
1.然后重新编译,将生成的.so 文件替换原有的就行。
2. run
点击按钮能获得我们改写的字符串就代表验证成功。
代码分析中若有出错,还望多多指正。