美文网首页
Java如何调用本地.so库里的方法

Java如何调用本地.so库里的方法

作者: 加油码农 | 来源:发表于2018-05-19 17:10 被阅读89次

    首先在此之前希望你已经掌握了基本JNI常识的运用,比如Java代码如何调用本地native的方法,native方法如何访问本地变量,本地方法等以及其他相关的基础知识。在此我还是贴上Activity的部分代码,如下:

    // Used to load the 'native-lib' library on application startup.
      static {
        System.loadLibrary("native-lib");
      }
      public String name = "test";
      private int source[] = { 1, 4, 0, 7, 33, 11 };
    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
        }
      /**
       * A native method that is implemented by the 'native-lib' native library,
       * which is packaged with this application.
       */
      public native String stringFromJNI();
    
      public native String updateNameFromC();//属性访问
    
      public native String getMethod();//方法访问
    
      public native void getArray(int arrays[]);
    
      //引用解决什么问题呢,什么时候通知JVM回收JNI的对象
      public native void getLocalReference();
    
      //缓存策略,对象生命周期的问题
      public native void cachede();
    
      //测试
      public native String test(String str);
    

    同理,本地cpp的代码如下:

    #include <jni.h>
    #include <string>
    #include <string.h>
    #include "stdlib.h"
    #include <android/log.h>
    //首先将a强制声明为指向整数的指针,然后读取指针对应的整数
    int compare(const void *a,const void *b){
        return (*(int *)a-*(int *)b);
    }
    
    #define TAG "myDemo-jni" // 这个是自定义的LOG的标识
    #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
    #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
    #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
    #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
    #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型
    
    
    extern "C"
    JNIEXPORT jstring
    JNICALL
    Java_com_example_ee_ndkdemo_MainActivity_stringFromJNI(
            JNIEnv *env,
            jobject /* this */) {
        std::string hello = "Hello from C++";
        return env->NewStringUTF(hello.c_str());
    }
    

    运行程序,则会发现在下面的目录中生成了不同的.so库,如下:


    20180519164954.png

    好的,第一步已经完成。
    其次,新建一个项目,将其不同的.so库拷贝到项目的目录下,这里有两种方法,第一种,将.so库拷贝到项目src->main->jniLibs下,不同的架构放在这个目录的不同文件夹下面即可,这是最简单的;第二种,将.so库拷贝到项目app->libs中,不同的架构放在这个目录的不同文件夹下面即可,但是这时候要在build.gradle中配置

    rceSets{ 
    main{ 
    jniLibs.srcDirs = ['libs'] 
    } 
    }
    

    这时候就会涉及到如何引用.so库里面的方法了,其实调用So库里的方法也有两种方式:
    (1)So库有对应的jar包,把jar包放进libs里就可以调用so库里面的方法了,当然得先把so放进jniLibs里;
    (2)只有So库,没有jar包,下面详细讨论这种情况…..
    没有jar包又想调用so里的方法,其实也是很简单的,前提当然是要把so库放进jniLibs里,然后看下面的代码

    public class MainActivity {
      static {
        System.loadLibrary("native-lib");
      }
    
      public String hh(){
        return stringFromJNI();
      }
      
      public  static native String stringFromJNI();
      public  static native String getMethod();
    }
    

    实际上我这是希望在另外一个项目中调用之前打包成so库的本地方法
    stringFromJNI(),事实上中间有一个必须要注意的细节,就是调用已经打包so库的那个类,必须要与已经生成的so库的类名,包名都要一致,否则就会出现问题,这是一个细节。所以笔者最后发现只有so库的调用实际上还是相对麻烦一下,因为你要调用的一些第三方的so库,比人不会告诉你他们的报名,已经加载这个so库所在的类名。相反例如百度推送以及七牛云等相关的so库,别人会额外再提供你一个相关的jar包,我们只需要操作jar包就Ok了,所以最终我认为对第三方so库里面方法的调用,so库配jar包的使用比单纯的so库的使用要简洁的多。

    相关文章

      网友评论

          本文标题:Java如何调用本地.so库里的方法

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