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 用于生成头文件 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
修改文件目录如下
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 文件夹
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 文件内容
/* 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 文件
9.在需要 native 方法的地方直接调用
NdkTest.getString(); NdkTest.doAdd(5, 12);
10.运行 app 试试效果吧
关于我
如果对你有帮助,请 star 一下,然后 follow 我,给我增加一下分享动力,谢谢!
如果你有什么疑问或者问题,可以提交 issue 和 request,发邮件给我 jeanboy@foxmail.com 。
或者加入下面的 QQ 群来一起学习交流。
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.