转载请标明出处:
http://blog.youkuaiyun.com/tyzlmjj/article/details/50725281
本文出自:【M家杰的博客】
2016-3-27更新
目前Android Studio使用NDK的最佳方式看这里
以下为原文
环境搭建
- 安装NDK
SDK工具里面已经提供了NDK的下载,以后不需要再去官网找地址自己下载了。
注意:用这个下载的时候可能遇到第一次下载完但是安装不成功的情况,再勾选一次就能完成安装了,我两台电脑都是点两次才成功!
- 为module添加NDK
下载完的NDK就在原来的SDK目录下
- 修改配置文件
在Project的build.gradle文件中修改如下
……
dependencies {
//注释掉这个
//classpath 'com.android.tools.build:gradle:1.5.0'
//修改成如下
classpath 'com.android.tools.build:gradle-experimental:0.4.0'
}
……
在Module的build.gradle文件中修改,这个修改比较多,我贴下修改前后的2份文件方便对比。
注意:不同于Eclipse,没有什么Android.mk文件,NDK的配置都在这里完成,具体看官方文档
新建项目自动生成的:
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.mjj.jnitest"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
修改后的文件:
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.2"
defaultConfig.with {
applicationId = "com.mjj.jnitest"
minSdkVersion.apiLevel = 15
targetSdkVersion.apiLevel = 23
versionCode = 1
versionName = "1.0"
}
}
android.ndk {
moduleName = "jni-Demo"
ldLibs.addAll(["android", "log"])
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles.add(file('proguard-rules.txt'))
}
}
android.productFlavors {
create("arm") {
ndk.abiFilters.add("armeabi")
}
create("arm7") {
ndk.abiFilters.add("armeabi-v7a")
}
create("arm8") {
ndk.abiFilters.add("arm64-v8a")
}
create("x86") {
ndk.abiFilters.add("x86")
}
create("x86-64") {
ndk.abiFilters.add("x86_64")
}
create("mips") {
ndk.abiFilters.add("mips")
}
create("mips-64") {
ndk.abiFilters.add("mips64")
}
create("all")
}
}
- 创建jni文件夹
上面的都完成之后,这个项目就可以使用NDK了。首先创建一个存放本地代码的目录,目录就叫jni,默认位置../项目/src/main/jni
编译头文件
开始使用NDK开发写代码之前,还需要了解一点基本的命令,比如生成头文件的命令,这在开发中使用频率还是比较高的。
- 基本命令
生成.h
头文件的命令, -jni是默认的,不写也可以
javah -jni [包名.类名]
例:
javah -jni com.test.MyClass
- 编码问题
国内基本都用UTF-8编码,在windows下一般默认是GBK,编译的时候会出错,这个时候就要声明下编码,使用-encoding
javah -encoding UTF-8 com.test.MyClass
- 在Android Studio工程中使用
首先CD
到放Java包的目录下,一般的目录../项目名/src/main/java
按标准的目录格式,生成的头文件要放到jni
文件夹中,使用修饰符-d
javah -d ../jni com.test.MyClass
按上面这样生成头文件比较方便,也可以加上编码声明:
javah -encoding UTF-8 -d ../jni com.test.MyClass
简单例子
官方的例子在Android Studio中可以很方便的导入,建议看看官方例子。下面是我写的一个简单的例子。
新建一个项目,里面只有一个ManActivity类和一个对应的布局文件。
在ManActivity中声明一个本地方法并加载本地库,代码如下:
public class MainActivity extends AppCompatActivity {
//加载library
static {
System.loadLibrary("jni-Demo");
}
//本地方法
private native String sayHello();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = (TextView) findViewById(R.id.textView);
//使用本地方法
textView.setText(sayHello());
}
}
注意:上面代码中System.loadLibrary("jni-Demo")
这一段中jni-Demo
这个名字是在module的Build.gradle的android.ndk标签中定义好的
然后用命令行CD到java
目录,生成头文件,我的包名是:com.mjj.jnitest
所以命令是这样的:
javah -encoding UTF-8 -d ../jni com.mjj.jnitest.MainActivity
成功之后就会在jni目录生成一个.h文件。
然后在jni目录新建一个C++文件,导入刚才的头文件并且把头文件里的方法复制过来修改下,代码如下:
#include "com_mjj_jnitest_MainActivity.h"
#include <jni.h>
JNIEXPORT jstring JNICALL Java_com_mjj_jnitest_MainActivity_sayHello
(JNIEnv *env, jobject jobject1)
{
return env->NewStringUTF("这是一段本地方法返回的字符串!");
}
到这里就完成了一个简单的例子。其实在这个例子中,你不生成头文件也没关系,创建一个C++文件,自己手动写这个方法名就可以了。
在本地代码中打印Log
先在build.gradle的android.ndk标签中添加依赖
android.ndk {
……
ldLibs.addAll(["android", "log"])
}
然后在C文件中添加代码如下:
//导入日志头文件
#include <android/log.h>
//修改日志tag中的值
#define LOG_TAG "asd"
//日志显示的等级
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
上面的代码主要是简化使用时的操作,可以很简单的使用:
LOGI("打印一个整型:%d",22);