安卓JNI分析
安卓JNI分析
jni定义
使用jni的原因
jni实现步骤
具体实现
jni数据类型
jni定义
jni(JavaNative Interface),java本地开发接口,一般上层Android应用程序通过Java虚拟机调用底层接口,衔接底层c/c++库与Java应用程序间的接口正是jni。
使用jni的原因
效率上c++优与java
代码移植,复用c++/c的模块
java容易被反编译
jni实现步骤
java类中书写对应的native方法
使用javah创建符合jni规范的C语言头文件
编写c++/c代码
书写makefile文件
使用ndk编译成so文件
在java层载入so文件并使用里面的方法
具体实现
书写native方法
public native void CallNativcFromJava(byte[] arrray);
public native void CallNativcFromJava2(byte[] arrray);
// 测试Native访问C
public native void CallNativcFromJava3();
public native void CallNativcFromJava4();
生成对应jni方法
接口名字必须符合JNI规范
JNIEXPORT 函数返回值类型 JNICALL
Java_报名类名函数名(JNIEenv* env,jobject obj,参数列表)
{}
JNIEXPORT void JNICALL
Java_com_example_newyx_jnidemo2_MainActivity_CallNativcFromJava(JNIEnv *env, jobject instance, jbyteArray arrray_)
{
}
JNIEXPORT void JNICALL
Java_com_example_newyx_jnidemo2_MainActivity_CallNativcFromJava2(JNIEnv *env, jobject instance, jbyteArray arrray_)
{
}
JNIEXPORT void JNICALL
Java_com_example_newyx_jnidemo2_MainActivity_CallNativcFromJava3(JNIEnv *env, jobject instance)
{
}
JNIEXPORT void JNICALL
Java_com_example_newyx_jnidemo2_MainActivity_CallNativcFromJava4(JNIEnv *env, jobject instance)
{
}
书写对应代码
#include <jni.h>
#include <android/log.h>
#include <stdio.h>
#define TAG "System.out" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型
JNIEXPORT void JNICALL
Java_com_example_newyx_jnidemo2_MainActivity_CallNativcFromJava(JNIEnv *env, jobject instance,
jbyteArray arrray_)
{
char array[1024];
// 获取传递下来数组的长度
int len = (*env)->GetArrayLength(env,arrray_);
(*env)->GetByteArrayRegion(env,arrray_,0,len,array);
int i;
for(i = 0;i < len;i++)
{
array[i] += i;
LOGI(" %d",array[i]);
}
(*env)->SetByteArrayRegion(env,arrray_,0,len,array);
}
JNIEXPORT void JNICALL
Java_com_example_newyx_jnidemo2_MainActivity_CallNativcFromJava2(JNIEnv *env, jobject instance,
jbyteArray arrray_)
{
// 获取传递下来数组的长度
int len = (*env)->GetArrayLength(env,arrray_);
// 对数组进行直接操作
char* pArray = (*env)->GetByteArrayElements(env,arrray_,0);
int i;
for(i = 0;i < len;i++)
{
pArray[i] += i;
LOGI(" %d",pArray[i]);
}
// 释放内存 防止内存泄漏
(*env)->ReleaseByteArrayElements(env,arrray_,pArray,0);
}
JNIEXPORT void JNICALL
Java_com_example_newyx_jnidemo2_MainActivity_CallNativcFromJava3(JNIEnv *env, jobject instance)
{
// 获取域所属的类
jclass calzz = (*env)->GetObjectClass(env,instance);
// 定义域ID
jfieldID numberID = (*env)->GetFieldID(env,calzz,"number","I");
// 把域ID转成本地的基本数据类型
int num = (*env)->GetIntField(env,instance,numberID);
LOGI("************num = %d",num);
num += 1000;
// 获取方法ID
jmethodID showNumID = (*env)->GetMethodID(env,calzz,"showNumber","(I)V");
// 调用方法
(*env)->CallVoidMethod(env,instance,showNumID,num);
}
JNIEXPORT void JNICALL
Java_com_example_newyx_jnidemo2_MainActivity_CallNativcFromJava4(JNIEnv *env, jobject instance)
{
// 获取ID 的class
jclass clazz = (*env)->GetObjectClass(env,instance);
// 获取域ID
jfieldID numID = (*env)->GetFieldID(env,clazz,"number","I");
jfieldID strID = (*env)->GetFieldID(env,clazz,"testStr","Ljava/lang/String;");
jfieldID chID = (*env)->GetFieldID(env,clazz,"ch","C");
jfieldID arrayID = (*env)->GetFieldID(env,clazz,"mArray","[B");
// 获取整形值
int num = (*env)->GetIntField(env,instance,numID);
LOGI("num = %d",num);
// 获取字符串
jstring str = (*env)->GetObjectField(env,instance,strID);
// 把jstring转换为char *
char *p = (*env)->GetStringUTFChars(env,str,0);
LOGI("string = %s",p);
// 获取字符 (注意是2个字节)
unsigned short ch = (*env)->GetCharField(env,instance,chID);
LOGI("ch = %d" , ch);
// 获取数组
jbyteArray mArray = (*env)->GetObjectField(env,instance,arrayID);
// 获取数组长度
int len = (*env)->GetArrayLength(env,mArray);
// 把jbayteArray转换为char数组
char* pArray = (*env)->GetByteArrayElements(env,mArray,0);
int i;
for(i = 0;i < len;i++)
{
LOGI(" %d",pArray[i]);
pArray[i] += 2;
}
// 获取方法ID
jmethodID showInfoID = (*env)->GetMethodID(env,clazz,"showInfo","(ILjava/lang/String;[B)Ljava/lang/String;");
// 调用方法
(*env)->CallObjectMethod(env,instance,showInfoID,num,str,mArray);
// 释放资源
(*env)->ReleaseStringUTFChars(env,str,p);
(*env)->ReleaseByteArrayElements(env,mArray,pArray,0);
}
mk书写(此处为gradle脚本)
defaultconfig
{
ndk
{
moudleName “myjni.so”
ldLibs “LOG”
}
}
java层调用
static
{
System.loadLibrary("myjni");
}
使用方法
package com.example.newyx.jnidemo2;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity
{
private int number = 1000;
private String testStr = "fjsd";
private char ch = 'a';
private byte[] mArray= {1,2,3,4,5};
// 导入库
static
{
System.loadLibrary("myjni");
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void testArray(View v)
{
byte[] array = {3, 4, 5, 6, 7};
CallNativcFromJava(array);
for (byte i : array)
{
System.out.println(" " + i);
}
}
public void testArray2(View v)
{
byte[] array = {3, 4, 5, 6, 7};
CallNativcFromJava(array);
for (byte i : array)
{
System.out.println(" " + i);
}
}
public void testDemo1(View v)
{
System.out.println("number = " + number);
CallNativcFromJava3();
}
public void testDemo2(View v)
{
CallNativcFromJava4();
}
public void showNumber(int num)
{
System.out.println("----->num = " + num);
}
public String showInfo(int num,String str,byte[] array)
{ System.out.println("-----------------------------------------------------------");
System.out.println("num = "+ num);
System.out.println("str = " + str);
for(byte v : array)
{
System.out.println(" "+v);
}
return null;
}
// 声明本地接口
public native void CallNativcFromJava(byte[] arrray);
public native void CallNativcFromJava2(byte[] arrray);
// 测试Native访问C
public native void CallNativcFromJava3();
public native void CallNativcFromJava4();
}
jni数据类型
基础数据类型
引用数据类型