android JNI笔记
来源:互联网 发布:手机淘宝没有投诉卖家 编辑:程序博客网 时间:2024/05/19 16:02
第一个例子
//Hello.c文件:#include <string.h>#include <jni.h>jstring Java_org_wangliang_ndktest_MainActivity_getGreetings(JNIEnv *env, jobject javaThis) { return (*env)->NewStringUTF(env, "Hello from native code!");}JNIEnv 类型代表了java环境 通过JNIEnv* 指针,就可以对java端的代码进行操作.
1、创建java类的对象,调用java对象的方法
2、获取java对象的属性 等等.
jobject obj 就是当前方法所在的类
//Android.mk文件LOCAL_PATH := $(call my-dir)#此文件目录include $(CLEAR_VARS)#库的名字(会加上lib)LOCAL_MODULE := Greet#源文件LOCAL_SRC_FILES := Hello.c#动态库include $(BUILD_SHARED_LIBRARY)
Android.mk 的含义
LOCAL_PATH:=$(call my-dir)
LOCAL_PATH是定义源文件目录.my-dir 是个定义的宏方法, $(call my-dir)就是调用这个叫 my-dir的宏方法,这个方法返回值就是Android.mk文件所在的目录
include $(CLEAR_VARS)
CLEAR_BARS 变量是build system里面的一个变量,这个变量指向了所有的类似 LOCAL_XXX的变量,
执行完这一句话, 这个编译系统就把所有的类似LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_STATIC_LIBRARIES,...这样的变量都清除掉,但是不会清除掉 LOCAL_PATH
LOCAL_MODULE 就是你要生成的库的名字,这个名字要是唯一的.不能有空格.编译后系统会自动在前面加上lib的头, 比如说我们的Hello 就编译成了libHello.so还有个特点就是如果你起名叫libHello 编译后ndk就不会给你的module名字前加上lib了,但是你最后调用的时候 还是调用Hello这个库
LOCAL_SRC_FILES = :Hello.c这个是指定你要编译哪些文件,不需要指定头文件 ,引用哪些依赖, 因为编译器会自动找到这些依赖自动编译
include $(BUILD_SHARED_LIBRARY) BUILD_STATIC_LIBRARY.so编译后生成的库的类型,如果是静态库,配置include $(BUILD_STATIC_LIBRARY)
别的参数:
LOCAL_CPP_EXTENSION := cc //指定c++文件的扩展名
LOCAL_MODULE := ndkfoo
LOCAL_SRC_FILES := ndkfoo.cc
LOCAL_LDLIBS += -llog -lvmsagent -lmpnet -lmpxml -lH264Android 指定需要加载一些别的什么库.
主文件org.wangliang.ndktest.MainActivity://主文件org.wangliang.ndktest.MainActivity:package org.wangliang.ndktest;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.widget.Toast;public class MainActivity extends Activity {static{System.loadLibrary("Greet");//载入库(库的名字libGreet.so)}public native String getGreetings(); public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } public void get(View v){ String greetings = getGreetings();//调用C的方法 Toast.makeText(this, greetings, 0).show(); }}使用javah输出头文件
Javah:C:\>javah -classpath E:\wangliang\JAVAEE_Work\NdkProject\bin -d E:\ org.wangliang.ndktest.MainActivity
javap获得方法签名
javap -s 路径C:\Documents and Settings\Administrator>javap -s -classpath E:\Soft\workspace\IntentReceiver\bin org.wangliang.intentreceiver.SignatureCompiled from "Signature.java"public class org.wangliang.intentreceiver.Signature extends java.lang.Object{public org.wangliang.intentreceiver.Signature(); Signature: ()Vpublic static void main(java.lang.String[]); Signature: ([Ljava/lang/String;)Vpublic void method1(byte, char, short, int, long); Signature: (BCSIJ)Vpublic void method2(java.lang.String, boolean, float, double); Signature: (Ljava/lang/String;ZFD)Vpublic void method3(java.sql.Date); Signature: (Ljava/sql/Date;)Vpublic void method4(byte[], char[], short[], int[], long[]); Signature: ([B[C[S[I[J)Vpublic java.util.List method5(java.lang.String[], boolean[], float[], double[]); Signature: ([Ljava/lang/String;[Z[F[D)Ljava/util/List;}对象和对象数组后加上;JNI中使用logcat
l 1、Android.mk文件增加:LOCAL_LDLIBS += -llog
l 2、C代码中增加
#include <android/log.h>#define LOG_TAG "logfromc"//共下面的宏使用(值是自定义的)#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)使用LOGI("log from c code ");//一个参数(因为就相当于printf)LOGI("x= %ld",x); //两个参数(因为就相当于printf)LOGD("y= %ld",y);C中调用java代码(在一个方法A中调用java,此方法A最终得被java调用)
1、通过类名获得类
2、类、方法名、签名获得方法id
3、通过方法id和调用对象obj执行方法
具体的
1、 jclass class = (*env)->FindClass(env,”完整类名”)
2、 jmethodId id = (*env)GetMethodId(env,class,”方法名”,”方法签名”)
3、(*env)->Callvoke<Type>Method(env,obj ,id);
或者(*env)->CallStatic<Type>Method(env,id,obj);
Java中调用C代码
1、 在java中声明native方法(如public static native void method())
2、 可以自己写C代码:导入包jni.h和string.h(若要记录信息,还要android/log.h,当然就要定义宏了),编写java中与native方法相应的的方法。其中方法名为Java_包名_类名_方法名,方法参数为(JNIEnv *env, jobject javaThis,native方法中的参数列表)
3、 不用2的方法,使用javah输出头文件,然后自己编写一个c文件,include刚才的头文件,把里面的方法拷贝过来,然后实现方法。但是机器生成的头文件的方法声明不太一样,会在方法返回值其那后分别加上JNIEXPORT 和JNICALL,比如:JNIEXPORT void JNICALL。
小结:
1.创建一个android工程
2.JAVA代码中写声明native 方法 public native String helloFromJNI();
3.用javah工具生成头文件
4. 创建jni目录,引入头文件,根据头文件实现c代码
5.编写Android.mk文件
6.Ndk编译生成动态库
7.Java代码load 动态库.调用native代码
例子:
//DataProvider.java//==========package org.wangliang.ndk01.test;import android.content.Context;import android.widget.Toast;public class DataProvider {Context context;public DataProvider(Context context){this.context = context;}public native void greetToC(String greetings);public void greetToJava(String greetings){String text = " "+greetings+" to JAVA";Toast.makeText(context, text, 1).show();}}//Activity01.java//=================package org.wangliang.ndk01.test;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.widget.EditText;public class Activity1 extends Activity {private EditText text;private DataProvider provider;static{System.loadLibrary("Greet01");}/** * java-->c-->java */ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); text = (EditText) findViewById(R.id.text); provider = new DataProvider(this); } public void greet(View v){ String greetings = text.getText().toString(); provider.greetToC(greetings); }}Main.xml<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="fill_parent"android:layout_height="fill_parent"><EditText android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content"/><Button android:text="问候"android:layout_width="fill_parent" android:layout_height="wrap_content"android:gravity="center"android:onClick="greet"/></LinearLayout>
编写C文件位置:/NDK01/jni/org_wangliang_ndk01_test_DataProvider.h/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class org_wangliang_ndk01_test_DataProvider */#ifndef _Included_org_wangliang_ndk01_test_DataProvider#define _Included_org_wangliang_ndk01_test_DataProvider#ifdef __cplusplusextern "C" {#endif/* * Class: org_wangliang_ndk01_test_DataProvider * Method: greetToC * Signature: (Ljava/lang/String;)V */JNIEXPORT void JNICALL Java_org_wangliang_ndk01_test_DataProvider_greetToC (JNIEnv *, jobject, jstring);#ifdef __cplusplus}#endif#endif位置:/NDK01/jni/Greet01.c#include "org_wangliang_ndk01_test_DataProvider.h"#include <string.h>//jstring--> char* char* Jstring2CStr(JNIEnv* env , jstring jstr){ char* rtn = NULL; jclass clsstring = (*env)->FindClass(env,"java/lang/String"); jstring strencode = (*env)->NewStringUTF(env,"GB2312"); jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B"); // 相当于String .getByte("GB2312"); jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); jsize alen = (*env)->GetArrayLength(env,barr); jbyte* ba = (*env)->GetByteArrayElements(env,barr,JNI_FALSE); if(alen > 0){ rtn = (char*)malloc(alen+1); //new char[alen+1]; "\0" memcpy(rtn,ba,alen); rtn[alen]=0; } (*env)->ReleaseByteArrayElements(env,barr,ba,0); //释放内存 return rtn;}JNIEXPORT void JNICALL Java_org_wangliang_ndk01_test_DataProvider_greetToC (JNIEnv *env, jobject obj, jstring greetings){ char* className = "org/wangliang/ndk01/test/DataProvider"; jclass clazz = (*env)->FindClass(env,className); jmethodID methodID = (*env)->GetMethodID(env,clazz,"greetToJava","(Ljava/lang/String;)V"); char* text = strcat(Jstring2CStr(env,greetings),"to C and Trans "); (*env)->CallVoidMethod(env,obj,methodID,(*env)->NewStringUTF(env,text));}
编写Android.mk文件LOCAL_PATH := $(call my-dir)#此文件目录include $(CLEAR_VARS)#库的名字(会加上lib)LOCAL_MODULE := Greet01#源文件LOCAL_SRC_FILES := Greet01.c#动态库include $(BUILD_SHARED_LIBRARY)最后$ ndk-build
结果在再写几个简单的函数
做更多的事情:#include "org_wangliang_ndk01_test_DataProvider.h"#include <string.h>#include <stdlib.h>char* Jstring2CStr(JNIEnv* env , jstring jstr){//工具方法 char* rtn = NULL; jclass clsstring = (*env)->FindClass(env,"java/lang/String"); jstring strencode = (*env)->NewStringUTF(env,"GB2312"); jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B"); // 相当于String .getByte("GB2312"); jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); jsize alen = (*env)->GetArrayLength(env,barr); jbyte* ba = (*env)->GetByteArrayElements(env,barr,JNI_FALSE); if(alen > 0){ rtn = (char*)malloc(alen+1); //new char[alen+1]; "\0" memcpy(rtn,ba,alen); rtn[alen]=0; } (*env)->ReleaseByteArrayElements(env,barr,ba,0); //释放内存 return rtn;}/* * Class: org_wangliang_ndk01_test_DataProvider * Method: greetToC * Signature: (Ljava/lang/String;)V */JNIEXPORT void JNICALL Java_org_wangliang_ndk01_test_DataProvider_greetToC //调用java的greetToJava (JNIEnv *env, jobject obj, jstring greetings){ char* className = "org/wangliang/ndk01/test/DataProvider"; jclass clazz = (*env)->FindClass(env,className); jmethodID methodID = (*env)->GetMethodID(env,clazz,"greetToJava","(Ljava/lang/String;)V"); char* text = strcat(Jstring2CStr(env,greetings),"to C and Trans "); (*env)->CallVoidMethod(env,obj,methodID,(*env)->NewStringUTF(env,text));}/* * Class: org_wangliang_ndk01_test_DataProvider * Method: swap01 * Signature: ([III)V */JNIEXPORT void JNICALL Java_org_wangliang_ndk01_test_DataProvider_swap01//不返回值交换数组数据 (JNIEnv *env, jobject obj, jintArray arr, jint i, jint j){ int len = (*env)->GetArrayLength(env,arr);//c语言中没法在被调用的方法中获得数组长度(因为传入的是指针,sizeof(p)==4) if(len = 0)return ; jint* p = (*env)->GetIntArrayElements(env,arr,0); jint tmp = *(p+i); *(p+i) = *(p+j); *(p+j) = tmp; }/* * Class: org_wangliang_ndk01_test_DataProvider * Method: swap02 * Signature: ([III)[I */JNIEXPORT jintArray JNICALL Java_org_wangliang_ndk01_test_DataProvider_swap02//返回值交换数组数据 (JNIEnv *env, jobject obj, jintArray arr, jint i, jint j){ int len = (*env)->GetArrayLength(env,arr); if(len = 0)return ; jint* p = (*env)->GetIntArrayElements(env,arr,0); jint tmp = *(p+i); *(p+i) = *(p+j); *(p+j) = tmp; return arr; }/* * Class: org_wangliang_ndk01_test_DataProvider * Method: addANum * Signature: ([II)[I */JNIEXPORT jintArray JNICALL Java_org_wangliang_ndk01_test_DataProvider_addANum//数组元素加上一个数 (JNIEnv *env, jobject obj, jintArray arr, jint num){// 1.获取到 arr的大小 int len = (*env)->GetArrayLength(env, arr);//上面为什么是jsize alen = (*env)->GetArrayLength(env,barr);而且memcpy(rtn,ba,alen); if(len==0){ return arr; } jint* p = (*env)-> GetIntArrayElements(env,arr,0); int i=0; for(;i<len;i++){ *(p+i) += num; } return arr; }/* * Class: org_wangliang_ndk01_test_DataProvider * Method: getCondition * Signature: (I)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_org_wangliang_ndk01_test_DataProvider_getCondition (JNIEnv *env, jobject obj, jint day){//jint如何转成int->char*(另一个问题char*-->int?) //需要调用static int getSales(int day) // char* className = "org/wangliang/ndk01/test/DataProvider"; jclass clazz = (*env)->FindClass(env,className); jmethodID methodID = (*env)->GetStaticMethodID(env,clazz,"getSales","(I)I");//有静态static //jint sales = (*env)->CallStaticIntMethod(env,clazz,methodID,1);//正确 long sales = (*env)->CallStaticIntMethod(env,clazz,methodID,day);//正确(jint和int都行?) char* condition ;//"The sales in ..."; char* d;//2 //itoa((int)sales, condition, 10);//stdlib.h中没有itoa方法(怎么把数字转变成字符串) //itoa((int)day, d, 10); //condition = strcat(strcat("The sales in ",d),condition); return (*env)->NewStringUTF(env,"hello world"); }
- android JNI 学习笔记
- android JNI 学习笔记
- android jni 学习笔记
- android JNI 学习笔记
- Android JNI 学习笔记
- android JNI笔记
- android JNI笔记
- android-jni项目笔记
- android JNI 学习笔记
- Android JNI学习笔记
- Android Jni开发笔记
- Android JNI 学习笔记
- Android Jni 基础笔记
- Android JNI开发笔记
- Android JNI 学习笔记
- Android JNI 自学笔记
- JNI 开发笔记 - Android JNI Tips
- android JNI 学习笔记1
- H.264视频的RTP荷载格式
- IE6和IE7不能识别display:inline-block的解决办法
- Wildcard
- 5个iOS应用开发者海外学习资源站推荐
- JAVA中重写自己的hashCode()方法原因
- android JNI笔记
- 第一博:Pl/Sql序列触发器的使用
- 9A
- syslog的使用方法个人小结
- 拒绝事倍功半:轻松生活达成卓越成就
- linux下DNS详解及应用之三
- Flex学习笔记(五) 动画效果
- vs中的主题配置
- 达尔文的眼睛