• Android Studio使用JNI和NDK进行开发


    想要学习一下在Android Studio中进行JNI的开发,文章挺多的,但是几乎没有一个完整的说明的,中间总是有一两步漏掉。分享技术就应该完整的让读者学会,藏着掖着不是君子所为。对于那些故意含糊过去的,我只想说Navie!

    转载请注明出处 http://www.cnblogs.com/qiusuo/p/5656625.html

    正文

    JNI是JAVA标准平台中的一个重要功能,它弥补了JAVA的与平台无关这一重大优点的不足,在JAVA实现跨平台的同时,也能与其它语言(如C、C++)的动态库进行交互,给其它语言发挥优势的机会。

    Android NDK(Native Development Kit )是一套工具集合,允许你用像C/C++语言那样实现应用程序的一部分。

    1. 在使用NDK之前需要配置NDK和LLDB
      通过使用SDK Manager找到NDK和LLDB,进行安装
    2. 按照一般方法,创建一个Android应用
      File - New - New Project

    3. 创建一个新的Java Class(与MainActivity一个目录),类名为JniDemo,其中有一个Native方法
      package com.example.angel.myapplication;
      
      /**
       * Created by Angel on 2016/7/8.
       */
      public class JniDemo {
          public native String getJniMessage();
      } 
    4. 编译JniDemo.java这个带有Native方法的类
      在命令提示符中,cd到文件所在目录,执行javac JniDemo.java,可以看到目录中生成了对应的.class文件
    5. 生成对应的.h头文件
      a) 在命令提示符中,cd到src/main/java文件夹中(内部的目录结构是包名,例如我的包名是com.example.angel.myapplication,目录结构为/src/main/java/com/example/angel/myapplication)
      b) 执行javah com.example.angel.myapplication.JniDemo,会在当前目录生成head file(.h)文件。
    6. 在Project树形目录下app - src - main,建立jni folder,并将head file放到里边
       
    7. 在jni文件夹中创建C/C++源文件,并include这个头文件,实现其中的方法。
      #include "com_example_angel_myapplication_JniDemo.h"
      JNIEXPORT jstring JNICALL Java_com_example_angel_myapplication_JniDemo_getJniMessage
        (JNIEnv *, jobject)
      {
          return (*env)->NewStringUTF(env,"Jni Message: Hello World!");
      }
    8. build - Rebuild Project后,会出现一个错误。并且给出了解决方案:Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.
      在gradle.properties中添加一行android.useDeprecatedNdk=true
    9. build - Rebuild Project后,又会出现warming,NDK option is not configured。按照提示,进行如下内容的添加:
      在app的build.gradle文件中,添加如下内容:
      android {
          sourceSets {
              main {
                  jniLibs.srcDir 'src/main/jni'
              }
          }
      }

      并且自定义so库的名称

      android {
          ......
          defaultConfig {
              ......
              ndk {
                  moduleName 'jnidemo'//自定义名称
              }
          }
      }

      如果不这么做的话,生成的库文件名称是[lib][module name].so

    10. build - Rebuild Project,可以看到生成了so文件
      在目录:app - build - intermediates - ndk - debug - lib下
    11. 加载so文件。
      so文件加载一次便可以使用,一般情况下,在静态代码段中进行加载
          static {
              System.loadLibrary("jnidemo");
          }
    12. 使用Native方法
      public class MainActivity extends AppCompatActivity {
          static {
              System.loadLibrary("jnidemo");
          }
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
              final JniDemo jniDemo = new JniDemo();
              TextView textView = (TextView) findViewById(R.id.text);
              textView.setText(jniDemo.getHelloWordText());
          }
      } 
    13. Native方法使用java代码
      在Java代码中,创建如下方法,用以在Native代码中调用
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              sContext = getApplicationContext();
          }
          private static Context sContext;
          public static void showToast() {
              Toast.makeText(sContext, "此方法由Native方法调用", Toast.LENGTH_SHORT).show();
          }

      在Native代码中,使用如下代码进行调用

          //找到我们要调用的方法,注意包名+类名
          jclass clazz = (*env)->FindClass(env,"com/example/angel/myapplication/MainActivity");
          //获取某个静态方法的ID
          //clazz 是我们上面找到的类的字节码文件
          //showToast 是clazz类中的方法名
          //"()V" 这个表示方法的签名;()是方法的参数列表;V表示方法的返回类型;V -> void
          jmethodID id = (*env)->GetStaticMethodID(env,clazz, "showToast","()V");
          //最后调用这个方法,CallStaticVoidMethod(clazz,方法ID)
          (*env)->CallStaticVoidMethod(env,clazz,id);
  • 相关阅读:
    Oracle不同版本中序列的注意点
    SQLite – LIMIT子句
    LeetCode:219. Contains Duplicate II
    python返回值进行unpack
    Android编程权威指南第三版 第32章
    ThinkPHP使用soapclient调用webservice接口
    C++杂记
    关于Docker清理
    Leetcode 063 不同路径二
    第五章:详解广播机制
  • 原文地址:https://www.cnblogs.com/qiusuo/p/5656625.html
Copyright © 2020-2023  润新知