JNI简介

2017-01-16  本文已影响216人  dafaycoding

JNI和NDK?

为什么用JNI?

JNI编译特点


1、eclipse下jni开发流程简介

第一个JNI的HelloWorld程序。

    1. 在MainActivity中声明一个native方法:

            public native String sayHello();

    2. 在工程的根目录下创建一个jni的文件夹, 并在里边创建一个Hello.c的文件.

    3. 在Hello.c文件中实现MainActivity中声明的native方法.

            
            jstring Java_com_example_jnihelloworld_MainActivity_sayHello(JNIEnv* env, jobject obj) {
                // jstring     (*NewStringUTF)(JNIEnv*, const char*);
                char* text = "Hello from c!!!!";
                return (**env).NewStringUTF(env, text);
            }

    4. 在jni的目录下创建一个Android.mk文件.

            LOCAL_PATH := $(call my-dir)
            
            include $(CLEAR_VARS)
            
            LOCAL_MODULE    := example
            LOCAL_SRC_FILES := Hello.c
            
            include $(BUILD_SHARED_LIBRARY)

    5. 在工程的根目录下执行ndk-build命令, 编译.so文件.

    6. 在调用native方法前, 加载.so的库文件.

            System.loadLibrary("example");

    7. 在java代码中调用native方法, 工程会自动去找.so文件中对应实现的代码.

    1. 在java代码中声明native方法.

    2. 在window -> preferences -> Android -> NDK 把ndk的根目录配置进去.
       右键工程 Android Tools -> Add Native Support 写进去一个函数库的名字.

    3. 使用javah命令生成.h的头文件, 把头文件拷贝到工程的jni目录下.

    4. 实现c代码: 把生成的.h头文件引入进来(使用双引号方式引入).

    5. 处理错误和代码提示: 右键工程 -> Properties -> C/C++ General -> Paths and Symbols -> Includes -> Add 把android-ndk-r9\platforms\android-9\arch-arm\usr\include配置进去.

    6. 把c代码对应native方法实现了.

    7. 在java代码中加载.so库文件, 调用native方法.
javap -s com.example.callbackjava.JNI

jni开发常见错误:

1. 在jni目录下没有发现Android.mk文件

        Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: ./jni/Android.mk

2. c文件中没有导入jni.h的头文件.

        jni/CommonError.c:4:1: error: unknown type name 'JNIEXPORT'
        jni/CommonError.c:4:19: error: expected '=', ',', ';', 'asm' or '__attribute__'
        before 'JNICALL'
        jni/CommonError.c:4:19: error: unknown type name 'JNICALL'

3. c代码实现的方法没有写形参的名字.

        jni/CommonError.c: In function 'Java_com_example_commonerrordemo_MainActivity_
        sayHelloInC':
        jni/CommonError.c:6:3: error: parameter name omitted
        jni/CommonError.c:6:3: error: parameter name omitted
        jni/CommonError.c:8:13: error: 'env' undeclared (first use in this function)
        jni/CommonError.c:8:13: note: each undeclared identifier is reported only once f
        or each function it appears in

4. 调用native方法, 没有加载.so文件.

        No implementation found for native Lcom/example/commonerrordemo/MainActivity;.sayHelloInC ()Ljava/lang/String;

5. 加载.so文件时, 名字写错.

        java.lang.UnsatisfiedLinkError: Couldn't load libcommonerror.so: findLibrary returned null

6. 当前生成的arm平台下的.so文件, 运行在了x86的平台模拟器下.

        java.lang.UnsatisfiedLinkError: Couldn't load libcommonerror.so: findLibrary returned null

    - 解决方案: 在jni的目录下, 创建一个Application.mk, 内容如下:

            # 生成所有的机器码.
            APP_ABI := all

            # 生成单个平台的机器码
            APP_ABI := x86 armeabi 

2、Elcipse下jni程序迁移到AndroidStudio

1.  设置NDK路径 
    选择File>Project Structure>SDK Location(快捷键:Cmd+;),指定NDK的路径。
2.  把jni文件下内容拷贝到AndroidStudio项目下面
3.  AndroidStudio项目的gradle下添加下面配置
    externalNativeBuild{
        ndkBuild{
            path file("src/main/jni/Android.mk");
        }
    }

如图所示

图2-1

3、AndroidStudio下jni开发流程简介

  1. 添加本地方法
public static native String hello_jni();
  1. 加载so文件
static {
        System.loadLibrary("hello_jni"); // 注意没有前缀lib和后缀.so
    }
  1. 利用javah命令生成JAVA所对应的JNI头文件,1、打开终端,2、将目录定位到java目录下,3、通过javah产生头文件。
图1-1
  1. 将com_example_idea_jnitest_1_HomeActivity.h拷贝一个将扩展名改为.c,在.c中完成业务逻辑处理相关代码:
JNIEXPORT jstring JNICALL Java_com_example_idea_jnitest_11_HomeActivity_helloJni
(JNIEnv * env, jobject obj) {
    return (*env)->NewStringUTF(env,"调用c代码  返回 hello!");
}
  1. 修改Module中Build.gradle文件,在defaultConfig段落中加入ndk编译配置。
        ndk {
            moduleName "hello_jni"
        }
图1-2
  1. 此时编译会出错
Error: NDK integration is deprecated in the current plugin. Consider 
trying the new experimental plugin. For details, see 
http://tools.android.com/tech-docs/new-build-system/gradle-
experimental. Set "android.useDeprecatedNdk=true" in 
gradle.properties to continue using the current NDK integration.
解决:
提示已经告诉我们需要在gradle.properties设置android.useDeprecatedNdk=true,设置好后点击同步按钮。
图1-3

参考:
Android Studio JNI开发入门教程
Android JNI编程—NDK编译
使用Android Studio进行JNI开发 - Mac篇

上一篇下一篇

猜你喜欢

热点阅读