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
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题