码迷,mamicode.com
首页 > 其他好文 > 详细

jni

时间:2014-10-28 23:31:11      阅读:294      评论:0      收藏:0      [点我收藏+]

标签:android   blog   http   io   color   os   ar   使用   java   

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

bubuko.com,布布扣
LOCAL_PATH := $(call my-dir)

   include $(CLEAR_VARS)

   LOCAL_MODULE    := hello
   LOCAL_SRC_FILES := Hello.c

   include $(BUILD_SHARED_LIBRARY)
bubuko.com,布布扣

然后activity里面加载library

bubuko.com,布布扣
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();
    }
}
bubuko.com,布布扣

 

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

jni

标签:android   blog   http   io   color   os   ar   使用   java   

原文地址:http://www.cnblogs.com/wikiki/p/4058048.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!