AndroidStudio 配置NDK/JNI开发环境


AndroidStudio 配置NDK/JNI开发环境

1、新建你的 AS 工程

 

2、在 AndroidStudio 中配置 NDK 路径

  方法如下:

  (1)先下载NDK并安装(这句基本是废话);

  (2)点菜单栏的 File->ProjectStructure…-> 在打开的窗口中左侧选中 SDKLocation-> 在右侧 Android NDK Location 中填入 NDK 目录所在路径,如下图所示:

                                  

 

  (3)首先写好我们的 java 文件

  如果有朋友不明白这里怎么写的,可以看我 JNI 栏第一、二篇文章

  JNI 原理介绍及最简单实例代码

  JNI 最简单例程步骤详解

   

                             

 

  先创建好我们的 JNITest.java 文件,内容如下:

1 package com.clay.example; 2 
3 public class JNITest { 4     public native String getJNIString(); 5 }

 

  (4)使用 javah 命令行生成 jni 目录及对应的头文件:

  这里我们使用 Android studio 的命令行终端就行,毕竟打开默认就是工程根目录,这里进行的 javac、javah 参数释义不再描述,前面两篇博文讲的很明白了,不清楚的同学可以去看看前面两篇博客。

                                         

 

  经过 javac 编译过后,我们看到了 JNITest.java 生成的 JNITest.class 文件

  我们使用 javah 生成 .h 文件

 

 

   生成的 .h 文件内容如下:com_clay_example_JNITest.h

 1 /* DO NOT EDIT THIS FILE - it is machine generated */
 2 #include <jni.h>
 3 /* Header for class com_clay_example_JNITest */
 4 
 5 #ifndef _Included_com_clay_example_JNITest  6 #define _Included_com_clay_example_JNITest
 7 #ifdef __cplusplus  8 extern "C" {  9 #endif
10 /*
11  * Class: com_clay_example_JNITest 12  * Method: getJNIString 13  * Signature: ()Ljava/lang/String; 14  */
15 JNIEXPORT jstring JNICALL Java_com_clay_example_JNITest_getJNIString 16   (JNIEnv *, jobject); 17 
18 #ifdef __cplusplus 19 } 20 #endif
21 #endif

 

  创建我们所需的 C/C++ Source File

 

   这里我们选择 .c 文件(C跟C++也没什么区别)

 

 1 //
 2 // Created by zhengchuanyu on 20-12-9.  3 //  4 #include <stdio.h>
 5 #include <stdlib.h>
 6 #include <jni.h>
 7 
 8 JNIEXPORT jstring JNICALL Java_com_clay_example_JNITest_getJNIString  9 (JNIEnv* env, jobject obj) 10 { 11     return (*env)->NewStringUTF(env, "Hello From JNITest Function(getJNIString)"); 12 }

 

  如果是 .cpp 文件

 1 //
 2 // Created by zhengchuanyu on 20-12-9.  3 //  4 #include <stdio.h>
 5 #include <stdlib.h>
 6 #include <jni.h>
 7 
 8 JNIEXPORT jstring JNICALL Java_com_clay_example_JNITest_getJNIString  9 (JNIEnv* env, jobject obj) 10 { 11     return env->NewStringUTF(env, "Hello From JNITest Function(getJNIString)"); 12 }

 

  在 jni 目录下创建 Android.mk 文件:

 

1 LOCAL_PATH := $(call my-dir) 2 
3 include $(CLEAR_VARS) 4 
5 LOCAL_MODULE := JNITest 6 LOCAL_SRC_FILES := \ 7 JNITest.c \ 8 
9 include $(BUILD_SHARED_LIBRARY)

 

  在 jni 目录下创建 Application.mk 文件(事实上这个可以不创建,但是还是讲一下吧)这一步的配置我嫌改 AndroidManifest.xml 跟 build.gradle 麻烦就没添加,如果你有兴趣可以去捣鼓一下,我自己也没有捣鼓明白,后面捣鼓明白了再补充上来。

1 APP_STL := gnustl_static 2 APP_CPPFLAGS := -frtti -fexceptions 3 # APP_ABI:是将要生成哪些 cpu 类型的 so, all 代表全部 4 APP_ABI := all 5 #APP——PLATFORM:生成的 so 的最低 android 版本 6 APP_PLATFORM := android-8

 

  在这里,我们会定义几个变量:

    LOCAL_PATH:        其值是 call my-dir,而 my-dir 是个宏函数,会返回 Android.mk 所在的路径,在这里,就是 jni 文件夹。

    include $(CLEAR_VARS),      这个命令会清除掉所有 LOCAL 开头的变量,比如 LOCAL_MODULE 之类的,但有一个例外,就是其上面的 LOCAL_PATH 。

    LOCAL_MODULE:      要生成的 so 包名,也是 Android 中 Java 代码加载时的名称。

    LOCAL_SRC_FILES:       要进行编译的源文件,如在这里,有JNITest.c。

    include $(BUILD_SHARED_LIBRARY):表明生成一个动态链接库。

    定义后这样一个Android.mk文件之后,在命令行中调用 ndk-build 命令,如下:

    ndk-build:command not found 请点击此链接  ndk-build:command not found

 

  命令实行之后,我们可以在项目目录下看到 libs 中多了一个 so 库,如下:

 

  到这里,关于Jni实现的就结束了,接下来就是如何在Android中使用这个本地方法了。

  我们创建了一个 Activity,在它里面只放置一个 TextView 控件,它的布局如下:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3  xmlns:tools="http://schemas.android.com/tools"
 4  android:layout_width="match_parent"
 5  android:layout_height="match_parent"
 6  tools:context=".MainActivity">
 7 
 8     <TextView  9         android:id="@+id/text"
10  android:layout_width="match_parent"
11  android:layout_height="wrap_content"
12  android:text="test"
13  android:textSize="20dp"/>
14 </LinearLayout>

 

  然后在 Activity 中,我们要加载这个 so 库,如下:

 1 package com.clay.example;  2 
 3 import androidx.appcompat.app.AppCompatActivity;  4 
 5 import android.os.Bundle;  6 import android.widget.TextView;  7 
 8 import org.w3c.dom.Text;  9 
10 public class MainActivity extends AppCompatActivity { 11 
12     static { 13         System.loadLibrary("JNITest"); 14  } 15 
16  @Override 17     protected void onCreate(Bundle savedInstanceState) { 18         super.onCreate(savedInstanceState); 19  setContentView(R.layout.activity_main); 20         TextView textView = (TextView) findViewById(R.id.text); 21         JNITest jniTest = new JNITest(); 22  textView.setText(jniTest.getJNIString()); 23  } 24 }

 

  最后还有一步要做:接下来就是使用so了,首先先与.so关联起来,有两种方法 

  (1)第一种方法,app/src/main目录下面创建一个jniLibs文件夹,将刚才生成的libs下的所有文件夹拷贝或者剪切到这里面,然后在 build.gradle中加入:

1 android { 2  ...... 3  sourceSets { 4  main() { 5             jni.srcDirs = [] //屏蔽掉默认的jni编译生成过程
6  } 7  } 8 }

 

  (2)第二种方法,直接在 gradle 中加入

1  sourceSets.main { 2             jni.srcDirs = [] //屏蔽掉默认的jni编译生成过程
3         jniLibs.srcDir 'src/main/libs' 
4   }

 

1 android {
2    ......
3     sourceSets {
4         main() {
5             jniLibs.srcDirs = ['src/main/libs']
6             jni.srcDirs = [] //屏蔽掉默认的jni编译生成过程
7         }
8     }
9 }

 

  1)利用 static 静态代码块,加载 so 库文件,可以看到在这里,这个名称就是 Anrdoid.mk 中定义的 LOCAL_MODULE 值。

  2)创建  JNITest 对象,调用其 getJNIString() 方法,最终显示结果如下:

  最后,我们总结一下这几个步骤:

  1)创建 Java 类文件,并定义 Native 方法,如 JNITest 类。

  2)利用 javac 生成 class 文件,利用 javah 生成 C/C++ 头文件,在这里要注意 (javah -d <path>(要生成的.h文件的目录) -classpath <path>(类所在的根目录) -jni -v(输出详细信息)) 的使用方法

  3)编写对应的C文件,如 JNITest.c,在里面实现C/C++的方法,记得要放在 jni 文件夹下面。

  4)编写 Android.mk 文件,利用 ndk-build 命令生成 so 文件。

  5)在 Android 中利用 static 静态代码块,调用 system.loadLibrary 方法来加载 so 库文件。

  6)在 build.gradle 中关联 ndk-build 编译出来的 so 库文件。

  7)在 Java 逻辑中调用之前定义的 JNITest 类的方法。

结束。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM