靠谱Android Studio JNI Demo

前言

作为工作了近四年时间的Android开发,搞通这个Demo用了一个工作日,觉得自己动手能力有些差,所以记录下。这里我们不介绍JNI的基础理论知识。只讲Demo流程。

Demo

第一步

创建Demo工程,从SDK Manager中下载NDK相关组件,同时将Support Repository也下载下来

第二步

创建Java文件,如下:

package com.example.jnidemo;

public class JNITest {

    public native String getStrFromJNI();
    
}

第三步

使用javah命令生成JNITest的头文件。我就是这步卡主的,在使用javah命令过程中遇到了很多问题。例如 javah不是命令、无法识别的文件名、找不到类文件。这里我说下我这里如何跑通的。注意以下几点。

  • 1、在Android Studio的终端中使用Javah如果报不是内部或外部命令,也不是可运行的程序。则在cmd命令行中执行,只要环境变量配置无误,一定会识别javah命令

  • 2、在生成的classes文件夹目录下使用命令,在源文件目录下执行会报找不到xxx的类文件

  • 3、之前class文件目录是在build/intermediates/classes/debug下。我一度怀疑没有生成class文件。后来发现目录是:build/intermediates/javac/debug/complieDebugJavaWithJavac/classes下。那么我们就在如下目录下执行如下命令:

javah -jni com.example.jnidemo.JNITest

如下:
命令执行截图
生成的.h文件就在同目录下,如下:

生成.h文件截图

第四步

在src/main/下建立jni文件下,jni文件夹与java文件是平行的。建立方法如下:

创建jni文件

第五步

将刚刚生成的.h文件复制到jni目录下,并编写其实现类,文件名自取,我们这里就叫demo.c。如下:

//
// Created by xxx on 2019/6/17.
//
#include<jni.h>
//导入头文件
#include "com_example_jnidemo_JNITest.h"  
//实现.h文件中定义的方法
jstring Java_com_example_jnidemo_JNITest_getStrFromJNI(JNIEnv *env,jobject thiz){
    return (*env)->NewStringUTF(env,"I am Str from jni libs!");
}

第六步

在jni文件夹下建立Android.mk文件用于编译,如下:

#my-dir:返回当前 Android.mk 所在的目录的路径
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

# 定义生成so文件的名字
LOCAL_MODULE := hello-jni
# 需要编译的文件,由于在一个文件夹下,不用写路径
LOCAL_SRC_FILES := demo.c

include $(BUILD_SHARED_LIBRARY)
# 指定生成全部的ABI的so文件
APP_ABI := all

第七步

在app.gradle中android{}内添加ndk相关配置,如下:

externalNativeBuild {
        ndkBuild {
            path 'src/main/jni/Android.mk'
        }
    }

第八步

make project即可看到生成的so文件,如下:

生成so截图

可以看到每个ABI均生成了so文件,但是so文件的名字多了个前缀lib,这是因为Android强制要求所有的so文件必须是lib前缀,我们可以看到例如高德地图、融云聊天等第三方的so库也是如此

第九步

加载so文件并使用,如下:

package com.example.jnidemo;

public class JNITest {
    static {
        System.loadLibrary("jni-demo");//与Android.mk文件中设置的一致,不需要手动添加前缀lib
    }
    public native String getStrFromJNI();
}
package com.example.jnidemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new JNITest();
        ((TextView)findViewById(R.id.tv_info)).setText(new JNITest().getStrFromJNI());
    }
}

文件目录

文件目录截图

写在后边

这里只介绍了最基础最简单的jni使用方法,还有如CMake等方式没有调研。后边有时间会陆续更新。如照着这个Demo跑不通可留言共同探讨。网上还有另一种方式,不写Android.mk文件,而是在app.gradle的defaultConfig{}下添加ndk设置,如下:

 ndk {
            moduleName "NdkJniDemo"          //生成的so名字
            abiFilters "armeabi-v7a", "x86","arm64-v8a","x86_64" //输出指定三种abi体系结构下的so库,目前可有可无。
        }

我并没有跑通。没有继续纠结。

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页