/Android-JNITest

Android Studio JNI environment.

Primary LanguageJavaApache License 2.0Apache-2.0

Android-JNITest

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
	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试试效果吧

关于我

如果对你有帮助,请 star 一下,然后 follow 我,给我增加一下分享动力,谢谢!

如果你有什么疑问或者问题,可以提交 issue 和 request,发邮件给我 jeanboy@foxmail.com

或者加入下面的 QQ 群来一起学习交流。

Android技术进阶:386463747

License

Copyright 2015 jeanboy

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.