Android Studio JNI开发(C语言版)
2.JNI开发
2.1 配置jni开发工具
* ndk (native develop kit ) 下载http://developer.android.com/tools/ndk/index.html
解压到C:\Android\android-sdk\ndk-bundle,将该目录配置到系统环境变量(测试下ndk-build出现下面提示说明配置成功)
C:\Users\kl>ndk-build
Android NDK: Could not find application project directory !
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
C:\Android\android-sdk\ndk-bundle\build\\..\build\core\build-local.mk:151: *** Android NDK: Aborting . Stop.
* ndk目录
* docs 帮助文档
* platforms 好多平台版本文件夹 选择时选择项目支持的最小版本号对应的文件夹
* 每一个版本号的文件夹中放了 不同cpu架构的资源文件
* include文件夹 jni开发中常用的 .h头文件
* lib 文件夹 google打包好的 提供给开发者使用的 .so文件
* samples google官方提供的样例工程 可以参考进行开发
* android-ndk-r9d\build\tools linux系统下的批处理文件 在交叉编译时会自动调用
* ndk-build 交叉编译的命令
* cdt eclipse的插件 高亮C代码 C的代码提示
2.2 Android Studio环境配置
* 配置local.properties
ndk.dir=C\:\\Android\\android-sdk\\ndk-bundle
sdk.dir=C\:\\Android\\android-sdk
* 配置gradle.properties
android.useDeprecatedNdk=true
* 配置app的build.gradle(指定so包的地址,可以设置了libs)
// 把 ndk 放在 defaultConfig 里面 否则报错Could not find method ndk() for arguments
ndk{
//设置支持的SO库架构
abiFilters 'armeabi' ,'x86','armeabi-v7a','x86_64','arm64-v8a', "mips"
}
// 把 sourceSets.main 放在android下
sourceSets.main {
jniLibs.srcDir 'libs'
jni.srcDirs = []//disable automatic ndk-build call
}
2.3 编写代码
创建工具类JniMethod(其中System.loadLibrary("JniMethod");中的"JniMethod"是so文件的名字去掉"lib",用来指定要用到的so文件,有的人可能getNativeString会报红线,不用管,手动去除就好)
public class JniDemoActivity extends BaseSimpleActivity implements View.OnClickListener {
private TextView tvTest;
private Button btnTest;
@Override
protected int getLayoutResID() {
return R.layout.activity_jni;
}
@Override
protected void initContentView() {
initView();
}
@Override
protected boolean onGoBack() {
return false;
}
private void initView() {
tvTest = (TextView) findViewById(R.id.tv_test);
btnTest = (Button) findViewById(R.id.btn_test);
btnTest.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_test:
tvTest.setText(getNativeString("本地方法"));
break;
}
}
static {
System.loadLibrary("JniMethod");
}
public static native String getNativeString(String s);
2.4 生成so文件
1.生成class文件
切换路径到JniDemoActivity.java所在目录下,执行命令 javac JniDemoActivity.java
E:\>cd E:\workdata\code\android\android-architecture\Arch\app\src\main\java\com\klfront\arch
E:\workdata\code\android\android-architecture\Arch\app\src\main\java\com\klfront\arch>javac JniDemoActivity.java
或者Android Studio的Build菜单栏下的Make Project命令生成.class文件(生成到这里的 执行javah有问题)
2.javah生成c头文件
点击"View->Tool Windows->Terminal",执行如下命令生成c语言头文件
javah -classpath E:\workdata\code\android\android-architecture\Arch\app\build\intermediates\classes\debug\com\klfront\arch -d E:\workdata\code\android\android-architecture\Arch\app\src\main -jni com.klfront.arch.JniDemoActivity
错误: 找不到 'com.klfront.arch.JniDemoActivity' 的类文件。
简单写一个不带包名的类文件,javac得到class文件,然后javah测试就OK。
网上查了很多,试了很多,最后确定是与包相关的问题,解决方案:
(1)就在.java源文件的目录下,javac生成.class文件
(2)直接cd到class包名所在目录的上一级,然后javah com.klfront.arch.JniMethod,如下:
E:\workdata\code\android\android-architecture\Arch\app\src\main\java>javah com.klfront.arch.JniMethod
3.实现JNI方法
main下创建文件夹jni 并把JniMethod.h导入进去,并创建JniMethod.c
JniMethod.h中的方法签名:
JNIEXPORT jstring JNICALL Java_com_klfront_arch_JniMethod_getNativeString
(JNIEnv *, jclass, jstring);
JniMethod.c按照JniMethod.h的签名实现方法:
#include <stdlib.h>
#include <stdio.h>
#include <jni.h>
#include <android/log.h>
#define LOG_TAG "System.out"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
JNIEXPORT jstring JNICALL Java_com_klfront_arch_JniMethod_getNativeString
(JNIEnv *env, jclass obj, jstring arg){
char* hellostr = "hello from c!";
char* str=(char*)(*env)->GetStringUTFChars(env,string,NULL);
return (*env)->NewStringUTF(env,hellostr);
}
4.配置Android.mk和Application.mk
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := JniMethod
LOCAL_SRC_FILES := JniMethod.c
LOCAL_LDLIBS += -llog
include $(BUILD_SHARED_LIBRARY)
Application.mk 按如下配置可生成各个CPU平台下的动态库
APP_ABI := all
5.使用ndk-build编译生成.so库
在app的build.gradle中,android节点里添加
externalNativeBuild {
ndkBuild {
path 'src/main/jni/Android.mk'
}
}
在Terminal中运行cd到main目录,执行ndk-build指令,就可以在和jni目录同级生成一个libs文件夹,里面存放相对应的平台的.so库。
E:\workdata\code\android\android-architecture\Arch>cd app/src/main
E:\workdata\code\android\android-architecture\Arch\app\src\main>ndk-build
打包运行测试,ok。