• android ndk开发



    理论部分:

    android ndk就是Java里面jni技术,当然会略有点区别,但总体一致。android 项目要使用ndk开发主要有两大原因:

    1,能够使用已有的类库(很多开源库c++/c为基础)在基础上进行开发,有些功能java无法实现(解码库)或者效率问题(这个比较少)

    2,考虑源代码保护,c++/c编译成类库比Java更难破解


    学习ndk开发应用程序首先掌握jni语法,可以参考jni手册或者oracle网站进行了解

    首先看一下数据类型:

    Java类型    本地类型         描述

    boolean    jboolean       C/C++8位整型

    byte       jbyte          C/C++带符号的8位整型

    char       jchar          C/C++无符号的16位整型

    short      jshort         C/C++带符号的16位整型

    int        jint           C/C++带符号的32位整型

    long       jlong          C/C++带符号的64位整型e

    float      jfloat         C/C++32位浮点型

    double     jdouble        C/C++64位浮点型

    Object     jobject        任何Java对象,或者没有对应java类型的对象

    Class      jclass         Class对象

    String     jstring        字符串对象

    Object[]   jobjectArray   任何对象的数组

    boolean[]  jbooleanArray  布尔型数组

    byte[]     jbyteArray     比特型数组

    char[]     jcharArray     字符型数组

    short[]    jshortArray    短整型数组

    int[]      jintArray      整型数组

    long[]     jlongArray     长整型数组

    float[]    jfloatArray    浮点型数组

    double[]   jdoubleArray   双浮点型数组

    和Java类型一一对应,了解更多详细内容,自行查询jni手册

    jni函数:看一个简单的函数

    // 返回字符串"hello load jni"
    JNIEXPORT jstring JNICALL native_hello(JNIEnv* env,jobject thiz, jclass clazz)
    {
        return (*env)->NewStringUTF(env, "hello load jni.");
    }
    说一下参数含义:

    其中 JENEnv* 代表的是java环境 通过这个环境可以调用java的方法,jobject 表示哪个对象调用了 这个c语言的方法, thiz就表示的是当前的对象

    JNI方法注册到jvm有两种:

    1,静态注册(方法名称为Java_packegeName_包含native方法声明class_native method name)

    2,动态注册(通过JNI_OnLoad()实现,jvm启动时调用该方法,在该方法内注册方法签名即可)后面介绍

    两种方法的区别如下:

    静态:先由Java得到本地方法的声明,然后再通过JNI实现该声明方法。

    动态:先通过JNI重载JNI_OnLoad()实现本地方法,然后直接在Java中调用本地方法。


    ndk编译:

    1,需要下载ndk开发包,解压配置环境变量,和sdk配置差不多

    下载地址:http://developer.android.com/tools/sdk/ndk/index.html

    2,下载cygwin软件在windows下模拟Linux环境编译器

    下载地址:http://www.cygwin.com/

    相关文章:http://blog.csdn.net/buildon/article/details/711536

    http://www.cnblogs.com/playing/archive/2011/07/14/2106727.html

    编译.so类库

    相关文章:http://blog.csdn.net/android_panda/article/details/7607946

    http://blog.csdn.net/wangkuifeng0118/article/details/7311724




    @Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    	//	setContentView(R.layout.activity_main);
    		 TextView  tv = new TextView(this);
    	        tv.setText( stringFromJNI() );
    	        setContentView(tv);
    	}
    
    	 /* A native method that is implemented by the
         * 'hello-jni' native library, which is packaged
         * with this application.
         */
        public native String  stringFromJNI();
    
        
        static {	//导入的lib名去掉前面的lib
            System.loadLibrary("hello-jni");
        }

    2.build下项目,打开cmd,cd到该工程bin目录下,
    D:\>cd D:\android\rayn\TestJni\bin

    D:\android\rayn\TestJni\bin>javah -jni com.stay.jni.CallNative

    然后在bin目录下会出现一个.h文件这是声明的头文件

    3.我们要的是里面声明的方法,把我们要写的c文件改成相同的方法名就可以了。

    4.在工程里建个jni目录,将改好的c文件和mk文件(随便copy一个,改下路径和lib名就好啦)copy进去


    常见错误:

    错误1:当输入cd &NDK时出现no such file or Director时

    原因1:在配置目录下cygwin\home\Andy\下的.bash_profile时配置的ndk所在路径有错误(

    正确格式NDK=/cygdrive/d/adt-bundle-windows-x86/android-ndk-r8e

    export NDK)

    原因2:没有在系统环境变量中配置ndk(与sdk路径配置一样)


    错误2:native method not found

    原因:.c或.cpp内的函数名与Javah 编译生成包名不一致所导致


    关于ndk详细介绍,可参考这篇文章

    http://blog.chinaunix.net/uid-10008293-id-2972294.html

    http://blog.csdn.net/zhangjie201412/article/category/1086150


    第一步:打开命令行切换目录到xx.java目录下 javac命令编译:


    第二部编译头文件:当执行javah -jni xxx文件是会出现找不到文件情况

    解决办法:将目录切换到项目中src下(例如项目目录E:\workspace4.2\HelloJavaJni\src\com\sample\jni)


    即可在src目录下生成xx.h头文件

    问题原因:环境变量的设置不正确,正确设置如下:
    path为"%JAVA_HOME%\bin"
    ClassPath设置为".;%JAVA_HOME%\lib"
    JAVA_HOME为"E:\Java\jdk1.6.0_13" (JDK的安装路径)
    另外:需要先编译,后生成头文件:


    下面介绍一下JNA技术:

    JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架。使用JNI调用共享类库(.dll/.so文件)是非常麻烦的事情,既需要编写java代码,又要编写C语言的代理方法,这其中需要很多数据类型的转换,是让人非常头痛。JNA框架就是为了解决这些问题和繁琐的事情而开发的,
    它提供一组Java工具类用于在运行期动态访问系统本地共享类库而不需要编写任何Native/JNI代码。开发人员只要在一个java接口中描述目标native library的函数与结构,
    JNA将自动实现Java接口到native function的映射,大大降低了Java调用本体共享库的开发难度。JNA与.NET平台上的P/Invoke机制一样简单和方便。

    使用JNA的强大功能方便地调用动态链接库中的C函数,需要下载一个jar包,https://github.com/twall/jna
    假设有一个动态链接库: Jna.dll。里面有这样一个函数

    void sayHello(char * name){
        printf("C Code Start...\n");
        printf("Hello! Mr %s.\n",name);
        printf("C Code End.\n");
    }
    为了调用这个函数,使用JNA,我们需要编写下面的JAVA代码:
    public interface ICnblogsJna extends Library {
        // 接口实例
        ICnblogsJna INSTANCE = (ICnblogsJna) Native.loadLibrary("CnblogsJna",ICnblogsJna.class);

        // 与C代码映射的函数
        public void sayHello(String name);
    }

    接口内部需要一个公共静态常量INSTANCE, 通过这个常量,就可以获得这个接口的实例,从而使用接口的方法。也就是调用动态链接库CnblogsJna.dll中的sayHello函数了。
     如果使用JNI,你需要使用System.loadLibrary方法,来加载我们专为JNI编写的动态链接库,这个动态链接库实际上是我们真正需要的动态链接库的代理。使用JNA是,
    需要用JNA类库的Native类的loadLibrary函数,是直接把我们需要的动态链接库载入进来。使用JNA,我们不需要编写作为代理的动态链接库,不需要编写一行原生代码。
    Native类的loadLibrary方法有两个参数:第一个参数是.dll或者.so文件的名字,但不带后缀名。这符合JNI的规范,因为带了后缀名就不可以跨操作系统平台了。
    第二个参数是本接口的Class类型,JNA通过这个Class类型,根据指定的dll/.so文件,动态创建接口的实例
                
     // 调用动态链库中的sayHello函数
      ICnblogsJna.INSTANCE.sayHello("jna sayhello test!");
     由于跨平台和跨语言尤其自身无法克服的确定,所以尽量少跨平台、跨语言传递数据。如果必须这样做,也尽量使用简单的数据类型。如果有复杂的数据类型需要在Java和原生函数中传递,
    那么我们就必须在Java中模拟这种复杂的原生类型。这将大大增加实现的难度,甚至无法实现。如果在Java和原生函数间存在大量的数据传递,一方面,会损失程序的性能

    ;另一方面会造成内存碎片,Java调用原生函数时,会把数据固定在内存中,这样原生函数才可以访问这些Java数据。这些数据,JVM的GC不能管理,就会造成内存碎片。




  • 相关阅读:
    解析#pragma指令
    查看内核版本和发行版本

    unix 环境高级编成 apue.h ,apueerror.h的代码
    类string的构造函数、拷贝构造函数和析构函数 (转)
    归并排序
    C++ 中调用其他应用程序的方法
    [MySQL] MySQL的Grant命令
    static的作用
    白话经典算法系列之七 堆与堆排序 (转)
  • 原文地址:https://www.cnblogs.com/happyxiaoyu02/p/6818956.html
Copyright © 2020-2023  润新知