一下是用eclipe ide实现的ndk开发的jni的例子。
目录结构如下:
E:.
├─.settings
├─assets
├─bin
│ ├─classes
│ │ ├─android
│ │ │ └─support
│ │ │ └─v7
│ │ │ └─appcompat
│ │ └─com
│ │ └─example
│ │ └─jnitest
│ ├─dexedLibs
│ └─res
│ └─crunch
│ ├─drawable-hdpi
│ ├─drawable-mdpi
│ ├─drawable-xhdpi
│ └─drawable-xxhdpi
├─gen
│ ├─android
│ │ └─support
│ │ └─v7
│ │ └─appcompat
│ └─com
│ └─example
│ └─jnitest
├─jni
├─libs
│ └─armeabi
├─obj
│ └─local
│ └─armeabi
│ └─objs
│ └─StringJni
├─res
│ ├─drawable-hdpi
│ ├─drawable-ldpi
│ ├─drawable-mdpi
│ ├─drawable-xhdpi
│ ├─drawable-xxhdpi
│ ├─layout
│ ├─menu
│ ├─values
│ ├─values-v11
│ ├─values-v14
│ └─values-w820dp
└─src
└─com
└─example
└─jnitest
目录简单说明下,assets res都是资源文件,obj libs gen bin都是生成的,src是我们需要的java源代码目录,jni是c/c++源代码目录。
我先以最简单从native cpp返回一个字符串的用例讲下ndk jni开发的完整结构.
首先写两个类,一个是有用显示的MainActivity类,另一个用于专门jni的StringJni java类。
MaianActivity.java
package com.example.jnitest; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends ActionBarActivity { private TextView Stirngformjni; private String str; private TextView sum; private int tmp; private String sumStr; private TextView init2DArray; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 1. jni native string to java string Stirngformjni = (TextView) findViewById(R.id.stirngformjni); StringJni stringJni = new StringJni(); str = stringJni.stringjni(); str = "1. " + str ; Stirngformjni.setText(str); //2.jni string to native stringJni.stringTojni("hello"); //3.jni native int to java int sum = (TextView) findViewById(R.id.sum); JniAdd jniAdd = new JniAdd(); tmp = jniAdd.Add(2, 8); sumStr = tmp +" "; sum.setText(sumStr); //4. jintArray int[] int sum =0; IntArray intArray = new IntArray(); int[] int_array = {1,2,3,4,5} ; sum = intArray.SumIntArray(int_array); Toast.makeText(this, "this is intArray sum from jni: "+sum, Toast.LENGTH_SHORT).show(); //5. int[][] from native init2DArray = (TextView) findViewById(R.id.init2DArray); Int2DArray init2DArry = new Int2DArray(); int[][]i2dArray = init2DArry.initInt2DArray(10); StringBuilder strd = new StringBuilder(); for(int i=0; i<i2dArray.length;i++){ for(int j=0; j<i2dArray[i].length;j++){ strd.append(i2dArray[i][j]+" "); } } init2DArray.setText(strd ); //6. c++ access java class data and method JavaClassAccess jclassAccess = new JavaClassAccess(); jclassAccess.nativeMethod(); Log.d("MainActivity", "wanlihua debug JavaClassAccess num value before: " + jclassAccess.num); //ClassC classC = new ClassC(0.007); ClassC.nativeMethodC(); Log.d("MainActivity", "wanlihua debug ClassC.nativeMethodC num value after: " + ClassC.getD()); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
StringJni.java
package com.example.jnitest; public class StringJni { static { System.loadLibrary("StringJni"); } public native String stringjni(); public native void stringTojni(String str); }
然后把StringJni.java用javah生成c/c++调用的.h文件
在eclipse开发环境下,进到HelloJni\bin\classes 目录下,
输入 javah -d ../../jni com.example.jnitest.JavaClassAccess
则在代码根目录生成jni目录,并生成com_example_jnitest_StringJni.h
如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_jnitest_StringJni */ #ifndef _Included_com_example_jnitest_StringJni #define _Included_com_example_jnitest_StringJni #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_jnitest_StringJni * Method: stringjni * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_example_jnitest_StringJni_stringjni (JNIEnv *, jobject); /* * Class: com_example_jnitest_StringJni * Method: stringTojni * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_com_example_jnitest_StringJni_stringTojni (JNIEnv *, jobject, jstring); #ifdef __cplusplus } #endif #endif
然后这样就编写c/cpp代码并include该头文件。
#include <jni.h> #include "com_example_jnitest_StringJni.h" #include <android/log.h> #include <stdio.h> //#include <utils/Log.h> //#include "cutils/log.h" #define TAG "StringJni" #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)) JNIEXPORT jstring JNICALL Java_com_example_jnitest_StringJni_stringjni (JNIEnv *env, jobject obj){ //LOG_PRI (ANDROID_LOG_WARN, NXPLOG_ITEM_EXTNS, __VA_ARGS__); LOGD("XXX debug Java_com_example_jnitest_StringJni_stringjni!!!"); __android_log_print(ANDROID_LOG_DEBUG,"StringJni","XXX debug Java_com_example_jnitest_StringJni_stringjni __android_log_print"); return env->NewStringUTF("i'm from stringjni"); }
然后在写上对这个jni目录的源码写上android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := StringJni LOCAL_SRC_FILES := StringJni.cpp LOCAL_LDLIBS := -llog #LOCAL_SHARED_LIBRARIES := liblog LOCAL_PROGUARD_ENABLED:= disabled include $(BUILD_SHARED_LIBRARY)
然后在MainActivity中加入
// 1. jni native string to java string Stirngformjni = (TextView) findViewById(R.id.stirngformjni); StringJni stringJni = new StringJni(); str = stringJni.stringjni(); str = "1. " + str ; Stirngformjni.setText(str);
调用native 本地方法。
然后而eclipse设置过ndk环境,这时候就可以直接编译app了。大功告成。
然后把别的 在natvie实现加法,数组传递,c++调用java的属性等等都贴出来。
JniAdd.java :cpp实现算法(加法)
package com.example.jnitest; public class JniAdd { static { System.loadLibrary("StringJni"); } public native int Add(int a,int b); }JniTest/jni/com_example_jnitest_JniAdd.h
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_jnitest_JniAdd */ #ifndef _Included_com_example_jnitest_JniAdd #define _Included_com_example_jnitest_JniAdd #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_jnitest_JniAdd * Method: Add * Signature: (II)I */ JNIEXPORT jint JNICALL Java_com_example_jnitest_JniAdd_Add (JNIEnv *, jobject, jint, jint); #ifdef __cplusplus } #endif #endif
IntArray.java :传递一维整型数组
package com.example.jnitest; public class IntArray { static { System.loadLibrary("StringJni"); } public native int SumIntArray (int[]arr); }
JniTest/jni/com_example_jnitest_IntArray.h
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_jnitest_IntArray */ #ifndef _Included_com_example_jnitest_IntArray #define _Included_com_example_jnitest_IntArray #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_jnitest_IntArray * Method: Add * Signature: ([I)I */ JNIEXPORT jint JNICALL Java_com_example_jnitest_IntArray_SumIntArray (JNIEnv *, jobject, jintArray); #ifdef __cplusplus } #endif #endif
Int2DArray.java : 传递二维数组,二维数组会作为一个object处理
package com.example.jnitest; public class Int2DArray { static { System.loadLibrary("StringJni"); } public native int[][] initInt2DArray (int size); }
JniTest/jni/com_example_jnitest_Int2DArray.h
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_jnitest_Int2DArray */ #ifndef _Included_com_example_jnitest_Int2DArray #define _Included_com_example_jnitest_Int2DArray #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_jnitest_Int2DArray * Method: initInt2DArray * Signature: (I)[[I */ JNIEXPORT jobjectArray JNICALL Java_com_example_jnitest_Int2DArray_initInt2DArray (JNIEnv *, jobject, jint); #ifdef __cplusplus } #endif #endif
JavaClassAccess.java : c/c++访问java成员和成员函数。
package com.example.jnitest; import android.util.Log; public class JavaClassAccess { String str = "smj"; int num = 8; public native void nativeMethod(); private void javaMethod(){ System.out.println("call java method sucessful!"); Log.d("JavaClassAccess", "wanlihua debug start from native callback!!!"); } static{ System.loadLibrary("StringJni"); } }
JniTest/jni/com_example_jnitest_JavaClassAccess.h
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_jnitest_JavaClassAccess */ #ifndef _Included_com_example_jnitest_JavaClassAccess #define _Included_com_example_jnitest_JavaClassAccess #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_jnitest_JavaClassAccess * Method: nativeMethod * Signature: ()V */ JNIEXPORT void JNICALL Java_com_example_jnitest_JavaClassAccess_nativeMethod (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif