Android Studio生成so库


前言

在看《安卓艺术探索》中Jni开发流程的时候发现里面的内容好像是Linux系统的,但自己电脑是Windows的,无法按照书上的流程正常操作。下面内容将按照《安卓艺术探索》的实例在Windows系统上生成so库并使用。(没看过这本书不影响阅读本篇文章)


一、JNI是什么?

Android Studio JNI是一种在Android Studio中使用JNI(Java Native Interface)的方法。JNI是一种Java平台的编程框架,它允许Java应用程序调用本地代码库中的函数。在Android开发中,JNI可以用于将Java代码与C/C++代码集成在一起,以提高应用程序的性能和功能。Android Studio提供了一些工具和插件,使得使用JNI变得更加容易和高效。

二、JNI的开发流程

1. NDK的下载和配置

1.1 NDK的下载

开发工具:Android Studio
下载路径:File -> settings -> Appearance&Behavior -> Android SDK -> SDK Tools-NDK
备注:勾选Show Package Details可以选择下载指定版本(不勾选,默认下载最新版本)
在这里插入图片描述

1.2 环境配置

ndk默认下载到SDK目录下,复制ndk目录(SDK目录可以在项目的local.properties文件查看)
在这里插入图片描述
打开此电脑(桌面)-> 属性 -> 高级系统设置 -> 环境变量 -> 系统变量 -> Path -> 编辑 -> 新建,将复制的NDK路径配置在系统变量的path里面。
在这里插入图片描述

1.3 验证配置是否成功

win+R -> cmd打开cmd输入ndk-build,如下图所示为成功配置。
在这里插入图片描述

2. 生成so库

2.1 生成.h文件(该步骤可以跳过)

创建一个类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 <jni.h>
/* 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代码要注意的细节。

2.2 编写.c文件

在app目录下新建jni文件夹, 在jni文件夹中创建test.c文件(注:方法名要改成自己生成的.h文件中的方法名)

test.c,代码如下:

#include <string.h>
#include <stdio.h>
#include <jni.h>
#include <android/log.h>

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);
}

2.3 新建Android.mk文件

与.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)

不删除//注释的报错:
在这里插入图片描述

2.4 生成so库

在文件夹打开工程app目录,在app目录下打开cmd

输入命令行:ndk-build

在这里插入图片描述
编译完成后会在app目录下生成libs和obj两个文件夹。obj文件夹可以直接删除,不会用到。
在这里插入图片描述

备注:在AS的Terminal里使用ndk-build命令可能会报错(原因是配置环境变量后,没有重启AS)
在这里插入图片描述

3. so库的使用

3.1 在AS配置ndk

在local.properties中添加ndk的路径

ndk.dir=ndk的路径

在这里插入图片描述

3.2 运行so库

在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库,我自己也没有这个需求,但是闲下来的时候又想多学点东西实践一下,还是挺有意思的。

猜你喜欢

转载自blog.csdn.net/weixin_46092051/article/details/131598755