在看《安卓艺术探索》中Jni开发流程的时候发现里面的内容好像是Linux系统的,但自己电脑是Windows的,无法按照书上的流程正常操作。下面内容将按照《安卓艺术探索》的实例在Windows系统上生成so库并使用。(没看过这本书不影响阅读本篇文章)
Android Studio JNI是一种在Android Studio中使用JNI(Java Native Interface)的方法。JNI是一种Java平台的编程框架,它允许Java应用程序调用本地代码库中的函数。在Android开发中,JNI可以用于将Java代码与C/C++代码集成在一起,以提高应用程序的性能和功能。Android Studio提供了一些工具和插件,使得使用JNI变得更加容易和高效。
开发工具:Android Studio
下载路径:File -> settings -> Appearance&Behavior -> Android SDK -> SDK Tools-NDK
备注:勾选Show Package Details可以选择下载指定版本(不勾选,默认下载最新版本)
ndk默认下载到SDK目录下,复制ndk目录(SDK目录可以在项目的local.properties文件查看)
打开此电脑(桌面)-> 属性 -> 高级系统设置 -> 环境变量 -> 系统变量 -> Path -> 编辑 -> 新建,将复制的NDK路径配置在系统变量的path里面。
win+R -> cmd打开cmd输入ndk-build,如下图所示为成功配置。
创建一个类JniTest.java
JniTest.java,代码如下:
package com.habit.jnitest;
public class JniTest {
static {
System.loadLibrary("jni-test"); //加载so库
}
public native String get(); //声明两个本地方法
public native void set(String str);
}
在AS下方工具栏切换到Terminal,进入工程的java目录下,输入命令行:
javah -jni 包名.类名
在java目录下生成的com_habit_jnitest_JniTest.h文件。
.h文件中的代码如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_habit_jnitest_JniTest */
#ifndef _Included_com_habit_jnitest_JniTest
#define _Included_com_habit_jnitest_JniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_habit_jnitest_JniTest
* Method: get
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_habit_jnitest_JniTest_get
(JNIEnv *, jobject);
/*
* Class: com_habit_jnitest_JniTest
* Method: set
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_habit_jnitest_JniTest_set
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
其中get和set方法的写法要特别注意,在.h文件中方法名为Java_包名_类名_方法名。在写C代码是也要使用这种命名方式。
备注:.h文件不生成也是可以的,只是为了说明下面C代码要注意的细节。
在app目录下新建jni文件夹, 在jni文件夹中创建test.c文件(注:方法名要改成自己生成的.h文件中的方法名)
test.c,代码如下:
#include
#include
#include
#include
jstring
Java_com_habit_jnitest_JniTest_get(JNIEnv *env, jobject thiz) {
//参数一是日志级别,参数二是日志TAG,参数三就是日志内容
__android_log_print(ANDROID_LOG_ERROR, "test", "invoke get from C\n");
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
void
Java_com_habit_jnitest_JniTest_set(JNIEnv *env, jobject thiz, jstring string) {
__android_log_print(ANDROID_LOG_ERROR, "test", "invoke set from C\n");
char* str = (char*)(*env)->GetStringUTFChars(env,string,NULL);
__android_log_print(ANDROID_LOG_ERROR, "test", "%s\n", str);
(*env)->ReleaseStringUTFChars(env, string, str);
}
与.c文件一样,在jni文件夹创建(注:下方//注释在使用时要删掉,否则会报错)
Android.mk,文件内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#加入这句可以使得so文件打印日志
LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog
LOCAL_MODULE := jni-test //要生成的so库的名称,但实际为libjni-test.so
LOCAL_SRC_FILES := test.c //要使用的文件,刚才编写的test.c文件
include $(BUILD_SHARED_LIBRARY)
在文件夹打开工程app目录,在app目录下打开cmd
输入命令行:ndk-build
编译完成后会在app目录下生成libs和obj两个文件夹。obj文件夹可以直接删除,不会用到。
备注:在AS的Terminal里使用ndk-build命令可能会报错(原因是配置环境变量后,没有重启AS)
在local.properties中添加ndk的路径
ndk.dir=ndk的路径
在app\src\main目录下创建文件夹jniLibs,将libs生成的so库剪切到jniLibs文件夹中。
在MainActivity.java中调用JniTest.java的本地方法。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
JniTest jniTest = new JniTest();
System.out.println(jniTest.get());
jniTest.set("hello world");
}
}
以上简单介绍了生成so库的步骤,在实际安卓开发中虽然很少会需要开发so库,我自己也没有这个需求,但是闲下来的时候又想多学点东西实践一下,还是挺有意思的。