一个 Demo 告诉你怎么搞 JNI

来源:互联网 发布:h3c s7506e 端口聚合 编辑:程序博客网 时间:2024/06/05 10:20

Android-JNITest

项目地址:freekite/Android-JNITest
简介:一个 Demo 告诉你怎么搞 JNI
Android Studio JNI environment.

Android Studio JNI 环境配置。


介绍

Android Studio + NDK 来实现 JNI。

什么是 NDK 与 JNI 技术?
NDK:Native Development Kit

The NDK is a toolset that allows you to implement parts of your app using native-code languages such as C and C++.(谷歌官方文档)

大致意思:NDK 是一个工具,可以让你实现你的应用程序使用本地代码的语言,如 C 和 C++的部分。

JNI:Java Native Interface
它提供了若干的 API 实现了 Java 和其他语言的通信(主要是 C&C++)。从 Java1.1 开始,JNI 标准成为 java 平台的一部分,它允许 Java 代码和其他语言写的代码进行交互。

准备工作

  • 1.搭建好 Android Studio 开发环境。
  • 2.新建一个 Android 项目

Android Studio 配置 NDK

  • 1.如图所示下载 LLDB+NDK 并安装。
    第一

  • 2.配置安装好的 NDK 路径。
    第二

  • 3.配置一些快捷方式。
    第三
    javah
    ndk-build 三
    ndk-build clean

      javah    用于生成头文件  Program:$JDKPath$/bin/javah  注意:这个命令我加上了-encoding UTF-8 指定编码,你可以改成你工程的编码。  Parameters:-encoding UTF-8 -d ../jni -jni $FileClass$  Working directory:$SourcepathEntry$\..\java  ndk-build    用于构建 so 包  注意:MAC/Linux 用 ndk-build,没有.cmd 后缀  Program:C:\Develop\Android\sdk\ndk-bundle\ndk-build.cmd  Parameters:什么都不用填  Working directory:$ModuleFileDir$\src\main  ndk-build clean    清除 so 包  注意:MAC/Linux 用 ndk-build,没有.cmd 后缀  Program:C:\Develop\Android\sdk\ndk-bundle\ndk-build.cmd  Parameters:clean  Working directory:$ModuleFileDir$\src\main

配置项目

  • 在 gradle.properties 文件中添加
      android.useDeprecatedNdk=true
  • 修改文件目录如下
    修改文件目录

  • 参考Android Studio Project Site

  • 1.修改根目录下的 build.gradle

      buildscript {  repositories {      jcenter()  }  dependencies {  //    修改 build:gradle 为 build:gradle-experimental      classpath "com.android.tools.build:gradle-experimental:0.7.0"  //        classpath 'com.android.tools.build:gradle:2.1.2'      }  }  allprojects {      repositories {          jcenter()      }  }  //添加  task clean(type: Delete) {      delete rootProject.buildDir  }
  • 2.修改 gradle->wrapper->gradle-wrapper.properties

      #Mon Dec 28 10:00:20 PST 2015  distributionBase=GRADLE_USER_HOME  distributionPath=wrapper/dists  zipStoreBase=GRADLE_USER_HOME  zipStorePath=wrapper/dists  distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip//修改这里的版本号
  • gradle-experimental 与 gradle-wrapper 相对应的版本号如下图
    版本号对比

  • 3.修改 app->build.gradle

      修改之前的  apply plugin: 'com.android.application'  android {      compileSdkVersion 23      buildToolsVersion "23.0.3"      defaultConfig {          applicationId "com.jeanboy.demo.jnitest"          minSdkVersion 15          targetSdkVersion 23          versionCode 1          versionName "1.0"      }      buildTypes {          release {              minifyEnabled false              proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'          }      }  }  dependencies {      compile fileTree(dir: 'libs', include: ['*.jar'])      compile 'com.android.support:appcompat-v7:23.4.0'  }
      修改之后的  apply plugin: 'com.android.model.application'//修改  //apply plugin: 'com.android.application'  model {//修改      android {          compileSdkVersion 23          buildToolsVersion "23.0.3"          defaultConfig {              applicationId "com.jeanboy.demo.jnitest"              minSdkVersion.apiLevel 15              targetSdkVersion.apiLevel 23              versionCode   1              versionName   "1.0"          }          ndk {//指定生成的 lib,比如此时生成 native.so              moduleName   "NdkTest"          }          buildTypes {              release {                  minifyEnabled false                  proguardFiles.add(file("proguard-rules.pro"))//修改              }          }      }  }  dependencies {      compile fileTree(dir: 'libs', include: ['*.jar'])      compile 'com.android.support:appcompat-v7:23.4.0'  }
  • 4.创建 jni 文件夹
    创建 jni 文件夹

  • 5.创建 NdkTest.java

      public class NdkTest {      static {          System.loadLibrary("NdkTest");//加载要使用的 so 文件      }      //生命 native 方法      public static native String getString();      public static native int doAdd(int param1,int param2);  }
  • 6.生成 NdkTest.h 并创建 NdkTest.cpp 实现 NdkTest.h 中的 native 方法
    生成 NdkTest.h

NdkTest.h 文件内容

    /* DO NOT EDIT THIS FILE - it is machine generated */    #include <jni.h>    /* Header for class com_jeanboy_demo_jnitest_NdkTest */    #ifndef _Included_com_jeanboy_demo_jnitest_NdkTest    #define _Included_com_jeanboy_demo_jnitest_NdkTest    #ifdef __cplusplus    extern "C" {    #endif    /*     * Class:     com_jeanboy_demo_jnitest_NdkTest     * Method:    getString     * Signature: ()Ljava/lang/String;     */    JNIEXPORT jstring JNICALL Java_com_jeanboy_demo_jnitest_NdkTest_getString      (JNIEnv *, jclass);//待实现的 native 方法    /*     * Class:     com_jeanboy_demo_jnitest_NdkTest     * Method:    doAdd     * Signature: (II)I     */    JNIEXPORT jint JNICALL Java_com_jeanboy_demo_jnitest_NdkTest_doAdd      (JNIEnv *, jclass, jint, jint);//待实现的 native 方法    #ifdef __cplusplus    }    #endif    #endif

NdkTest.cpp 文件内容

    #include "com_jeanboy_demo_jnitest_NdkTest.h"    JNIEXPORT jstring JNICALL Java_com_jeanboy_demo_jnitest_NdkTest_getString            (JNIEnv *env, jclass type) {//具体实现        return env->NewStringUTF("hello world!!!");    }    /*     * Class:     com_jeanboy_demo_jnitest_NdkTest     * Method:    doAdd     * Signature: (II)I     */    JNIEXPORT jint JNICALL Java_com_jeanboy_demo_jnitest_NdkTest_doAdd            (JNIEnv *env, jclass type, jint param1, jint param2) {//具体实现        return param1 + param1;    }
  • 7.在 jni 文件夹下创建 Android.mk 和 Application.mk

Android.mk 文件内容

    LOCAL_PATH := $(call my-dir)    include $(CLEAR_VARS)    LOCAL_MODULE := NdkTest//moduleName    LOCAL_SRC_FILES := NdkTest.cpp//上面创建的 NdkTest.cpp    include $(BUILD_SHARED_LIBRARY)

Application.mk 文件内容

    APP_MODULES := NdkTest    /*这个变量是可选的,如果没有定义,NDK 将由在 Android.mk 中声明的默认的模块编译,并且包含所有的子文件(makefile 文件);    如果 APP_MODULES 定义了,它不许是一个空格分隔的模块列表,这个模块名字被定义在 Android.mk 文件中的 LOCAL_MODULE 中。    注意 NDK 会自动计算模块的依赖*/    APP_ABI := all//支持所有平台,也可以指定平台空格隔开 armeabi armeabi-v7a x86
    Android 系统目前支持的 CPU 架构:    ARMv5,ARMv7 (从 2010 年起)    x86 (从 2011 年起)    MIPS (从 2012 年起)    ARMv8,MIPS64 和 x86_64 (从 2014 年起)    每一个 CPU 架构对应一个 ABI    CPU 架构            ABI    ARMv5    --->    armeabi    ARMv7    --->    armeabi-v7a    x86        --->    x86    MIPS    --->    mips    ARMv8    --->    arm64-v8a    MIPS64    --->    mips64    x86_64    --->    x86_64    armeabi:默认选项,将创建以基于 ARM* v5TE 的设备为目标的库。 具有这种目标    的浮点运算使用软件浮点运算。 使用此 ABI(二进制接口)创建的二进制代码将可以    在所有 ARM*设备上运行。所以 armeabi 通用性很强。但是速度慢    armeabi-v7a:创建支持基于 ARM* v7 的设备的库,并将使用硬件 FPU 指令。    armeabi-v7a 是针对有浮点运算或高级扩展功能的 arm v7 cpu。    mips:MIPS 是世界上很流行的一种 RISC 处理器。MIPS 的意思是“无内部互锁流水级    的微处理器”(Microprocessor without interlocked piped stages),其机    制是尽量利用软件办法避免流水线中的数据相关问题。    x86:支持基于硬件的浮点运算的 IA-32 指令集。x86 是可以兼容 armeabi 平台运行    的,无论是 armeabi-v7a 还是 armeabi,同时带来的也是性能上的损耗,另外需要    指出的是,打包出的 x86 的 so,总会比 armeabi 平台的体积更小。    总结    如果项目只包含了 armeabi,那么在所有 Android 设备都可以运行;    如果项目只包含了 armeabi-v7a,除 armeabi 架构的设备外都可以运行;     如果项目只包含了 x86,那么 armeabi 架构和 armeabi-v7a 的 Android 设备是无法    运行的;    如果同时包含了 armeabi,armeabi-v7a 和 x86,所有设备都可以运行,程序在运    行的时候去加载不同平台对应的 so,这是较为完美的一种解决方案,同时也会导致    包变大。
  • 8.生成 so 文件
    生成 so 文件

  • 9.在需要 native 方法的地方直接调用

      NdkTest.getString();  NdkTest.doAdd(5, 12);
  • 10.运行 app 试试效果吧

0 0
原创粉丝点击