hello-jni实例讲解

5 篇文章 0 订阅

一、Jni简介

Jni全称是Java Native Interface(Java本地接口),它是java平台的一部分,允许Java代码和其他语言编写的代码进行交互,它使得在Java虚拟机(JVM)内部运行的Java代码可以和其他语言编写的应用程序或库进行交互操作。


二、hello-jni项目简介

截图如下:


这里先对各个文件夹进行分析:

1、jni文件夹

要想在Java项目里或是Android项目里面调用native代码必须在项目下面新建一个jni目录,在这个目录里面编写有关native代码,并且编写编译规则(Android.mk文件),这里重点细说一下这个文件~

这个文件主要是规定编译器如何去生成.so文件、引用的头文件目录、需要编译的.c .cpp .a等文件,hello-jni里面的Android.mk文件很简单并且只有一个,所以先简单分析一下hello-jni提供的Android.mk文件~


LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)


LOCAL_PATH := $(call my-dir)

LOCAL_PATH这个变量用于给定当前文件的路径,my-dir这个宏是由Build System提供的,用于指出当前文件夹所在的路径。


include $(CLEAR_VARS)

这个include的作用就是指向一个编译脚本,指向哪个脚本由括号内的变量决定,CLEAR_VARS指向了一个清理以LOCAL_开头的变量(LOCAL_PATH这个变量排除在外,因为每个模块都会用到当前文件的路径)。在Android.mk中可能会存在很多的模块,每个模块都会有一些变量,而且这些变量又都是全局的,Build System每次只能编译一个模块,所以在每一个模块的最开始都要执行CLEAR_VARS这个脚本来清理其他模块的变量。


LOCAL_MODULE :=hello-jni

这个变量是规定Android.mk文件执行完成之后生成的so文件的名字,在生成so文件的过程中Build System会自动加上lib和.so后缀,比如这个,最后会生成libhello-jni.so这个文件,这个文件可以再代码里面加载,代码如下:

    /* this is used to load the 'hello-jni' library on application
     * startup. The library has already been unpacked into
     * /data/data/com.example.hellojni/lib/libhello-jni.so at
     * installation time by the package manager.
     */
    static {
        System.loadLibrary("hello-jni");
    }



LOCAL_SRC_FILES :=hello-jni.c

这个变量规定要打包的Native的源码,如示例中的hello-jni.c,这里不需要列出头文件,因为Build System会自动加载头文件的,缺省的C++扩展名为cpp,要想改变C++的扩展名,修改LOCAL_CPP_EXTENSION就可以了。


include $(BUILD_SHARED_LIBRARY)

这个BUILD_SHARED_LIBRARY是由Build System提供的一个变量,指向一个编译脚本,用来收集上一次执行CLEAR_VARS这个脚本之后所有的LOCAL信息,并且决定编译生成什么类型的文件。

BUILD_SHARED_LIBRARY 编译为动态库

BUILD_STATIC_LIBRARY 编译为静态库

BUILD_EXECUTABLE 编译为Native程序


这个hello-jni的Android.mk文件就说完了~


Application.mk:这个文件是描述你的应用程序中所需要的模块(静态库还是动态库)

APP_ABI :=all 这个表示编译出所有平台。

我们知道,这个ABI表示ApplicationBinaryInterface(应用程序二进制接口),一个应用程序一般是由高级语言编写完成之后,经过编译生成汇编程序,然后在链接生成二进制文件,这个生成二进制文件的过程中有一个ABI的概念,决定了生成的二进制程序可以运行在哪个CPU架构上(也就是不同的平台)


这个Application.mk文件就说完了~


hello-jni.c文件是Native源码文件

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include <string.h>
#include <jni.h>

/* This is a trivial JNI example where we use a native method
 * to return a new VM String. See the corresponding Java source
 * file located at:
 *
 *   apps/samples/hello-jni/project/src/com/example/hellojni/HelloJni.java
 */
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
#if defined(__arm__)
  #if defined(__ARM_ARCH_7A__)
    #if defined(__ARM_NEON__)
      #if defined(__ARM_PCS_VFP)
        #define ABI "armeabi-v7a/NEON (hard-float)"
      #else
        #define ABI "armeabi-v7a/NEON"
      #endif
    #else
      #if defined(__ARM_PCS_VFP)
        #define ABI "armeabi-v7a (hard-float)"
      #else
        #define ABI "armeabi-v7a"
      #endif
    #endif
  #else
   #define ABI "armeabi"
  #endif
#elif defined(__i386__)
   #define ABI "x86"
#elif defined(__x86_64__)
   #define ABI "x86_64"
#elif defined(__mips64)  /* mips64el-* toolchain defines __mips__ too */
   #define ABI "mips64"
#elif defined(__mips__)
   #define ABI "mips"
#elif defined(__aarch64__)
   #define ABI "arm64-v8a"
#else
   #define ABI "unknown"
#endif

    return (*env)->NewStringUTF(env, "Hello from JNI !  Compiled with ABI " ABI ".");
}

这个源文件的编写和普通的C文件不太一样,因为是和Java打交道的嘛~

这个jstring是jvm里面的字符串,下面是Java和C++的类型在JVM里面的映射:


函数名称之所以要这么写是因为要和调用这个函数的java代码交互,截图如下:


Java是固定的,com_example_hellojni这个是包名,HelloJni这个是类名,stringFromJNI这个就是Java的native方法了~


这个说完了函数名称编写,然后看一下这个函数的参数

第一个JNIEnv类型的参数,通过这个参数我们可以在Native代码里面获取一些Java代码的信息。我们在Java端的函数是没有这个参数的,这个参数是从Java端自动传过来的,作用是提供给JNI一个Java的运行环境,在Java里面就是JVM,在Android里面就是Dalvik VM。

第二个jobject类型的参数的意思是,如果这个Native方法是静态的话,jobject表示的就是这个包含这个Native方法的类的实例,如果这个Native方法不是静态的话,jobject表示的就是这个类的对象的实例。


hello-jni.c就到这里了。


有什么疑问可以加我QQ:763949771,一起交流学习。如有错误请留言指正~



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. linux下jni环境搭建 参考:http://blog.csdn.net/zhouyuanjing/article/details/7553706 2. 编写HelloJni工程,在主Activity(本例:HelloJni.java)里声明native函数: 如下: public native String stringFromJNI(); public native double add(double a, double b); public native double sub(double a, double b); public native double multi(double a, double b); public native double div(double a, double b); static { System.loadLibrary("hello-jni"); } 3. 在根目录下创建 jni 目录(mkdir jni). 4. 利用命令生成相应的头文件,在根目录下执行:javah -classpath bin/classes -d jni com.xxx.hello.HelloJni ————————————— ——————— ^ ^ 包名 类名 5. 编写相应的.c文件(hello-jni.c) #include<string.h> #include<jni.h> JNIEXPORT jstring JNICALL Java_com_xxx_hello_HelloJni_stringFromJNI(JNIEnv *env, jobject obj) { return(*env)->NewStringUTF(env, "Hello World from JNI !"); } JNIEXPORT jdouble JNICALL Java_com_xxx_hello_HelloJni_add(JNIEnv *env, jobject obj, jdouble a, jdouble b) { return a + b; } JNIEXPORT jdouble JNICALL Java_com_xxx_hello_HelloJni_sub(JNIEnv *env, jobject obj, jdouble a, jdouble b) { return a - b; } JNIEXPORT jdouble JNICALL Java_com_xxx_hello_HelloJni_multi(JNIEnv *env, jobject obj, jdouble a, jdouble b) { return a * b; } JNIEXPORT jdouble JNICALL Java_com_xxx_hello_HelloJni_div(JNIEnv *env, jobject obj, jdouble a, jdouble b) { return a / b; } 6. jni目录下编写Android.mk文件 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c include $(BUILD_SHARED_LIBRARY) 在根目录下运行:ndk-build xxx@xion-driver:~/android_env/eclipse/Workspace/HelloJni$ndk-build Install : libhello-jni.so => libs/armeabi/libhello-jni.so 可以看到已经正确的生成了libhello-jni.so共享库了。 7. Eclipse运行该工程即可。 ~~完~~

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值