ndk开发
来源:互联网 发布:资料员用的软件 编辑:程序博客网 时间:2024/06/13 12:44
NDk的用处:1,核心代码保护,写入由于apk的Java层代码很容易被反编译,而C/C++库反汇难度较大。
NDK开发常用于-驱动开发、无线热点共享、数学运算、实时渲染的游戏、音视频处理、文件压缩、人脸识别、图片处理等。
1,首先是so文件的生产
创建Native方法
public class NdkJniUtils { static { System.loadLibrary("native-lib"); } //获取C中隐藏的AppKey public native String getStringFromNative(); //native方法}2,build->make project生产class文件
3,使用android studio自带的Terminal进入cd app/src/main 然后执行javah -d jni -classpath {sdk位置}\platforms\android-22\android.jar;..\..\build\intermediates\classes\debug {类的package.类名} 示例如下:
javah -d jni -classpath D:\android_studio_new\sdk\platforms\android-22\android.jar;..\..\build\intermediates\classes\debug com.xcm91.relation.ndkapp.NdkJniUtils
在ndk会自动生成一个.h文件
4,创建.c文件引用.h文件
#include "com_xcm91_relation_ndkapp_NdkJniUtils.h"JNIEXPORT jstring JNICALL Java_com_xcm91_relation_ndkapp_NdkJniUtils_getStringFromNative(JNIEnv *env, jclass obj){ char buf[] = "HEllO JNI"; return (*env)->NewStringUTF(env,buf);}5,build->rebuile project
在app\build\intermediates\ndk\debug\lib\中生产so文件
3.1 System.loadLibrary
java在java.lang.System包提供了两个静态方法用于加载共享库(一种含原生语言实现的可供android程序调用的库),分别是load,loadLibrary两个方法,由于我们在程序启动的时候就需要加载共享库,因此放在静态代码块中加载。这两个方法的参数是共享库名称。注意共享库为了跨平台使用,它的文件名称会包含一些前缀,而共享库文件的后缀是so。比如我们加载cppUtils共享库,其实他的全名是:libcppUtils.so。
3.2 native标签
native标签用于告诉java编辑器,它的方法是由原生语言实现的,因此不需要去实现它。native方法用分号结束。即如果你希望一个方法用原生语言实现,那么你就给它声明为native方法。
3.3 生成原生语言头文件
由于原生语言头文件需要根据字节码文件来进行分析,所以,在生成头文件之前,我们必须对项目进行build。之后打开我们项目的bin/classes的文件夹,笔者的文件夹如下图:
接着我们就要针对CppUtils.class进行分析生成头文件,在我们对编写原生语言头文件的时候,最好借助工具生成,而不是手写,这样出错的概率才会更低,否则很容易发生jni桥无法将java函数与原生方法联系起来的错误。生成头文件的方法,就是使用命令行工具。比如笔者这里就是,先进入自己项目要分析的java文件的目录下,然后生成头文件。生成头文件的命令如下:
javah -classpath bin/classes com.example.jnibolg.CppUtils
完整的操作过程看下图:
然后回到eclipse中,刷新下我们的项目,我们会发现多了一个以h结尾的文件,这个就是机器生成的头文件。
关于原声函数的实现以及祥光头文件,我们需要放在jni文件夹中,因此,我们接下来需要在项目中建立jni文件夹,并将相关文件放进去。
这样我们的原生文件就生成了。
3.4 分析头文件
接下来我们需要分析头文件的内容,有助于帮助我们了解整个实现过程。首先我们看头文件的代码:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_jnibolg_CppUtils */
#ifndef _Included_com_example_jnibolg_CppUtils
#define _Included_com_example_jnibolg_CppUtils
#ifdef __cplusplus
extern
"C"
{
#endif
/*
* Class: com_example_jnibolg_CppUtils
* Method: getStringFromCPP
* Signature: ()Ljava/lang/String;
*/
<pre
class
=
"cpp"
name=
"code"
>JNIEXPORT jstring JNICALL Java_com_example_jnibolg_CppUtils_getStringFromCPP
(JNIEnv *, jobject);</pre>
<br>
#ifdef __cplusplus}#endif#endif
<pre
class
=
"brush:java;"
></pre>
<p> </p>
首先我们可以看到jni.h头文件被包含了,这个头文件包含了jni机制为了实现从java对象到原生语言的映射的规则。因此,我们一切java调用原生函数,或者原声函数调用java,都必须通过它来实现。</jni.h>
其次我们关注这个函数声明:
JNIEXPORT jstring JNICALL Java_com_example_jnibolg_CppUtils_getStringFromCPP
(JNIEnv *, jobject);
这个函数声明说明了,它实现的是jnibolg包下的CppUtils类的getStringFromCPP方法,返回的是jstring类型,这是一个jni类型,映射到java的string类型。这里不详细解析jni类型映射,以免变得复杂,主要以实现一个例子了解整个流程为主。
JNIEnv 是一个指针,指向jni对象。通过它,就可以调用jni.h头文件包含的所有函数。即,它就是一个指向jni对象的指针。
jobject表示当前函数所实现方法所属的java对象,这里指的是CppUtils的一个实例。
有了头文件,那么接下来,我们需要用到NDK了,这就需要获取NDK的支持。
3.6 分析mk文件的内容
我们打开Android.mk文件,内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := cppUtils
LOCAL_SRC_FILES := cppUtils.cpp
include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH,这是一个用于定位源文件的宏,在Android.mk文件中,它必须是第一个变量。
include $(CLEAR_VARS),作用是清除命名冲突,因为Android构建系统在单次执行中会构建多个文件和模块,为了避免LOCAL_模式的变量名冲突,必须包含这条指令。
LOCAL_MODULE,指的是生成的共享库的名称,为了适应不同的架构,生成的共享库会含有lib前缀。
LOCAL_SRC_FILES,指的是生成共享库的源文件,多个源文件之间用空格隔开。
include $(BUILD_SHARED_LIBRARY)指令表示生成一个共享库。
关于共享库的生成,可以有更复杂的组织,比如多个共享库依赖某个静态库.....这里不详细讲解,只为了让大家理解整个流程。我们要知道的就是,基本的生成流程都是按照上面这几条指令顺序来的。
3.7实现原生代码
我们打开cppUtils.cpp文件,会发现是空的。如果包含了jni.h头文件指令,我们把他删掉,因为我们即将要实现的头文件已经包含了jni,h头文件,所以我们的源文件无需再次包含。
接着我们将头文件需要实现的函数声明复制过来,为了避免出错,强烈建议复制过来。然后修改成下面这个样子。
#include
"com_example_jniblog_CppUtils.h"
JNIEXPORT jstring JNICALL Java_com_example_jniblog_CppUtils_getStringFromCpp
(JNIEnv * env, jobject jthis)
{
return
env->NewStringUTF(
"来自C++"
);
}
3.8调用native函数
做完了上面这些,就可以函数调用了。调用和正常的java调用没有差别的。比如这里就是:
private
TextView text;
CppUtils cppUtils =
new
CppUtils();
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
text.setText(
"从C++获取字符串:"
+ cppUtils.getStringFromCpp());
}
- NDK开发-初识NDK
- NDK开发
- NDK开发
- NDK开发
- NDK开发
- NDK开发
- NDK 开发
- NDK开发
- NDK开发
- NDK开发
- NDK 开发
- ndk开发
- Ndk开发
- ndk开发
- ndk 开发
- Android NDK开发配置NDK
- NDK开发指南---NDK使用方法
- Android NDK : NDK开发概要
- 查询某段时间的数据
- AndroidStudio项目打包成jar,rebuild project生成aar
- 使用Androidstudio将本地项目上传到oschina或者Github及将项目取消与Github的关联
- 习题3
- Spring是什么
- ndk开发
- 教大家如何删除CSDN上已上传的资源
- 用Matlab实现猫变虎简单动画
- 将内网映射到外网
- ES6-面向对象实现tab切换
- linux 检测远程端口是否打开---nmap命令
- C语言字符串函数大全
- Android使用NDK编译时的常用命令
- ganglia配置文件详解