美文网首页
helloWorld JNI

helloWorld JNI

作者: jeffrey要努力 | 来源:发表于2018-07-13 11:23 被阅读17次

    hello world JNI

    创建

    我使用的是android studio 3.1.3.直接新建一个项目.在Create Android Project界面下面勾选Include C++ support.然后一路next就可以了

    对比

    与普通的安卓项目相比

    1. main文件夹下多了个cpp文件夹,cpp文件夹下有个native-lib.cpp文件
    2. app/build.gradle中多了externalNativeBuild配置
    android{
      defaultConfig{
        ....
        externalNativeBuild {
                cmake {
                    cppFlags ""
                }
            }
      }
    
      externalNativeBuild {
                cmake {
                    CMakeLists.txt
                }
      }
    }
    
    1. app文件夹下多了个CMakeLists.txt
    
    //第一个参数是将要打包的库的名字
    //第二个参数是共享链接库
    //第三个参数是打包的文件
    add_library( # Sets the name of the library.
                 native-lib
    
                 # Sets the library as a shared library.
                 SHARED
    
                 # Provides a relative path to your source file(s).
                 src/main/cpp/native-lib.cpp
                  )
    
    
    //找到内置的库
    find_library( # Sets the name of the path variable.
                  log-lib
    
                  # Specifies the name of the NDK library that
                  # you want CMake to locate.
                  log )
    
    
    //把内置的库链接进native-lib 然而并不知道有啥用
    target_link_libraries( # Specifies the target library.
                           native-lib
    
                           # Links the target library to the log library
                           # included in the NDK.
                           ${log-lib} )
    
    1. 在activity里,声明下就可以使用了
       static {
            System.loadLibrary("native-lib");
       }
       public native String stringFromJNI();
    
       @Override
       protected void onCreate(Bundle savedInstanceState) {
           ....
           TextView tv = (TextView) findViewById(R.id.sample_text);
           tv.setText(stringFromJNI());
       }
    

    对于native-lib.cpp文件来说

    //引入jni.h头文件
    #include <jni.h>
    //引入string头文件
    #include <string>
    
    // extern "C" 标识后面的用C编译 ,这里的意思是这个函数用C编译,C++为了函数重载会把参数带上,而c没有函数重载
    // JNICALL表示调用约定,相当于C++的stdcall,说明调用的是本地方法
    // JNIEXPORT表示函数的链接方式,当程序执行的时候从本地库文件中找函数
    // 中间的jstring就是返回类型,是c++中对应java中String的类型
    // JNIEnv 是对java环境的引用,并且提供了一些类型转换方法
    // jobject 是调用这个函数的java对象.没发现如何使用
    extern "C" JNIEXPORT jstring JNICALL Java_com_happy_fei_helloworldjni_MainActivity_stringFromJNI(
            JNIEnv *env,
            jobject /* this */) {
        std::string hello = "Hello from C++";
        return env->NewStringUTF(hello.c_str());
    }
    
    

    extern "C" 告诉编译器后面的按照C的风格编译.我测试下如果函数前不加extern "C"会报错

    java.lang.UnsatisfiedLinkError: No implementation found for java.lang.String com.happy.fei.helloworldjni.MainActivity.helloWorld(java.lang.String, java.lang.String) (tried Java_com_happy_fei_helloworldjni_MainActivity_helloWorld and Java_com_happy_fei_helloworldjni_MainActivity_helloWorld__Ljava_lang_String_2Ljava_lang_String_2)
    

    错误的信息是没有找到helloWorld函数也没有找到helloWorld(String,String)函数.
    问题:什么时候可以不使用extern "C". 我这个文件是CPP啊,不过留待以后熟练了发现吧.现在还不太溜

    稍微难一点

    上面这个stringFromJNI函数是返回一个字符串.现在进阶一下,输入两个字符串连起来之后再返回

    //jstring 对应的java中的String
    extern "C" JNIEXPORT jstring JNICALL Java_com_happy_fei_helloworldjni_MainActivity_helloWorld(
            JNIEnv *env,
            jobject /* this */ ,jstring s1 ,jstring s2) {
              //将jstring转为std::string
              std::string cs1 = env->GetStringUTFChars(s1, NULL);
              std::string cs2 = env->GetStringUTFChars(s2, NULL);
              std::string result = cs1 + cs2 ;
              //再将std::string转为jstring 返回给java
              return env->NewStringUTF(result.c_str());
    }
    

    GetStringUTFChars返回const char* 对于C++来说就是std::string
    在MainActivity里使用

    public native String helloWorld(String s1,String s2);
    .....
    protected void onCreate(Bundle savedInstanceState){
       ....
       //str为helloworld
       String str = helloWorld("hello","world"));
    }
    .....
    
    添加新的类

    上面都是在编辑器给我们生成的文件里操作.真写起来肯定需要新建多个类文件的.尝试新增一个C++类

    1. 右键cpp文件目录 new - class - c++ class .输入名字hello.点击ok.会在目录下生成hello.cpp和hello.h
    2. 编辑hello.h
    
    //如果没有定义过  HELLOWORLDJNI_HELLO_H就定义下
    //HELLOWORLDJNI_HELLO_H 是指hello.h这个头文件
    //再往下就不会了
    #ifndef HELLOWORLDJNI_HELLO_H
    #define HELLOWORLDJNI_HELLO_H
    
    #include <string>
    
    //定义一个hello类,声明一个public方法 say
    class hello {
        public:
         std::string say(std::string name);
    };
    
    
    #endif //HELLOWORLDJNI_HELLO_H
    
    
    1. 根据.h来实现cpp
    //引入hello.h
    #include "hello.h"
    
    //头文件中类的方法没有实现,只是定义了下.需要在cpp文件里实现
    std::string hello::say(std::string name) {
        return "hello " + name;
    }
    
    1. .cpp和.h文件编辑完了就可以使用了

    在native-lib.cpp中

    //引入头文件,""的意思是在项目目录下找 <>是到系统库里去找
    #include "hello.h"
    
    //对应的java方法是helloClass(String name)
    extern "C" JNIEXPORT jstring JNICALL Java_com_happy_fei_helloworldjni_MainActivity_helloClass(
            JNIEnv *env,
            jobject /* this */ ,jstring name) {
        //c++中的类就是这么奔放,声明了就可以用
        //查了下new.new是创建个对象并返回指向该对象的指针,这里的话就不需要new了      
        hello helloObj;
        //将jstring转为std::string
        std::string strName = env->GetStringUTFChars(name, NULL);
        //调用类的方法
        std::string result = helloObj.say(strName);
        //再将std::string转为jstring并返回回去
        return env->NewStringUTF(result.c_str());
    }
    
    
    1. 在MainActivity中使用
    //声明原生方法
    public native String helloClass(String name);
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      .....
      //result 为 hello fei
      String result= helloClass("fei");
      .....
    }      
    
    
    1. 运行...然后报错..... 没有找到hello::say方法
    error: undefined reference to 'hello::say(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >)'
    
    1. 想起之前有个打包相关的,就是CMakelist.txt.将hello.cpp加入编译就可以了
    //加了个hello.cpp
    add_library( # Sets the name of the library.
                 native-lib
                 SHARED
                 # Provides a relative path to your source file(s).
                 src/main/cpp/native-lib.cpp
                 src/main/cpp/hello.cpp
                  )
    
    1. 在运行就可以了

    感想

    c/c++真是博大精深.好歹之前干过半年,然而复习了几天还是一脸蒙蔽,这个demo肯定有很多错误.希望自己能继续看下去.发现并修改这些错误

    相关资料

    jni常用函数大全\

    相关文章

      网友评论

          本文标题:helloWorld JNI

          本文链接:https://www.haomeiwen.com/subject/avdjpftx.html