AndroidStudio2.2.3 JNI与NDK开发之一:生成可调用.so库
网友前辈总结的一种方法,直接用Android Studio中ndk与CMake实现,见博主文章AndroidStudio2.2开发NDK的正确姿势
本文选用的是用ndk和.mk文件实现编译生成.so。首先需要确保电脑中配置了ndk环境变量,这里不赘述,需要的网友可以自己百度,比较简单。
本文选用ndk版本为r9d(AS配置最新为r13b),使用方式基本没有太大的差别。开始进入正文:
1、新建app项目为JniDemo
(1)新建类JniUtil,两个jni层的测试接口getJniString()与getJniAdd(int a,int b);
public class JniUtil {
static {
System.loadLibrary("JniUtil");
}
public static native String getJniString();
public static native int getJniAdd(int a, int b);
}
(2)新建jni文件夹,app->new->Folder->JNI Folder, 如图
点击之后弹出框选择
点击finish之后,项目目录下生成jni文件夹,如图:
jni文件夹新建Android.mk文件,用于ndk-build命令时执行编译出.so库,Android.mk内容如下:
# Copyright (C) 2009 The Android Open Source Project
#
# 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.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := JniUtil
LOCAL_SRC_FILES := jniUtil.c
include $(BUILD_SHARED_LIBRARY)
接下来,在AS界面的Terminal窗口下执行 cd app\src\main\java,定位到java文件夹,回车,再执行javah -jni com.example.jnidemo.JniUtil,(这里要注意的是包名com.example.jnidemo一定要完整正确)生成java文件中native方法相应的jni层c代码接口。如图:
新生成的.h文件中,拷贝出两个方法,复制到jni文件夹中新建的jniUtil.c中,如下:
#include
/*
* Class: com_example_jnidemo_JniUtil
* Method: getJniString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_jnidemo_JniUtil_getJniString(JNIEnv *env, jclass cls){
char *str = "this is from c file in jni.";
return (*env)->NewStringUTF(env,str);
}
/*
* Class: com_example_jnidemo_JniUtil
* Method: getJniAdd
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_example_jnidemo_JniUtil_getJniAdd(JNIEnv *env, jclass cls, jint a, jint b){
return a+b;
}
具体实现JniUtil.java中getJniString和getJniAdd方法。
2编译.so库
编译.so库有两种方法:
(1)ndk-build命令。(说在前面在windows的cmd命令中执行也是可以的,具体和下面步骤一致)
AS的Terminal执行cd app\src\main\jni\ 回车,再执行ndk-build命令(ndk-build主要根据Android.mk文件执行)。
编译出libJniUtil.so。文件生成到app\src\main\libs中
按项目中引用.so库的方法,将生成的.so拷贝到jniLibs文件中,删除无用的文件夹和文件,运行项目测试。
(2)配置build.gradle。
如果嫌命令输入太复杂,也可以配置项目的build.gradle文件,android中增加
sourceSets { main { jni.srcDirs = ['src/main/jni', 'src/main/jni/'] } } externalNativeBuild { ndkBuild { path file("src\\main\\jni\\Android.mk") } }前者告知执行的jni编译.c的文件夹,后者告知ndk-buid编译所需的Android.mk
完整的build.gradle为
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.example.jnidemo"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main {
jni.srcDirs = ['src/main/jni', 'src/main/jni/']
}
}
externalNativeBuild {
ndkBuild {
path file("src\\main\\jni\\Android.mk")
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.1.0'
testCompile 'junit:junit:4.12'
}
编译项目,在app\build\intermediates\ndkBuild文件下生成了.so库。
运行demo。
3总结
对比两种方法,第一种在eclipse中使用多,在Android Studio中推荐使用第二种。
增加:
新建Application.mk文件,放在jni文件夹下,设置编译出哪几个版本的.so库。如下:
APP_ABI := armeabi armeabi-v7a arm64-v8a x86 x86_64
APP_PLATFORM := android-14