博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NDK开发 - JNI开发流程
阅读量:6842 次
发布时间:2019-06-26

本文共 4845 字,大约阅读时间需要 16 分钟。

JNI是Java和C/C++建立连接的桥梁,开发者可以将关键的加密算法通过用C/C++实现以提高被反编译的难度,保护APK的数据安全。又或者通过C/C++获取一些手机数据,以此来绕过类似Xposed这类作弊工具,提高数据的准确性。

源码地址:

传送门:

在上一篇搭建的环境下,就可以进行NDK的开发。NDK开发主要分为一下几个步骤:

  • java层入口代码编写

  • java代码编译

  • C/C++头文件生成

  • C/C++代码编写

  • 运行编译SO

java层代码编写

  新建一个NativeMethod的Class,java层代码主要负责两件事:

Load native library(SO文件)

  Load操作很简单,其中包名为build.gradle中定义的ndk名,代码如下:

android.ndk {        moduleName = "native"  //设置库(so)文件名称//        CFlags.add("-DCUSTOM_DEFINE")        ldLibs.addAll(["log", "android", "EGL", "GLESv1_CM"])//        ldFlags.add("-L/custom/lib/path")        stl = "stlport_static"    }
static{        System.loadLibrary("native");    }

定义接口名

  JNI的接口名以native字符修饰,并且不需要实现。

package com.example.gnaix.ndk;/** * 名称: NativeMethod * 描述: * * @author xiangqing.xue * @date 16/3/10 */public class NativeMethod {    static{        System.loadLibrary("native");    }    /**     * 基础类型     * @param i     * @return     */    public static native int getInt(int i);    /**     * string     * @param str     * @return     */    public static native String getString(String str);    /**     * array     * @param data     * @return     */    public static native byte[] getByteArray(Byte[] data);    /**     * 调用java对象     * @param name     * @param age     */    public static native void invokeJobject(String name, int age);    /**     * 调用java静态方法     */    public static native void invokeStaticFieldAndMethod();    /**     * 获取结构体     * @return     */    public static native Person[] getPersons();}

  到这里java层的活就干完了。

java代码编译

  在生成C/C++的头文件前需要把上面写的class编译成.class文件。Android Studio中编译很简单点一下右上角的<img width=40px height=35px src=" style="display:inline-block"/>按钮就可以了。生成的class文件在app/build/intermediates/calsses/all/debug/xx.xx.xx/xx.class

C/C++头文件生成

  JNI开发对C/C++的头文件有命名的格式要求,所以我们可以使用jdk提供的javah命令生成规定的C/C++头文件。为了方便可以先切换到app/src/main目录下。

cd app/src/main

  再执行javah命令。(根据实际替换需要生成的class文件)

javah -d jni -classpath ../../build/intermediates/classes/all/debug com.example.gnaix.ndk.NativeMethod

参数说明:

  • classpath:类搜索路径

  • d:将生成的头文件放到当前的 jni 目录下

  • o: 指定生成的头文件名称,默认以类全路径名生成(包名+类名.h)

      执行完会发现在main目录下生成了一个jni目录,里面有个com_example_gnaix_ndk_NativeMethod.h的头文件。里面有生成好的头文件。

/* DO NOT EDIT THIS FILE - it is machine generated */#include 
/* Header for class com_example_gnaix_ndk_NativeMethod */#ifndef _Included_com_example_gnaix_ndk_NativeMethod#define _Included_com_example_gnaix_ndk_NativeMethod#ifdef __cplusplusextern "C" {#endif/* * Class: com_example_gnaix_ndk_NativeMethod * Method: getInt * Signature: (I)I */JNIEXPORT jint JNICALL Java_com_example_gnaix_ndk_NativeMethod_getInt (JNIEnv *, jclass, jint);/* * Class: com_example_gnaix_ndk_NativeMethod * Method: getString * Signature: (Ljava/lang/String;)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_example_gnaix_ndk_NativeMethod_getString (JNIEnv *, jclass, jstring);/* * Class: com_example_gnaix_ndk_NativeMethod * Method: getByteArray * Signature: ([Ljava/lang/Byte;)[B */JNIEXPORT jbyteArray JNICALL Java_com_example_gnaix_ndk_NativeMethod_getByteArray (JNIEnv *, jclass, jobjectArray);/* * Class: com_example_gnaix_ndk_NativeMethod * Method: invokeJobject * Signature: (Ljava/lang/String;I)V */JNIEXPORT void JNICALL Java_com_example_gnaix_ndk_NativeMethod_invokeJobject (JNIEnv *, jclass, jstring, jint);/* * Class: com_example_gnaix_ndk_NativeMethod * Method: invokeStaticFieldAndMethod * Signature: ()V */JNIEXPORT void JNICALL Java_com_example_gnaix_ndk_NativeMethod_invokeStaticFieldAndMethod (JNIEnv *, jclass);/* * Class: com_example_gnaix_ndk_NativeMethod * Method: getPersons * Signature: ()[Lcom/example/gnaix/ndk/Person; */JNIEXPORT jobjectArray JNICALL Java_com_example_gnaix_ndk_NativeMethod_getPersons (JNIEnv *, jclass);#ifdef __cplusplus}#endif#endif

C/C++代码编写

  生成头文件后就可以写具体的C++的实现代码,这里只写了一小段实现代码,具体的调用开发细节下一篇再说。 实现了getInt方法,获取了android的serialno,并用log打印出来。

//// Created by 薛祥清 on 16/3/10.//#include "com_example_gnaix_ndk_NativeMethod.h"#include 
#include
using namespace std;#define ENABLE_DEBUG 1#if ENABLE_DEBUG#define TAG "NDK_NATIVE"#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG,TAG, fmt, ##args)#define DEBUG_PRINT(format, args...) \ LOGD(format, ##args)#else#define DEBUG_PRINT(format, args...)#endifJNIEXPORT jint JNICALL Java_com_example_gnaix_ndk_NativeMethod_getInt (JNIEnv *env, jclass object, jint num){ int len; char buf[1024]; __system_property_get("ro.serialno", buf); LOGD("name : %s", buf); return num;}

运行编译SO

  经过上面的步骤,已经可以编译了,在NDK开发中除了自己apk需要,更多时候是作为第三方包提供给客户使用。Android Studio也为我们打包好了,可以在module目录下找到。

PS:

  • 这里需要注意debug模式编译会产生gdb.steup gdbserver这两个是gdb调试工具,在正式发布必须要用release模式编译。

  • 旧版本android-ndk-r9d只能编译armeabi armeabi-v7a mips x86四种cpu架构的,现在大多数手机已经是64位架构了,旧版本已经不能支持所有手机了。所以在android-ndk-r10e中增加了arm64-v8a mips64 x86_64三种架构。

  • 目前最新的NDK版本为android-ndk-r11b

转载地址:http://tqdul.baihongyu.com/

你可能感兴趣的文章
关于node 符号链接符号过多的问题
查看>>
GBin1分享的8个图片360度旋转展示的jQuery插件
查看>>
分享11个超棒的移动应用(mobile apps)开发解决方案
查看>>
【Spring】依赖注入三种方式
查看>>
【安全牛学习笔记】 本地提权
查看>>
VS2017 创建NET Core 1.1 Web项目,发布后找不到引用的js文件
查看>>
Linux_Mail_Server
查看>>
网络相关排查总结
查看>>
C++错误收集(2)
查看>>
博客园的老虞要搬家罗
查看>>
Data Pump需要用到steam pool
查看>>
异步7月上市新书,送出一本你爱的
查看>>
如何查看、管理npm模块--react-native为例
查看>>
归档及压缩
查看>>
Redis基础及与spring的整合总结
查看>>
小型公司局域网故障排查(思科)
查看>>
搭建Mysql数据库
查看>>
构建Squid传统代理及透明代理
查看>>
Ejecta (HTML5 Canvas加速引擎)
查看>>
数据备份与恢复
查看>>