您的位置:首页 > 移动开发 > Android开发

Android Jni之Helloworld

2016-05-30 23:52 766 查看

一、搭建NDK环境

NDK可以自己下载好,然后布置一下环境变量。不过我这里有个更加简便的方法。在Android studio2.2及更高版本中可以像插件那样安装NDK了。

设置流程如下:

点开File->Setting,弹出Setting窗口。



如图所示,在setting -> Appearance&Behavior -> System Setting -> Android SDK -> SDK Tools(视图右边),选择CMake、LLDB、NDK这三个下载。然后一边静静地等它下载安装。

如果你是建好工程再下载NDK,你还要在File ->Project Structure里面设置一下NDK地址。这里直接按“Select default NDK”就可以了。



它会自己生成路径:D:\Android\Sdk\ndk-bundle(这是我电脑NDK的地址)

并且会在local.properties里自动生成一行ndk目录地址。



在gradle.properties里面添加

android.useDeprecatedNdk=true




至此,你可以愉快地编写Jni了。

二、Jni编写

1)编写Java接口

在项目里新建一个Java类。

public class Jni {

public native String say(String str);

}


注意这里用到的是“native”修饰。

2)编写c/c++接口及代码

Android studio有个Terminal工具,对应Windows系统的cmd窗口。

在cmd里面cd进入项目的Java文件夹里面,因为Java文件夹里面的是对应包名

package com.example.jnitest;


输入javah -jni com.example.jnitest.Hello然后生成.h文件。



项目目录下就多了一个com_example_jnitest_Jni.h文件。



这个就是c/c++的头文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_jnitest_Jni */

#ifndef _Included_com_example_jnitest_Jni
#define _Included_com_example_jnitest_Jni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:     com_example_jnitest_Jni
* Method:    say
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_jnitest_Jni_say
(JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif


新建JNI文件夹



然后把com_example_jnitest_Jni.h文件拉进去



在jni目录里新建c/c++源码文件

#include <stdio.h>
#include <stdlib.h>
#define TAG "JNI" //自定义的变量
#include <android/log.h>
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, TAG ,__VA_ARGS__)
#include "com_example_jnitest_Jni.h"
JNIEXPORT jstring JNICALL Java_com_example_jnitest_Jni_say
(JNIEnv *env, jobject, jstring str) {
LOGD("This is JNI");
return str;
}


上面的c/c++源码
#include "com_example_jnitest_Jni.h"
就是引入刚刚生成的.h文件。Java_com_example_jnitest_Jni_say是对应Java类里的say方法。这个名字是要固定的格式写的,文件目录-文件名-方法名,如果你取其他名称也需准守起名规则。

总体的目录结构如下:



3)生成so文件

打开app Module的build.gradle文件,在defaultConfig节点加入NDK的配置信息。

ndk {
moduleName "HelloWorld"     //so文件名
ldLibs "log", "z", "m"      //添加系统库文件
abiFilters "armeabi", "armeabi-v7a", "x86"   //d对应芯片结构
}


moduleName是你的so文件名,lbLibs附加系统库文件,abIlity添加你要生成的库对应的芯片架构。

这里添加了log,在这个项目代码对应是

#define TAG "JNI" //自定义的变量
#include <android/log.h>
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, TAG ,__VA_ARGS__)


LOGD("This is JNI");


这个是在c/c++源码里添加log日记。



布置好了就可以编译了。



在工具来点击编译按钮,或者在Build -> Make Project来执行。

编译好了后,你会在你的项目module里面的build -> intermediates ->ndk ->发现对应的so文件。

注意你的项目所在的目录文件夹名字不能有空格,否则编译不通过了。



上面的配置在运行时候,每次都会编译一下的,你程序有对应的调用代码会调用到这个文件的,如果你不想每次都编译一下so库,你也可以把对应的so库拿出来用。

把刚刚生成的so文件连同文件夹复制到项目的libs文件夹里面,当然了,你也可以放到项目的其他位置。

注意要连同上面的“armeabli”,“armeabi-v7a”,”x86”文件夹一起复制,系统调用时候会根据不同的芯片架构来调用不同的so库。



然后在app的build.gradle指引一下配置目录,并设置不自动ndk编译。

android {
......
sourceSets.main {
jniLibs.srcDir 'libs'//放so文件的目录
jni.srcDirs = [] //disable automatic ndk-build call
}
}


好了上面几步你已经生成对应的so库了,下面就是调用。

4)调用so库

先需要加载动态库,动态库的名称是编译时候在build.gradle设置的名称。

然后像普通的方法一样调用即可。

public class MainActivity extends AppCompatActivity {

static {        // 加载动态库
System.loadLibrary("TestJNI");
}

TextView tv;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.text_hello);
Jni jni = new Jni();
tv.setText(jni.say("Hello world. This message is from Jni."));

}
}






源码下载地址:https://github.com/loongX/AndroidJniDemo/tree/master
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息