Android Stuido下NDK的简单实现
来源:互联网 发布:智能化数据分析 编辑:程序博客网 时间:2024/06/04 19:07
JNI是Sun公司定义的一套编程框架标准接口,允许Java代码和本地代码的相互调用.
我们什么情况下会使用JNI技术呢?
- 需要注重处理速度
- 直接进行硬件控制
- 对已有的本地代码进行复用
-加载动态链接库
我们通常接入别人sdk的时候都是使用的这种方法,比如接入新浪的SDK我们会得到一堆的动态链接库,我们需要将他们复制)到我们项目中调用,并将提供的jar文件添加到依赖库中
那如果我们自己来实现简单的本地方法和调用呢?
1.下载SDK Tools->NDK
在Setting->Android SDK->SDK Tools下下载NDK
2.声明本地函数
如果要在Java类中使用本地函数,那么我们需要现在Java类中声明它,声明本地函数时,需要在函数名前面添加关键字”native”关键字进行修饰,如下
package com.jju.yuxin.jnidev;/** * ============================================================================= * Copyright (c) 2016 yuxin All rights reserved. * Packname com.jju.yuxin.jnidev * Created by yuxin. * Created time 2016/10/5 0005 上午 11:10. * Version 1.0; * Describe : 本地函数的声明 * History: * ============================================================================== */public class JniAddUtils { public static native int add(int a,int b);}
我们在项目中创建了一个叫JniAddUtils 的类,并在里面声明了一个本地方法add,我们准备用它来实现两个数相加的操作.(如果在这一步出现方法找不到之类的错误,我们可以到Setting->Plugins下将Android NDK Support后面的勾去掉,重启android studio就好了)
3.编译文件并生成头文件
我们知道在C这种调用别的文件的方法都是通过引入头文件的方式.在生成头文件之前我们需要先编译java文件让其生成.class文件,编译java文件我们只需要在点击编译项目就可以了.(点击运行项目按钮旁边的Make Project)
我们会在项目下的app\build\intermediates\classes\debug的包路径下找到生成的class文件(build是项目生成的临时文件夹,编译的东都在这个目录下),我们用android studio 下的Terminal cd到这个目录并使用javah -jni 路径的方式生成头文件
之后我们会在debug的目录下看到生成的头文件,如:
com_jju_yuxin_jnidev_JniAddUtils.h
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_jju_yuxin_jnidev_JniAddUtils */#ifndef _Included_com_jju_yuxin_jnidev_JniAddUtils#define _Included_com_jju_yuxin_jnidev_JniAddUtils#ifdef __cplusplusextern "C" {#endif/* * Class: com_jju_yuxin_jnidev_JniAddUtils * Method: add * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_jju_yuxin_jnidev_JniAddUtils_add (JNIEnv *, jclass, jint, jint);#ifdef __cplusplus}#endif#endif
我们在mian下创建一个jni的文件夹,将之前的头文件剪切在这个文件夹中
4.实现本地函数
我们在 刚才创建的jni文件夹下创建一个.c文件用来实现加法运算,函数编写如下,正在编写函数时我们需要忘了将头文件引入,函数名为头文件中生成的函数名
jniadd.c
#include "com_jju_yuxin_jnidev_JniAddUtils.h"//JNIEnv *, jclass是固定参数 jint, jint为传入的两个参数JNIEXPORT jint JNICALL Java_com_jju_yuxin_jnidev_JniAddUtils_add (JNIEnv * env, jclass thiz, jint a, jint b){ jint result=a+b; return result; }
其中JNIEnv * env, jclass thiz,
这两个参数是固定的参数,因为我们的方法在java中声明为static所以传入的是jclass,如果是非静态方法,那么传入的将是jobject,有人会问jint是什么东西?我们接下来来说一下,如果你知道了可以直接跳到下一步,
在本地函数的参数和返回值类型根据等价约定映射到Java语言中的数据类型
1.基本类型的映射
2.引用类型的映射
3.引用类型的继承关系
4.ndk路径的添加与配置
一般在新版的android stuido你下载完成ndk后他都会帮你在项目的local.properties添加NDK的路径,就像SDK一样,如果没有的话记得添加上去
,就像一开始一样我们要用jni我们先需要动态链接库(.so)所以我们需要在mudule的build.gradle中配置要生成的动态链接库的名称和类型(注意添加的位置,是在defaultConfig的里面)
ndk{ moduleName "AddJniLibName"//名字自拟 abiFilters "armeabi","armeabi-v7a","x86" }
(如果后面运行成功,你会在app\build\intermediates\ndk\debug\lib\下看到三个目录下生成的对应的.so库)
5.代码中加载动态链接库
我们在最开始的JniAddUtils类中用到了本地方法,所以我们需要在那加载动态链接库
public class JniAddUtils { static { System.loadLibrary("AddJniLibName"); //加载动态链接库 } public static native int add(int a,int b);}
6.验证
我们在MainActivity中来验证下能否成功(布局就不写了,就一个TextView)
public class MainActivity extends Activity { private TextView tv_result; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv_result = (TextView) findViewById(R.id.tv_result); int addresult = JniAddUtils.add(1, 3); tv_result.setText("1+3="+addresult); }}
截图:
7.日志的输出
在android代码中能够输出log日志,那怎么在C或C++中代码中输出log日志呢?
1.配置log库
如果你用的是正式版gradle,在ndk标签中加入
ldLibs “log”
如果你用的是实验版gradle,在ndk标签中加入:
ldLibs.add(“log”)
如果你使用CMakeLists,在target_link_libraries标签中加入log
如果你使用的是MK文件,加入如下语句:
LOCAL_LDLIBS := -llog
因为我使用的是Android Studio2.2正式版,那我需要修改ndk标签为
ndk{ moduleName "AddJniLibName" abiFilters "armeabi","armeabi-v7a","x86" ldLibs "log" }
2.引入头文件
在你需要打印日志的C或C++文件中引入#include<android/log.h>
头文件.下面是我C文件修改版
#include <jni.h>#include<android/log.h>#include "com_jju_yuxin_jnidev_JniAddUtils.h"//JNIEnv *, jclass是固定参数 jint, jint为传入的两个参数JNIEXPORT jint JNICALL Java_com_jju_yuxin_jnidev_JniAddUtils_add (JNIEnv * env, jclass thiz, jint a, jint b){ jint result=a+b; //Log.i("JNIADD","result="+result); __android_log_print(ANDROID_LOG_INFO,"JNIADD","result=%d",result); return result; }
其他几种日志输出为
ANDROID_LOG_INFO –> Log.i
ANDROID_LOG_WARN –> Log.w
ANDROID_LOG_DEBUG –> Log.d
ANDROID_LOG_ERROR –> Log.e
ANDROID_LOG_FATAL –> Log.a
8.遇到的问题
1.Error:Execution failed for task ‘:app:compileDebugNdk’.
Error: NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin. For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental. Set “$USE_DEPRECATED_NDK=true” in gradle.properties to continue using the current NDK integration.
这个错误需要在项目的gradle.properties下添加android.useDeprecatedNdk=true
2. connot delete “app\build\intermediates\classes\debug”
我的解决办法是重启android studio 因为每次重启,他都会重新的编译,也就会重新生成build文件,但是我局的这方法不怎么靠谱,不知道你们的能用不
以上就是我的测试后成功之谈,不当之处还望指出.
本文参考我同学的博文实现,有不清楚的地方,可以去他那看看.
在android studio 2.1 实现简单的ndk
我的博客网站:http://huyuxin.top/欢迎大家访问,评论.
- Android Stuido下NDK的简单实现
- android stuido ndk 开发
- Android Stuido Ndk-Jni 开发(一):创建简单的JniDemo
- Android Stuido 使用cMake构建NDK项目
- Android NDK入门(实现简单的NDK程序)
- Android Stuido 实现多渠道打包
- wind7-64bite下 android stuido打不开的解决方案
- android stuido环境下获取sha1的方法
- eclipse 下android ndk开发的配置及简单功能实现
- 超简单方法搭建Eclipse下的Android NDK
- Android Stuido Ndk-Jni 开发(三):Jni基本语法
- 在android studio 2.1 实现简单的ndk
- 使用Android-studio简单实现一个NDK的例子
- Android NDK(二)最最简单的方法利用NDK实现MP3录音
- android ndk的简单应用
- android ndk 的简单使用
- Android NDK的简单例子
- android NDk开发学习一<简单实现>
- Linux进程通讯:消息队列
- 1062. Talent and Virtue (25)
- hdu5916 构造
- DTD 约束
- 自定义ListView
- Android Stuido下NDK的简单实现
- Windows线程同步机制的区别与比较及进程通信方法
- HDU 5914 Triangle【斐波那契数列】
- 图像二维离散傅里叶变换、幅度谱、相位谱
- [心得]面试题分析与整理2
- PHP代码规范
- Android多渠道打包(一):基础多渠道打包
- Java经典多线程问题--生产者与消费者
- 创建链式线性表