Android NDK——配置NDK及使用Android studio开发Hello JNI并简单打包so库

引言

尽管Android Studio已经越来越流行了,但很多人还是习惯于Eclipse或源码环境下开发JNI应用。笔者是从以前在学校参加谷歌大学学术合作项目的时候接触JNI的,当时是为了模仿底层的方法实现一个功能,使用的是Eclipse,直到最近项目中需要用到SmartLink、AirKiss才又再次接触到JNI,第一次使用Android Studio开发NDK,遇到不少弯路再次总结下,以期能帮助新手快速入门不再迷茫。

一、NDK相关角色概述

1、NDK和SO

Android NDK——配置NDK及使用Android studio开发Hello JNI并简单打包so库_第1张图片
NDK 全称 Native Development Kit,是Google在Android开发中提供的一套用于快速创建native工程的一个工具。从上图这个Android系统框架来看,我们上层是通过JNI方式来调用NDK层的,使用这个工具可以很方便的编写和调试JNI的代码。因为C语言不跨平台,在Windows系统下使用NDK编译在Linux下能执行的函数库——SO文件,全称Shared Objects,其实质就是一堆c、c++的头文件和实现文件打包成一个库。目前Android系统目前支持以下七种不同的CPU架构,每一种对应着各自的应用程序二进制接口ABI:(Application Binary Interface)定义了二进制文件(尤其是.so文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库。

  • ARMv5——armeabi
  • ARMv7 ——armeabi-v7a
  • ARMv8——arm64- v8a
  • x86——x86
  • MIPS ——mips
  • MIPS64——mips64
  • x86_64——x86_64

以本人ODM经验来说,你应该尽可能的提供专为每个ABI优化过的.so文件,(尽量不要混合着使用)。你应该为每个ABI目录提供对应的.so文件。当一个应用安装在设备上,只有该设备支持的CPU架构对应的.so文件会被安装。在x86设备上,libs/x86目录中如果存在.so文件的 话,会被安装,如果不存在,则会选择armeabi-v7a中的.so文件,如果也不存在,则选择armeabi目录中的.so文件(因为x86设备也支 持armeabi-v7a和armeabi)。ps: Native Libs Monitor 这个应用可以帮助我们理解手机上安装的APK用到了哪些.so文件,以及.so文件来源于哪些函数库或者框架。

2、JNI

Android NDK——配置NDK及使用Android studio开发Hello JNI并简单打包so库_第2张图片
JNI 全称Java Native Inteface,即Java本地接口,是Java中定义的一种用于连接Java和C/C++接口的一种实现方式。Java语言装载到虚拟机中,不能和硬件交互,不能驱动开发。JNI扩展了Java虚拟机的能力,驱动开发、无线热点共享,底层语言(C、C++)效率高,数学运算、实时渲染的游戏,音视频处理等等,简而言之,就是Java代码调用c、c++代码,JNI模式一共涉及到三个角色:C/C++ 代码本地方法接口类Java层中具体业务类

1、JNI简要流程

2、JNI的变量类型与Java类型对比表

Java中变量的类型 JNI对应的类型名 C/C++变量类型
boolean jboolean unsigned char
float jfloat float
double jdouble double
byte jbyte signed char
char jchar unsigned short
short jshort short
int jint/jsize int
long jlong long long
Object jobject void *
String jstring void *

3、JNI的基本语法

  • 命名规则
    JNIExport jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,jobject thiz )

  • Java端加载so

 System.loadLibrary("helloJni");//加载so文件,不要带上前缀lib和后缀.so
  • Java端的调用jni
((TextView)findViewById(R.id.jni_text)).setText(helloJni());

3、Gradle

Gradle 是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置。以往Android NDK开发需要在Eclipse或源码环境下,建立并配置Android.mk和Application.mk,且还要通过java命令生成.h头文件,才能编译生成so库。但在Android Studio中这些步骤都不需要,因为Gradle足够强大,只需配置Gradle即可编译生成so库。

三、开发JNI的步骤

JNI代码主要又分为Native代码和Java代码,所以我们得实现Native端和Java端

1、安装NDK配置环境变量和相关插件(NDK、CMake、LLDB)

Android NDK——配置NDK及使用Android studio开发Hello JNI并简单打包so库_第3张图片

把NDK里build目录添加到path变量 ,比如我的目录是D:\AndroidDevlopment\SDK\ndk-bundle

2、新建一个Android标准工程,并在工程设置中配置NDK路径。

3、打开app下的 build.gradle,配置NDK和在gradle.properties里配置android.useDeprecatedNdk=true

 ndk{
    moduleName "helloJni"//*生成的so文件名,必填
    abiFilters "armeabi", "armeabi-v7a", "x86" //配置输出的abi体系结构下的so库,
}

配置支持NDK

android.useDeprecatedNdk=true//是灰色的不影响

Android NDK——配置NDK及使用Android studio开发Hello JNI并简单打包so库_第4张图片
若不配置android.useDeprecatedNdk=true点击脚本同步,之后会报这个错误

4、在Actiivty类文件里定义jni本地接口方法

public class MainActivity extends AppCompatActivity {

    static {
        System.loadLibrary("helloJni");//加载so文件,不要带上前缀lib和后缀.so
    }
    public native String helloJni();//定义本地方法接口,这个方法类似虚方法,实现是用c或者c++实现的

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

5、生成对应的C文件默认实现

在我们定义了本地接口方法之后,我们在方法上按alt+Enter,然后生成对应的方法,可是不出意外的话生成的c文件只是有一个头文件的,并没有为我们生成对应的方法框架,

#include <jni.h>

如果你熟悉Jni的语法可以自己去实现,但是太麻烦了,幸好谷歌为我们提供了一个插件gradle-experimental,我们只需要在app下的gradle.build脚本里配置(仅仅在我们生成jni方法框架时添加,当我们全部添加完JNI方法框架之后,必须注释或者删除掉,否则run的时候就绝对报错)

  • gradle-experimental插件
    在2015年5月的Google I/O大会上, Google宣布Android Studio开始支持NDK开发,通过和JetBrains的合作,将Clion整合进了Android Studio 1.3,并免费支持NDC++开发。同年7月,在Android Studio 1.3版本上添加了 gradle-experimental插件,该插件支持NDK开发和调试,且带有代码不全和重构等高级功能。
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:24.2.1'
    compile 'com.android.tools.build:gradle-experimental:0.7.0'//仅仅在我们生成jni方法框架时添加,当我们全部添加完JNI方法框架之后,必须注释或者删除掉,否则run的时候就绝对报错
}

配置成功了之后,再执行下脚本,把原来生成的jni文件夹删除掉,再按万能键,这时候就妥妥滴生成了c文件

#include <jni.h>

JNIEXPORT jstring JNICALL Java_crazymo_train_jnitraining_MainActivity_helloJni(JNIEnv *env,jobject instance){
    // TODO
    return (*env)->NewStringUTF(env, "Hello Jni");
}

6、完成上面5个步骤之后,就可以make或者run了,然后就会生成对应的so文件(..\build\intermediates\ndk\debug\obj\local)

完整的Activity实现如下:

package crazymo.train.jnitraining;

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

public class MainActivity extends AppCompatActivity {

    static {
        System.loadLibrary("helloJni");//加载so文件,不要带上前缀lib和后缀.so
    }
    public native String helloJni();//定义本地方法接口,这个方法类似虚方法,实现是用c或者c++实现的

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((TextView)findViewById(R.id.jni_text)).setText(helloJni());//调用JNI
    }
}

二、HelloJNI源码

这么简单的也上传源码Hello JNI源码

你可能感兴趣的:(android,jni,NDK,native,本地接口方法)