jni

c知识html

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

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

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

linux          .elf      .so     .shlinux

 

 

x86对 jni兼容性能不好android

因为ndk一开始是作给linux下用的,全部wind下用ndk会有不少问题。
因此还要装个软件 cygwin
只要装2个功能 devel shellsshell

 

ndk环境变量设置windows

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

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

/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);
}
相关文章
相关标签/搜索