标签:
NDK开发环境的搭建
JNI_HelloWorld
步骤
实现
public native String hello();
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= hello-jni//要生成的动态库
LOCAL_SRC_FILES := hello-jni.c//源文件
include $(BUILD_SHARED_LIBRARY)
修改LOCAL_MODULE和LOCAL_SRC_FILES然后在 ndk-build 编译
[armeabi] Compile thumb : helloJNI <= hello.c
[armeabi] SharedLibrary : libhelloJNI.so
[armeabi] Install: libhelloJNI.so => libs/armeabi/libhelloJNI.so
生成动态库
jstring Java_com_example_jnihello_MainActivity_hello_from_jni(JNIEnv* env,jobject jobj)
ndk-build编译也不会报错,但是运行的时候会崩溃
No implementation found for native Lcom/example/jnihello/MainActivity;.hello_from_jni:()Ljava/lang/String;
在c代码中将Java的全类名中的.变为_ ,原来有下划线的地方需要在后面加个1,改成这样的:
jstring Java_com_example_jnihello_MainActivity_hello_1from_1jni(JNIEnv* env,jobject jobj)
但是如果native方法中有很多下划线和数字的话,这样修改起来就会显得很麻烦,需要一个便捷的方法来实现–javah
使用方法:javah+空格+java全类名
public native String hello_1_1_23_from_jni();
在src目录下启动cmd,输入Javah com.example.jnihello.MainActivity
就行了。将生成的.h文件移动到jni目录下。#include<jni.h>
修改为#include "com_example_jnihello_MainActivity.h"
并把c代码中的方法名修改为com_example_jnihello_MainActivity.h
中的方法名For example, to support hardware FPU instructions on ARMv7 based devices, use:
APP_ABI := armeabi-v7a
Or to support ARMv8 AArch64 instruction set, use:
APP_ABI := arm64-v8a
Or to support the IA-32 instruction set, use:
APP_ABI := x86
Or to support the Intel64 instruction set (r1), use:
APP_ABI := x86_64
Or to support the MIPS32 instruction set, use:
APP_ABI := mips
Or to support the MIPS64 instruction set (r6), use:
APP_ABI := mips64
Or to support all at the same time, use:
APP_ABI := armeabi armeabi-v7a x86 mips arm64-v8a x86_64 mips64
Or even better, since NDK r7, you can also use the special value ‘all’ which means “all ABIs supported by this NDK release”:
APP_ABI := all
#$:调用系统的工具链函数,当前的作用:调用当前目录
LOCAL_PATH := $(call my-dir)
#清除LOCAL环境变量并且初始化工具链工具,但是不会清除LOCAL_PATH
include $(CLEAR_VARS)
#要生成的.so文件名称,前面省略lib可以不写,但是后缀不需要写
LOCAL_MODULE := hello-jni
#指向源文件,多个源文件用空格连接
LOCAL_SRC_FILES := hello-jni.c
#编译成动态链接库BUILD_SHARED_LIBRARY,后缀.so ,文件比较小
#BUILD_STATIC_LIBRARY编译成静态链接库,后缀.a,文件比较大
include $(BUILD_SHARED_LIBRARY)
一开始我的Eclipse没有NDK这个选项,百度之后解决。
新建Android Progect
#include<android/log.h>
并使用宏定义#define LOGD(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
LOCAL_LDLIBS += -llog
在C代码中直接使用定义好的LOGD,并将要打印的信息传入即可。
将Java中的String类型转换成C中的char*类型
char* jstringTostring(JNIEnv* env, jstring jstr) {
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes",
"(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0) {
rtn = (char*) malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
JNI中对数组的操作
int size = (*env)->GetArrayLength(env, jarray);
jint* arrayElement = (*env)->GetIntArrayElements(env, jarray, JNI_FALSE);
for (i = 0; i < size;i++){
jint s = *(arrayElement + i);
}
Java反射机制主要提供的功能:
Java Reflection API简介
反射步骤:
MainActivity.java
package com.example.ccalljavademo;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
private JNI jni;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
jni = new JNI();
}
public void helloFromJava(View v) {
jni.cMethods_call_helloFromJava();
}
public void add(View v) {
jni.cMethods_call_add();
}
public void printString(View v) {
jni.cMethods_call_printString("sad");
}
public void callStatic(View cv) {
jni.cMethods_call_sayHello();
}
}
package com.example.ccalljavademo;
public class JNI {
{
System.loadLibrary("CCallJavaDemo");
}
/**
* C调用Java空方法
*/
public void helloFromJJava() {
System.out.println("Hello Form Java");
}
/**
* C调用Java两个int参数方法
* @param x
* @param y
* @return
*/
public int add(int x, int y) {
int result = x + y;
System.out.println("被c调用" + result);
return result;
}
/**
* C调用Java参数为String方法
* @param s
*/
public void printString(String s) {
System.out.println(s);
}
/**
* 静态方法
*/
public static void sayHello (){
System.out.println("Hello");
}
/**
* 让C语言调用JNI.java中的 helloFromJava
*/
public native void cMethods_call_helloFromJava();
/**
* 调用JNI.java中的add方法
*/
public native void cMethods_call_add();
/**
* 调用JNI.java中的printString方法
* @param s
*/
public native void cMethods_call_printString(String s);
/**
* 调用静态方法
*/
public native void cMethods_call_sayHello();
}
#include "com_example_ccalljavademo_JNI.h"
#include <stdio.h>
#include<Stdlib.h>
/**
* 让c语言调用Java中的HelloFromJava
*/
JNIEXPORT void JNICALL Java_com_example_ccalljavademo_JNI_cMethods_1call_1helloFromJava(
JNIEnv *env, jobject jobj) {
// 1.得到字节码文件
// jclass (*FindClass)(JNIEnv*, const char*);
// 第二个参数 是全类名 com.example.ccalljavademo.JNI 将.换成/
jclass jclazz = (*env)->FindClass(env, "com/example/ccalljavademo/JNI");
// 2.得到字节码对应的方法
// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
// 第三个参数:方法名
// 第四个参数:方法签名
jmethodID jmethodid = (*env)->GetMethodID(env, jclazz, "helloFromJJava",
"()V");
// 3.得到类的实例
// jobject (*AllocObject)(JNIEnv*, jclass);
jobject obj = (*env)->AllocObject(env, jclazz);
// 4.执行方法
// void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env, obj, jmethodid); //成功调用JNI.java中的helloFromJava方法
}
/***
*C调用Java中带有两个int参数的方法
*
*/JNIEXPORT void JNICALL Java_com_example_ccalljavademo_JNI_cMethods_1call_1add(
JNIEnv *env, jobject jobj) {
// 1.得到字节码文件
// jclass (*FindClass)(JNIEnv*, const char*);
// 第二个参数 是全类名 com.example.ccalljavademo.JNI 将.换成/
jclass jclazz = (*env)->FindClass(env, "com/example/ccalljavademo/JNI");
// 2.得到字节码对应的方法
// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
// 第三个参数:方法名
// 第四个参数:方法签名
jmethodID jmethodid = (*env)->GetMethodID(env, jclazz, "add", "(II)I");
// 3.得到类的实例
// jobject (*AllocObject)(JNIEnv*, jclass);
jobject obj = (*env)->AllocObject(env, jclazz);
// 4.执行方法
// jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallIntMethod(env, obj, jmethodid, 99, 12); //成功调用JNI.java中的add方法
}
JNIEXPORT void JNICALL Java_com_example_ccalljavademo_JNI_cMethods_1call_1printString(
JNIEnv *env, jobject jobj, jstring jstr) {
// 1.得到字节码文件
// jclass (*FindClass)(JNIEnv*, const char*);
// 第二个参数 是全类名 com.example.ccalljavademo.JNI 将.换成/
jclass jclazz = (*env)->FindClass(env, "com/example/ccalljavademo/JNI");
// 2.得到字节码对应的方法
// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
// 第三个参数:方法名
// 第四个参数:方法签名
jmethodID jmethodid = (*env)->GetMethodID(env, jclazz, "printString",
"(Ljava/lang/String;)V");
// 3.得到类的实例
// jobject (*AllocObject)(JNIEnv*, jclass);
jobject obj = (*env)->AllocObject(env, jclazz);
// 4.执行方法
// void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env, obj, jmethodid, jstr); //成功调用JNI.java中的add方法
}
JNIEXPORT void JNICALL Java_com_example_ccalljavademo_JNI_cMethods_1call_1sayHello(
JNIEnv *env, jobject jobj) {
// 1.得到字节码文件
// jclass (*FindClass)(JNIEnv*, const char*);
// 第二个参数 是全类名 com.example.ccalljavademo.JNI 将.换成/
jclass jclazz = (*env)->FindClass(env, "com/example/ccalljavademo/JNI");
// 2.得到字节码对应的方法
// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
// 第三个参数:方法名
// 第四个参数:方法签名
jmethodID jmethodid = (*env)->GetStaticMethodID(env, jclazz, "sayHello",
"()V");
// 3.得到类的实例
// jobject (*AllocObject)(JNIEnv*, jclass);
// jobject obj = (*env)->AllocObject(env, jclazz);
// 4.执行方法
// void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);
(*env)->CallStaticVoidMethod(env, jclazz, jmethodid);
}
标签:
原文地址:http://blog.csdn.net/u013476556/article/details/51189095