jni

c知识

stdlib 头文件即standard library标准库头文件 常用系统函数,跟系统调用相关的,比如内存申请malloc和释放free

stdio是标准io函数,比如printf和scanf函数 

windows和linux文件区别
windows     .exe     .dll    .bat

linux          .elf      .so     .sh

x86对 jni兼容性能很差

由于ndk一开始是做给linux下用的,所有wind下用ndk会有很多问题。
所以还要装个软件 cygwin
只要装2个功能 devel shells

ndk环境变量设置

windows下   1.直接解压缩ndk,然后搭建环境变量. 在path目录下面C:\android-ndk-r7b .  这是直接在cmd命令行下运行   ndk-build

Cygwin Terminal下   这个配置环境变量在  cygwin/etc/profile的32行

/cygdrive/c/android-ndk-r7b   把这个添加   不同ndk的安装路径不一样

每个环境变量用:分隔.

在cygwin下配置了环境便利ndk但是在别的目录 运行ndk-build一直找不到目录 .

执行./ndk-build -C samples/hello-jni 这个代码可解决   博客:http://blog.sina.com.cn/s/blog_4c73bcc80101177e.html

Jni.h 目录:C:\android-ndk-r7b\platforms\android-14\arch-arm\usr\include

log.h目录:C:\android-ndk-r7b\platforms\android-14\arch-arm\usr\include\android

实现步骤

1 定义一个c方法的接口   相当于在java代码中定义了一个接口 接口的实现方法是C语言实现的

2 步 实现C代码

3步骤 创建android.mk  告诉编译器 如何把c代码打包成函数库

4步 把c代码 打包成函数库  用到了安装的环境   通过cygwin terminal

5 步在java代码中 引入库函数

static{
System.loadLibrary("hello");// 注意事项 去掉前面的lib 后面的.so
}
6 使用方法

Anroid.mk 文件
LOCAL_PATH := $(call my-dir) // 返回当前c代码目录
include $(CLEAR_VARS) // 清楚了所有 已local 开头的配置文件 唯独不清楚LOCAL_PATH

LOCAL_MODULE := hello // 库函数的名字 严格遵守makefile 格式 lib .so 如果前面加lib 不会自动生成了
LOCAL_SRC_FILES := Hello.c
include $(BUILD_SHARED_LIBRARY) // 加入库函数

jni 常见的错误
1错误1 忘记方法的参数
2 错误2 203-28 03:41:56.758: E/AndroidRuntime(821): java.lang.UnsatisfiedLinkError: Native method not found: com.example.error.DemoActivity.helloWorld:()Ljava/lang/String;   方法名错误
3 错误3 一般没有日志打印 直接报错工程停止 一般c代码有运行错误
4 错误4 在交叉编译的工具链上报错 c代码有编译错误 比如 一些函数没有声明 一些类型没有声明 少符号
5 错误5 没有Android.mk 文件
6 错误6 Android.mk 文件有错 
7 错误7 引用别人.so 函数库 需要你自己native方法对应类的包名 和之前打包成.so函数库的包名一致

使用javah时 有时一直报错:找不到类文件   要添加环境变量classpath

把安卓adt    adt\adt\adt-bundle-windows-x86_64-20140702\sdk\platforms\android-10

这个目录下的android.jar 解压出来.然后把这个目录放在classpath里面加入

例:   classpath:.;D:\Program Files\Android\android-sdk\platforms\android-8\android

然后到src目录下   javah 包名.类名.  如果报错找不到类文件就到  bin/classes下

获取方法签名:

使用javap -s 获取内部类型签名  这个在反射方法时候要用到

在bin/classes 下执行:javap -s 包名.类名字


1

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__ )<br>解释:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

可变参数宏 ...和__VA_ARGS_ _

__VA_ARGS__ 是一个可变参数的宏,很少人知道这个宏,这个可变参数的宏是新的C99规范中新增的,目前似乎只有gcc支持(VC6.0的编译器不支持)。

实现思想就是宏定义中参数列表的最后一个参数为省略号(也就是三个点)。这样预定义宏_ _VA_ARGS_ _就可以被用在替换部分中,替换省略号所代表的字符串。比如:

#define PR(...) printf(__VA_ARGS__)

int main()

{

    int wt=1,sp=2;

    PR("hello\n");

    PR("weight = %d, shipping = %d",wt,sp);

    return 0;

}

输出结果:

hello

weight = 1, shipping = 2

省略号只能代替最后面的宏参数。

#define W(x,...,y)错误!

  


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

把java里的string转成c里面的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");

     jbyteArray   barr=   (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");

     jsize   alen   =   (*env)->GetArrayLength(env,barr);

     jbyte*   ba   =   (*env)->GetByteArrayElements(env,barr,JNI_FALSE);

     if(alen   >   0)

     {

      rtn   =   (char*)malloc(alen+1);         //"\0"

      memcpy(rtn,ba,alen);

      rtn[alen]=0;

     }

     (*env)->ReleaseByteArrayElements(env,barr,ba,0);  //

     return rtn;

}

  


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

通过反射 调用java代码   原理一样

    

java里面的反射

    Class<?> forName = Class.forName("com.example.ndkcallback.DataProvider");

        Method declaredMethod = forName.getDeclaredMethod("helloFromJava", new Class[]{});

        declaredMethod.invoke(forName.newInstance(), new Object[]{});

        

c里面反射java

    ///jclass      (*FindClass)(JNIEnv*, const char*);

    jclass clazz=(*env)->FindClass(env,"com/example/ndkcallback/DataProvider");

    //  jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);

    // 方法签名  参数和返回值

    jmethodID methodId=(*env)->GetMethodID(env,clazz,"helloFromJava","()V");

    // void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);

    (*env)->CallVoidMethod(env,jobject,methodId);

  

第一个:helloworld

创建jni目标.

创建Hello.c

#include<stdio.h>
#include<jni.h>

jstring Java_com_example_myhello_MainActivity_helloworldFromc(JNIEnv* env,jobject obj){
    return (*env)->NewStringUTF(env,"onehello");
}

创建Android.mk

LOCAL_PATH := $(call my-dir)

   include $(CLEAR_VARS)

   LOCAL_MODULE    := hello
   LOCAL_SRC_FILES := Hello.c

   include $(BUILD_SHARED_LIBRARY)

然后activity里面加载library

package com.example.myhello;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {

    public native String helloworldFromc();

    static{
        System.loadLibrary("hello");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void click(View view) {
        // TODO Auto-generated method stub
        Toast.makeText(getApplicationContext(), helloworldFromc(), 0).show();
    }
}

c代码调用java代码事例

要调用的方法


1

2

3

4

5

6

7

package com.example.threehello;

public class DataProvider {

    public native int add(int x,int y);

    public native String sayHello(String s);

    public native int[] intMethod(int []iNum);

}

在c里面的实现


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

#include <stdio.h>

#include <com_example_threehello_DataProvider.h>

#include <android/log.h>  //调用java代码log的时候导入这个头文件

#include <string.h>

#define LOG_TAG "clog"

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__ )

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__ )

char* Jstring2CStr(JNIEnv*   env,   jstring   jstr) //java里的string转 c的char*

{

     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");

     jbyteArray   barr=   (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");

     jsize   alen   =   (*env)->GetArrayLength(env,barr);

     jbyte*   ba   =   (*env)->GetByteArrayElements(env,barr,JNI_FALSE);

     if(alen   >   0)

     {

      rtn   =   (char*)malloc(alen+1);         //"\0"

      memcpy(rtn,ba,alen);

      rtn[alen]=0;

     }

     (*env)->ReleaseByteArrayElements(env,barr,ba,0);  //

     return rtn;

}

JNIEXPORT jint JNICALL Java_com_example_threehello_DataProvider_add

  (JNIEnv * env, jobject jobject, jint x, jint y){

    LOGD("x=%d",x);

    LOGI("y=%d",y);

    return x+y;

}

JNIEXPORT jstring JNICALL Java_com_example_threehello_DataProvider_sayHello

  (JNIEnv * env, jobject jobject, jstring str){

    //jstring NewStringUTF(const char* bytes)

    char *c="hello";

    char *strs = Jstring2CStr(env,str);

    strcat(strs,c);

    LOGD("%s",strs);

    return (*env)->NewStringUTF(env,strs);

}

JNIEXPORT jintArray JNICALL Java_com_example_threehello_DataProvider_intMethod

  (JNIEnv * env, jobject jobject, jintArray jarray){

    //    jsize       (*GetArrayLength)(JNIEnv*, jarray);

    //  jint*       (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);

    int length = (*env)->GetArrayLength(env,jarray);

    int *array = (*env)->GetIntArrayElements(env,jarray,0);

    int i=0;

    for(;i<length;i++){

        *(array+i)+=5;

    }

    return jarray;

}

c代码调用java代码  log

先导入  头文件 :    #include <android/log.h>

在  Android.mk 里面加入  LOCAL_LDLIBS += -llog  这个动态链接库在C:\android-ndk-r7b\platforms\android-14\arch-arm\usr\lib 目录下

c代码回调java代码

事例


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

package com.example.fourhello;

public class DataProvider {

    

    public void helloFromJava(){

        System.out.println("haha我被调用了");

    }

    

    public int Add(int x,int y){

        int result = x+y;

        System.out.println(result);

        return result;

    }

    

    public void printString(String s){

        System.out.println(s);

    }

    public native void callMethod1();

    public native void callMethod2();

    public native void callMethod3();

}

  

相当于java的反射


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

#include<stdio.h>

#include<string.h>

#include<com_example_fourhello_DataProvider.h>

JNIEXPORT void JNICALL Java_com_example_fourhello_DataProvider_callMethod1

  (JNIEnv * env, jobject jobject){

    //jclass      (*FindClass)(JNIEnv*, const char*);

    //    jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);

    //void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);

    jclass clazz = (*env)->FindClass(env, "com/example/fourhello/DataProvider");

    jmethodID methodID = (*env)->GetMethodID(env,clazz,"helloFromJava","()V");

    (*env)->CallVoidMethod(env,jobject,methodID);

}

JNIEXPORT void JNICALL Java_com_example_fourhello_DataProvider_callMethod2

  (JNIEnv * env, jobject jobject){

    jclass clazz = (*env)->FindClass(env, "com/example/fourhello/DataProvider");

    jmethodID methodID = (*env)->GetMethodID(env,clazz,"Add","(II)I");

    //    jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);

    (*env)->CallIntMethod(env,jobject,methodID,3,5);

}

JNIEXPORT void JNICALL Java_com_example_fourhello_DataProvider_callMethod3

  (JNIEnv * env, jobject jobject){

    jclass clazz = (*env)->FindClass(env, "com/example/fourhello/DataProvider");

    jmethodID methodID = (*env)->GetMethodID(env,clazz,"printString","(Ljava/lang/String;)V");

    //    jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);

    //jstring     (*NewStringUTF)(JNIEnv*, const char*);

    jstring str = (*env)->NewStringUTF(env,"i do call back");

    (*env)->CallVoidMethod(env,jobject,methodID,str);

}

  

c代码调用java 其他类里的方法


1

2

3

4

5

6

7

public class MainActivity extends Activity {

    public void hellocall(){

        System.out.println("main activity callback");

    }

    

}

  


1

2

3

4

5

6

7

8

JNIEXPORT void JNICALL Java_com_example_fourhello_DataProvider_callMethod4

  (JNIEnv * env, jobject j){

    jclass clazz = (*env)->FindClass(env, "com/example/fourhello/MainActivity");

    jmethodID methodID = (*env)->GetMethodID(env,clazz,"hellocall","()V");

    //jobject     (*AllocObject)(JNIEnv*, jclass);  获取jobject对象

    jobject jj = (*env)->AllocObject(env,clazz);

    (*env)->CallVoidMethod(env,jj,methodID);

}

  

c代码回调java的静态方法


1

2

3

public static void mystatic(){

    System.out.println("呵呵我是静态方法");

}

  


1

2

3

4

5

6

7

8

JNIEXPORT void JNICALL Java_com_example_fourhello_DataProvider_callMethod5

  (JNIEnv * env, jobject jobject){

    jclass clazz = (*env)->FindClass(env, "com/example/fourhello/DataProvider");

//  jmethodID   (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);

    jmethodID methodID = (*env)->GetStaticMethodID(env,clazz,"mystatic","()V");

//    void        (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);

    (*env)->CallStaticVoidMethod(env,clazz,methodID);

}

  

jni在项目开发的用途  通过jni直接调用c方法


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

package com.example.fivehello;

import android.app.Activity;

import android.os.Bundle;

import android.view.Menu;

import android.view.MenuItem;

import android.view.View;

import android.widget.Toast;

public class MainActivity extends Activity {

    static{

        System.loadLibrary("hello");

    }

    public native int login(String password);

    

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

    }

    

    public void onclick(View view){

        int login = login("123");

        Toast.makeText(getApplicationContext(), login+"", 0).show();

    }

}

  


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

#include<stdio.h>

#include<com_example_fivehello_MainActivity.h>

#include<string.h>

int login(char* psw){

    char* rightword = "123";

    int i = strcmp(rightword,psw);

    if(i==0){

        return 200;

    }else{

        return 302;

    }

}

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");

     jbyteArray   barr=   (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");

     jsize   alen   =   (*env)->GetArrayLength(env,barr);

     jbyte*   ba   =   (*env)->GetByteArrayElements(env,barr,JNI_FALSE);

     if(alen   >   0)

     {

      rtn   =   (char*)malloc(alen+1);         //"\0"

      memcpy(rtn,ba,alen);

      rtn[alen]=0;

     }

     (*env)->ReleaseByteArrayElements(env,barr,ba,0);  //

     return rtn;

}

JNIEXPORT jint JNICALL Java_com_example_fivehello_MainActivity_login

  (JNIEnv * env, jobject jobject, jstring str){

    char *c = Jstring2CStr(env,str);

    return login(c);

}

时间: 2024-08-03 22:17:26

jni的相关文章

Delphi使用android的NDK是通过JNI接口,封装好了,不用自己写本地代码,直接调用

一.Android平台编程方式:      1.基于Android SDK进行开发的第三方应用都必须使用Java语言(Android的SDK基于Java实现)      2.自从ndk r5发布以后,已经允许完全用C/C++ 来开发应用或者游戏,而不再需要编写任何Java 的代码   Android程序运行在Dalvik虚拟机中,NDK允许用户使用类似C / C++之类的原生代码语言执行部分程序. 二.跨平台移动开发   Delphi使用android的NDK是通过JNI接口,封装好了,不用自己

[转]Ubuntu下使用Jni开发例子

http://www.cnblogs.com/zxglive2006/archive/2012/01/15/2323110.html 先用eclipse 创建 Java Project; 然后直接在项目中添加Prompt.java文件,放在default package下(最好不要添加包,否则容易出错). 1. 编写Java文件,在其中声明native方法, 并通过static 语句块加载动态链接库,示例Prompt.java代码如下: class Prompt { private native

Android中JNI调用时出现accessed stale local reference的问题

之前在做一个native的模块时遇到这样一个问题: 代码运行在android2.3上没有任何问题,可是在4.2上运行时报出了:JNI ERROR (app bug): accessed stale local reference 的错误. 后来在StackOverflow上找到了问题的答案.简单来说就是  4.0以上的android系统GC在垃圾回收时为了减少内存碎片,会对内存进行整理,整理时必然会移动对象的内存地址,这时C代码的指针还指向原来对象的地址,这时该对象已经被移动到了其他位置,因此会

JTI + JNI,为Java程序提供获取JVM内部信息的通道

首先,JTI是啥? HotSpot JVM是使用C++写的,在操作系统层面来看,java.exe进程与其他进程并无特别之处.任何一个进程都可以加载第三方的DLL,JTI就是java.exe开放出来的向Java.exe进程注入dll的接口.也就是说,开发者根据JTI定义好的规范,用C++写一个dll,这个dll就可以被java.exe进程加载了[启动jvm的时候要加上-agentlib参数]. JTI的详细资料参见以下网址:http://docs.oracle.com/javase/7/docs/

JNI基础学习

1.JNI(Java Native Interface): 它允许Java代码和其他语言写的代码进行交互,JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了.下图是java与c的交互表现: 2.JNI的编写与编译流程: 1)编写java文件,声名Native方法 2)javac编译java文件 3)javah -jni 编译生成Native方法的头文件 4)用c/c++实现Native方法 5)编译Native方法 6)在JVM运

JNI/NDK开发指南(三)——JNI数据类型及与Java数据类型的映射关系

转载请注明出处:http://blog.csdn.net/xyang81/article/details/42047899 当我们在调用一个Java native方法的时候,方法中的参数是如何传递给C/C++本地函数中的呢?Java方法中的参数与C/C++函数中的参数,它们之间是怎么转换的呢?我猜你应该也有相关的疑虑吧,咱们先来看一个例子,还是以HelloWorld为例: HelloWorld.java: package com.study.jnilearn; class MyClass {}

android使用c通过jni回调java

很多场合都有这样的需求,由于以前都是java调用c的接口,没有做过回调,今天花了大半天时间把这个流程跑通了,记录一下,以备后用.这里发句牢骚,那些网上分享出来的代码,请问你们确实是能正常工作吗?还有查来查去都是那几份,大家转载精神可嘉啊 jni相关头文件代码 /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class com_example_ndktest_CallbackTest */ #

jni ndk 入门

1. Linux环境模拟,下载sygwin 安装,选择devl 和shell -> install sygwin 中的配置ndk环境,进入安装目录c:/cygwin64 etc/profile文件配置ndk的环境 //37行 PATH="/usr/local/bin:/usr/bin:/cygdrive/d/android-ndk-r9d-windows-x86_64/android-ndk-r9d${PATH:+:${PATH}}" 2. 下载ndk 3. 开发,参考于ndk/

在 Linux 平台下使用 JNI

引言 Java 的出现给大家开发带来的极大的方便.但是,如果我们有大量原有的经过广泛测试的非 Java 代码,将它们全部用 Java 来重写,恐怕会带来巨大的工作量和长期的测试:如果我们的应用中需要访问到特定的设备,甚至是仅符合公司内部信息交互规范的设备,或某个特定的操作系统才有的特性,Java 就显得有些力不从心了.面对这些问题,Sun 公司在 JDK1.0 中就定义了 JNI 规范,它规定了 Java 应用程序对本地方法的调用规则. 实现步骤及相关函数使用 本文将一步步说明在 Linux 平

Java中JNI的使用详解第一篇:HelloWorld

今天开始研究JNI技术,首先还是老套路,输出一个HelloWorld:具体流程如下:在Java中定义一个方法,在C++中实现这个方法,在方法内部输出"Hello World",然后再回到Java中进行调用.分为以下步骤: 第一步:在Eclipse中建立一个类:JNIDemo 1 package com.jni.demo; 2 public class JNIDemo { 3 //定义一个本地方法 4 public native void sayHello(); 5 public sta