android studio使用jni的方法很简单,但是在使用的过程中会出现很多的问题,查阅了很多教程,今天做个总结:
1、不要在继承AppCompatActivity的类中声明native方法,另写一个类,如下声明加载so的静态代码块,以及声明一个native方法,如下所示:
package com.chensd.jnitest;
/**
* Created by chensd on 2016/11/23.
*/
public class JniTest {
public native String getStringFromNative();
static {
System.loadLibrary("JniTest");
}
}
2、如上操作后,native方法会是红色的,不要在意这个!下文再解决。接下来在main\src\java下的acitivty编写简单的实例代码:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
JniTest jniTest = new JniTest();
TextView textview = (TextView) findViewById(R.id.textview);
textview.setText(jniTest.getStringFromNative());
}
}
3、编译生成class文件,两种方法:
a)直接利用Build->Make Project
b)打开Terminal cd到我们的JniTest.java文件下,执行 javac JniTest.java
编译后生成的文件在../app/build/intermediates/classes/debug/com/chensd/jintest
4、利用javah命令生成.h头文件:
打开Terminal,定位到项目的java文件下,执行javah命令
E:\android_csd\JniTest\app\src\main\java>javah -d ../jni com.chensd.jnitest.JniTest
之后会在java的同级目录下生成一个jni目录,该目录下会有一个.h的文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_chensd_jnitest_JniTest */
#ifndef _Included_com_chensd_jnitest_JniTest
#define _Included_com_chensd_jnitest_JniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_chensd_jnitest_JniTest
* Method: getStringFromNative
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_chensd_jnitest_JniTest_getStringFromNative
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
5、在jni目录下新建一个main.c的文件,copy 该.h文件内容,并且实现里面的主题方法返回一个简单的字符串:
#include <jni.h>
/* Header for class com_chensd_jnitest_JniTest */
#ifndef _Included_com_chensd_jnitest_JniTest
#define _Included_com_chensd_jnitest_JniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_chensd_jnitest_JniTest
* Method: getStringFromNative
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_chensd_jnitest_JniTest_getStringFromNative
(JNIEnv * env, jobject jobj){
return (*env)->NewStringUTF(env,"come_from_jnitest");//返回一个简单的字符串
};
#ifdef __cplusplus
}
#endif
#endif
另外再新建一个空的util.c的文件,这样android才能顺利编译so。
6、配置下NDK,可以去开发者工具集网站下载压缩包也可以直接在android studio里面下载,ctrl+shift+a,键入system settings,定位到android sdk->sdk tools 找到NDK并且下载安装!
a)打开gradle.properties文件末尾加上一句话:
android.useDeprecatedNdk=true
b)打开local.properties检查是否配置NDK路劲:
sdk.dir=D\:\\AndroidSDK\\android-sdk-windows
ndk.dir=D\:\\AndroidNDK\\android-ndk-r13b
c)配置下app module下build.gradle配置下NDK:
defaultConfig {
applicationId "com.chensd.jnitest"
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
ndk {
moduleName "JniTest" //必须与静态代码块中的相同
ldLibs "log", "z", "m"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
}
7、生成so文件,点击build->rebuild,so文件生成路径在,..\app\build\intermediates\ndk\debug\lib
接下来按照之前在MianActivity中的代码示例运行下,就成功了!
经过如上的折腾,简单的jni使用已经可以了,但是有一个问题:在main.c中我们导入.h文件会抱红,编写C代码不会联想等等的问题,为了解决这些问题,正常的可以开发NDK需要进行如下配置:
1、修改工程目录下的的build.gradle的classpath:
classpath 'com.android.tools.build:gradle-experimental:0.7.0'
2、修改app module下build.gradle文件
apply plugin: 'com.android.model.application' //这里变化了
model {
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.0"
defaultConfig.with {
applicationId = "com.chensd.ndkdeveloputil"
minSdkVersion.apiLevel = 14
targetSdkVersion.apiLevel = 23
}
tasks.withType(JavaCompile){
//指定编译JDK版本
sourceCompatibility=JavaVersion.VERSION_1_7
targetCompatibility=JavaVersion.VERSION_1_7
}
}
/* * native build settings */
android.ndk {
moduleName = "jnitest" //必须与JniTest类中的一致
// cppFlags.add("-fno-rtti")
// cppFlags.add("-fno-exceptions")
// ldLibs.addAll(["android", "log"])
// stl = "system"
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles.add(file('proguard-rules.txt'))
}
}
android.productFlavors {
// for detailed abiFilter descriptions, refer to "Supported ABIs" @
// https://developer.android.com/ndk/guides/abis.html#sa
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")
}
// To include all cpu architectures, leaves abiFilters empty
create("all")
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
}
也可以替换成如下:
apply plugin: 'com.android.model.application' //这里变化了
model {
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.0"
defaultConfig.with {
applicationId = "com.chensd.ndkdeveloputil"
minSdkVersion.apiLevel = 14
targetSdkVersion.apiLevel = 23
}
tasks.withType(JavaCompile){
//指定编译JDK版本
sourceCompatibility=JavaVersion.VERSION_1_7
targetCompatibility=JavaVersion.VERSION_1_7
}
}
/* * native build settings */
android.ndk {
moduleName = "jnitest" //必须与JniTest类中的一致
// ldLibs.addAll(["android", "log"])
abiFilters.add("armeabi")
abiFilters.add("armeabi-v7a")
abiFilters.add("x86")
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles.add(file('proguard-rules.txt'))
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
}
这样配置android.productFlavors后,rebuild后会在app->build->intermediates->transforms->mergeJniLibs下生成so库。
NDK正常编译demo:
https://github.com/chenshandong/NDKDevelopUtil