• android jni——helloworld


    看了网上好多牛人写的学习系列都是用HelloWorld作为开始,我们这里也用HelloWorld来开始我们的学习,首先我们来介绍下JNI吧。

    JNI作为java代码和C/C++的桥梁而存在的,为了让java代码更加接近原生代码,大家都知道在linux中,C语言可以直接访问硬件,但是java代码想要直接操作硬件或者说是直接读写寄存器的话不行,所以需要jni来作为桥梁来访问更底层的东西。

    JIN使得JAVA代码更加优越,但是用起来也不是那么容易的,特别是在规范方面,作为java虚拟机实现的一部分,jni是java应用程序调用原生代码的途径。下面这种图显示了JNI的角色扮演:


    OK,知道了JNI的作用我们就开始我们的例子吧,我这里编译jni是在ubunt下编译的,eclipse是在windows下面的开发环境,在ubuntu下配置ndk开发环境请看我前面一篇文章,这里跳过环境配置,这里我们要实现的功能是:

    功能:点击一个按钮,吐出来一个toast,toast中的字符串是在jni中传进来的。

    这样就演示了如何在java中去调用jni,我这边的jni是使用c语言编写的,也可以使用C++,稍有一点区别,用C++编写我比较喜欢在android BSP源码中编译。

    下面首先是android.mk文件,其实就是linux中的makefile文件而已,这里就是说明了一些编译方法以及生成模块的名字。

     

    [cpp]  view plain copy
     
    1. LOCAL_PATH := $(call my-dir)  
    2.   
    3. include $(CLEAR_VARS)  
    4.   
    5. LOCAL_C_INCLUDE := $(LOCAL_PATH)/include  
    6. LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog  
    7.   
    8. LOCAL_MODULE := HelloWorld  
    9. LOCAL_SRC_FILES :=   
    10.     HelloWorld.c  
    11.   
    12. include $(BUILD_SHARED_LIBRARY)  


    Android.mk的编写也是有规范的。

     

     

    一个Android.mk file用来向编译系统描述你的源代码。具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次。你可以在每一个Android.mk file中定义一个或多个模块,你也可以在几个模块中使用同一个源代码文件。编译系统为你处理许多细节问题。

    一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。

    makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。

    Make工具最主要也是最基本的功能就是通过makefile文件来描述源程序之间的相互关系并自动维护编译工作。而makefile 文件需要按照某种语法进行编写,文件中需要说明如何编译各个源文件并连接生成可执行文件,并要求定义源文件之间的依赖关系。makefile 文件是许多编译器--包括 Windows NT 下的编译器--维护编译信息的常用方法,只是在集成开发环境中,用户通过友好的界面修改 makefile 文件而已。

    1、LOCAL_PATH := $(call my-dir) 

    一个Android.mk file首先必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件。在这个例子中,宏函数’my-dir’, 由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录)。

    2、include $( CLEAR_VARS)

    CLEAR_VARS 由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES,LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。

    3、LOCAL_MODULE :=  HcSyncml

    LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包 含任何空格。注意编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'HcSyncml'的共享库模块,将会生成'libHcSyncml.so'文件。

    4、LOCAL_C_INCLUDES :=$(LOCAL_PATH)/extra_inc$(LOCAL_PATH)/main_inc

    LOCAL_C_INCLUDES 中加入所需要包含的头文件路径

    5、LOCAL_SRC_FILES

    LOCAL_SRC_FILES中加入源文件路径(需要编译的文件),多个文件用 ‘’ 隔开

    6、LOCAL_LDLIBS+= -L$(SYSROOT)/usr/lib –llog

    表示允许打印Log

    ----------------------------------------------------------------------------------

    下面是我们HelloWorld的jni代码:

     

    [cpp]  view plain copy
     
    1. //  
    2. //Jay-----HelloWorld  
    3. //HelloWorld.c  
    4. #include <string.h>  
    5. #include <jni.h>  
    6.   
    7. Jstring  
    8. Java_com_android_jni_HelloWorld_getString(JNIEnv *env,jobject jobj)  
    9. {  
    10.     return (*env)->NewStringUTF(env,"HelloWorld! From C!");  
    11. }  

    很简单吧,2个头文件,大家一看就知道第二个头文件,jni.h里面肯定定义了jni使用的一些库函数,还有jni的一些模板。

    JNI的函数名字也是要注意的一个地方,我们这边是:Java_com_android_jni_HelloWorld_getString

    Java+package name+class name+function name组成的

    -----------------------------------------------------------------------------------

    下面是java代码:

     

    [cpp]  view plain copy
     
    1. // package name  
    2. package com.android.jni;  
    3. //use inport  
    4. import android.app.Activity;  
    5. import android.content.Context;  
    6. import android.os.Bundle;  
    7. import android.view.View;  
    8. import android.view.View.OnClickListener;  
    9. import android.widget.Button;  
    10. import android.widget.Toast;  
    11.   
    12. public class HelloWorld extends Activity {  
    13.     /** Called when the activity is first created. */  
    14.     Context mContext = null;  
    15.     Button bt = null;  
    16.     @Override  
    17.     public void onCreate(Bundle savedInstanceState) {  
    18.         super.onCreate(savedInstanceState);  
    19.         setContentView(R.layout.main);  
    20.         setContentView(R.layout.main);  
    21.         mContext = this;  
    22.         bt = (Button)findViewById(R.id.button);  
    23.         bt.setOnClickListener(new MyButtonListener());  
    24.     }  
    25.     class MyButtonListener implements OnClickListener{  
    26.   
    27.         public void onClick(View v) {  
    28.             if(v.getId() == R.id.button ){  
    29.                 //调用原生函数得到字符串sre  
    30.                 String str=getString();  
    31.                 //吐出message  
    32.                 Toast.makeText(mContext, str, Toast.LENGTH_SHORT).show();  
    33.             }  
    34.         }  
    35.     }  
    36.     //声明jni原生函数  
    37.     public native String getString();  
    38.     //载入原生库  
    39.     static {  
    40.         System.loadLibrary("helloworld");  
    41.     }  
    42. }  


     

    注释在java代码中都有,这边都比较简单,下面我们来运行模拟器。



    点击button,会出现HelloWorld! from C!

    大功告成!

  • 相关阅读:
    笨方法学python(本文为阅读时从此书摘录的笔记) 第一天
    关于C++中的虚拟继承的一些总结
    用提高效率的暴力法求3000以内的素数
    DAY 155 python中parse模块
    DAY 154 python自带的hmac模块
    DAY 153 Python中使用pymongo操作mongodb
    DAY 152 hmac模块
    DAY 151 parse模块
    DAY 150 setter&getter&@property
    DAY 149 property和setter装饰器
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3170320.html
Copyright © 2020-2023  润新知