Android Studio JNI开发(C语言版)

作者:陆金龙    发表时间:2018-08-21 00:29   


2.JNI开发

2.1 配置jni开发工具

* ndk (native develop kit ) 下载http://developer.android.com/tools/ndk/index.html

解压到C:\Android\android-sdk\ndk-bundle,将该目录配置到系统环境变量(测试下ndk-build出现下面提示说明配置成功)

C:\Users\kl>ndk-build

Android NDK: Could not find application project directory !

Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.

C:\Android\android-sdk\ndk-bundle\build\\..\build\core\build-local.mk:151: *** Android NDK: Aborting    .  Stop.

 

* ndk目录

* docs 帮助文档

* platforms  好多平台版本文件夹 选择时选择项目支持的最小版本号对应的文件夹

* 每一个版本号的文件夹中放了 不同cpu架构的资源文件

* include文件夹 jni开发中常用的 .h头文件

* lib 文件夹 google打包好的 提供给开发者使用的 .so文件

* samples google官方提供的样例工程 可以参考进行开发

* android-ndk-r9d\build\tools linux系统下的批处理文件 在交叉编译时会自动调用

* ndk-build 交叉编译的命令

* cdt eclipse的插件 高亮C代码 C的代码提示

2.2 Android Studio环境配置

* 配置local.properties

ndk.dir=C\:\\Android\\android-sdk\\ndk-bundle
sdk.dir=C\:\\Android\\android-sdk

* 配置gradle.properties

android.useDeprecatedNdk=true

* 配置app的build.gradle(指定so包的地址,可以设置了libs)

// 把 ndk 放在 defaultConfig 里面 否则报错Could not find method ndk() for arguments
ndk{
    //设置支持的SO库架构
    abiFilters 'armeabi' ,'x86','armeabi-v7a','x86_64','arm64-v8a', "mips"
}

 

// 把 sourceSets.main  放在android下

sourceSets.main {
    jniLibs.srcDir 'libs'
    jni.srcDirs = []//disable automatic ndk-build call
}

 

2.3 编写代码

创建工具类JniMethod(其中System.loadLibrary("JniMethod");中的"JniMethod"是so文件的名字去掉"lib",用来指定要用到的so文件,有的人可能getNativeString会报红线,不用管,手动去除就好)

public class JniDemoActivity extends BaseSimpleActivity implements View.OnClickListener {
    private TextView tvTest;
    private Button btnTest;
    @Override
    protected int getLayoutResID() {
        return R.layout.activity_jni;
    }
    @Override
    protected void initContentView() {
        initView();
    }
    @Override
    protected boolean onGoBack() {
        return false;
    }
    private void initView() {
        tvTest = (TextView) findViewById(R.id.tv_test);
        btnTest = (Button) findViewById(R.id.btn_test);
        btnTest.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_test:
                tvTest.setText(getNativeString("本地方法"));
                break;
        }
    }

    static {
        System.loadLibrary("JniMethod");
    }
    public static native String getNativeString(String s);

2.4 生成so文件

1.生成class文件

切换路径到JniDemoActivity.java所在目录下,执行命令 javac JniDemoActivity.java

E:\>cd E:\workdata\code\android\android-architecture\Arch\app\src\main\java\com\klfront\arch

E:\workdata\code\android\android-architecture\Arch\app\src\main\java\com\klfront\arch>javac JniDemoActivity.java

或者Android Studio的Build菜单栏下的Make Project命令生成.class文件(生成到这里的 执行javah有问题)

2.javah生成c头文件

点击"View->Tool Windows->Terminal",执行如下命令生成c语言头文件

javah -classpath E:\workdata\code\android\android-architecture\Arch\app\build\intermediates\classes\debug\com\klfront\arch -d E:\workdata\code\android\android-architecture\Arch\app\src\main -jni com.klfront.arch.JniDemoActivity

错误: 找不到 'com.klfront.arch.JniDemoActivity' 的类文件。

简单写一个不带包名的类文件,javac得到class文件,然后javah测试就OK。

网上查了很多,试了很多,最后确定是与包相关的问题,解决方案:

(1)就在.java源文件的目录下,javac生成.class文件

(2)直接cd到class包名所在目录的上一级,然后javah com.klfront.arch.JniMethod,如下:

E:\workdata\code\android\android-architecture\Arch\app\src\main\java>javah com.klfront.arch.JniMethod

3.实现JNI方法

main下创建文件夹jni 并把JniMethod.h导入进去,并创建JniMethod.c

JniMethod.h中的方法签名:

JNIEXPORT jstring JNICALL Java_com_klfront_arch_JniMethod_getNativeString
  (JNIEnv *, jclass, jstring);

JniMethod.c按照JniMethod.h的签名实现方法:

#include <stdlib.h>
#include <stdio.h>
#include <jni.h>
#include <android/log.h>
#define LOG_TAG "System.out"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
JNIEXPORT jstring JNICALL Java_com_klfront_arch_JniMethod_getNativeString
  (JNIEnv *env, jclass obj, jstring arg){
      char* hellostr = "hello from c!";
      char* str=(char*)(*env)->GetStringUTFChars(env,string,NULL);
      return (*env)->NewStringUTF(env,hellostr);
  }

4.配置Android.mk和Application.mk

Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := JniMethod
LOCAL_SRC_FILES := JniMethod.c
LOCAL_LDLIBS += -llog

include $(BUILD_SHARED_LIBRARY)

Application.mk 按如下配置可生成各个CPU平台下的动态库

APP_ABI := all

5.使用ndk-build编译生成.so库

在app的build.gradle中,android节点里添加

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

在Terminal中运行cd到main目录,执行ndk-build指令,就可以在和jni目录同级生成一个libs文件夹,里面存放相对应的平台的.so库。

E:\workdata\code\android\android-architecture\Arch>cd app/src/main

E:\workdata\code\android\android-architecture\Arch\app\src\main>ndk-build

 

打包运行测试,ok。