• eclipse中新建jni工程


    1.什么是NDK

    网上很多不多说,全称是Android Native Developer Kit,是一个工具合集,我理解可以把c/c++打包成.so文件

    这是目录结构,要用到指令ndk-build

    需要配置环境变量

    配置成功在cmd中输入ndk-build会出现如下信息

    2.什么JNI

    JNI全称是 Java Native Interface,字面意思是java的本地接口,我们知道java是夸平台的,所以java写的程序应该是与平台无关的,

    所以在java中如果要调用本地库就需要专门的接口,我可以理解为一套调用机制或者说协议。

    进行JNI编程的步骤:  

      1.java 层:用关键字native声明c/c++方法。导入lib库:

    public class Native {
        static{
            System.loadLibrary("HelloJava");
        }
        public static native String getString();
    }

    注意这里"HelloJava"是你新建的c/c++文件名,不要多余写东西。现在我们定义了一个类是Native.java,然后我们要把这个类变成头文件。不过谷歌出的android studio 2.2版本以后可以直接新建一个支撑c/c++工程了。这里不先不提。

    首先需要将Native.java编译生成一个.class文件。这里要用的javac。不过你也可以直接运行一下。eclipse会主动帮你编译生成.class,打开cmd

    生成的Native.class

     

    这里注意javac的使用我直接cd到了这个类的目录。

    生成.class文件之后,再用jdk另外一个工具生成.h文件javah

    同样在cmd中:输入javah -help查看使用帮助

    [options]是可选项目,<classes>是必须项目。这个就是我们之前生成的Native.class

    现在我们要确定需要加载类的路径,还有输出目录。注意每一段之间的空格,容易出错

    类的后缀不需要写。执行这个指令完成之后会在当前目录下生成对应的.h文件

    在eclipse右键工程名,refresh(f5)以下就会显示出来

    至此我们java层的工作完成,接下来就是在Jni中实现所声明的方法。

    2.Jni层: 

    在工程中新建一个jni目录并且将刚才的.h文件移过来

    新建一个HelloJava.c的.c源文件在这里我们来实现java层中声明的native方法

    #include <stdio.h>
    #include <stdlib.h>
    #include <jni.h>
    JNIEXPORT jstring JNICALL Java_com_example_helloc_Native_getString
      (JNIEnv *env, jclass j){
        return (**env).NewStringUTF(env,"hello java!");
    }

    这个函数名字太复杂太扯淡了。其实jni有一个命名规则,我们现在不关心这个,这个函数名可以直接从之前生成的.h文件复制过来
    下面就是.h文件的内容

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_example_helloc_Native */
    
    #ifndef _Included_com_example_helloc_Native
    #define _Included_com_example_helloc_Native
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_example_helloc_Native
     * Method:    getString
     * Signature: ()Ljava/lang/String;
     */
    JNIEXPORT jstring JNICALL Java_com_example_helloc_Native_getString
      (JNIEnv *, jclass);
    
    #ifdef __cplusplus
    }
    #endif
    #endif

    这里只有函数声明,复制这个声明,我们只要在jni实现函数体就可以了。具体的编程方式这里先不提,这里只是返回了一个字符串

    ndk中已经集成了部分c库。完成之后,我们需要将.c变成linux系统能使用的.so库。这个工作就由ndk来完成,具体如下:

    ndk-build指令需要在工程目录下执行才有效果,但是并没有规定在什么子目录下,所有效果都是一样的。该指令会将.c或者c++文件生成对应的.so文件,而且是两份,一份在project pathobjlocalarmeabi,这份比较大,包含有调试信息,不会随着app一起发布。另外一份比较小 project path libsarmeabi,这个会随着apk一起发布。编译结果

    生成了各个平台支持的.so文件完成之后工程目录的libs还没有出现.so文件,

    需要右键工程refresh(F5)一下就会出现,这里系统会自动添加"lib"前缀。但是注意在java层导入库的时候不要写"libHelloJava"这个要写:

    static{

        System.loadLibrary("HelloJava");

    }

    完成之后执行结果。这是android代码

    public class MainActivity extends Activity {
        public Button btnShow;
        public TextView tvShow;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            btnShow = (Button)findViewById(R.id.btn_show);
            tvShow = (TextView)findViewById(R.id.tv_show);
            btnShow.setOnClickListener(new OnClickListener() {
                
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    tvShow.setText(Native.getString());
                }
            });
        }
    }

    结果

    另外执行ndk-build之前需要先编写.mk文件。具体如下:

    在jni中新建一个android.mk文件,内容如下:

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    
    LOCAL_MODULE    := HelloJava
    LOCAL_SRC_FILES := HelloJava.c
    #LOCAL_LDLIBS    := -llog -ljnigraphics
    
    include $(BUILD_SHARED_LIBRARY)

    具体解释如下(借用一为大神的):

    LOCAL_PATH := $(call my-dir)

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

     

    include $( CLEAR_VARS)

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

     

    LOCAL_MODULE    := Native

    编译的目标对象,LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。

    LOCAL_SRC_FILES := Native.c

    LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。

    注意,默认的C++源码文件的扩展名是’.cpp’. 指定一个不同的扩展名也是可能的,只要定义LOCAL_DEFAULT_CPP_EXTENSION变量,不要忘记开始的小圆点(也就是’.cxx’,而不是’cxx’)

    include $(BUILD_SHARED_LIBRARY)

    BUILD_SHARED_LIBRARY表示编译生成共享库,是编译系统提供的变量,指向一个GNU Makefile脚本,负责收集自从上次调用'include $(CLEAR_VARS)'以来,定义在LOCAL_XXX变量中的所有信息,并且决定编译什么,如何正确地去做。还有 BUILD_STATIC_LIBRARY变量表示生成静态库:lib$(LOCAL_MODULE).a, BUILD_EXECUTABLE 表示生成可执行文件。

    这个只不过是自己的流水账,偶尔有一些心得,错误的地方概不负责
  • 相关阅读:
    C++ Toolkit zz
    开发人员实际在用哪些工具 zz
    Page.RegisterClientScriptBlock和Page.RegisterStartupScript有何区别?
    动态网址与静态网址
    DIV垂直居中 (转)
    JS网页打印设置技巧(
    谈*静态页*(或网页*静态化*)的时候,请区分一些概念(转)
    添加新增 删除旧的 避免id自增过多
    浅谈CSRF攻击方式(转)
    简单的角色权限管理
  • 原文地址:https://www.cnblogs.com/ashitaka/p/5953708.html
Copyright © 2020-2023  润新知