Android ndk开发

前言:我对C/C++是没有任何基础的,虽然大学中学了一个学期的C可是都算还给老师了。这篇文章是我作一个NDK项目积累下来的知识,能够说是一篇小白上手文章,因此高手请自行绕路。java

一、准备android

    作NDK开发是很是要注意开发环境和开发版本的(我的认为)。我使用的是Eclipse (Luna 4.4.0),NDK版本r10,应该是在<=r6版本的NDK还须要安装cygwin(这这里就不讨论,网上大把资料),附上NDK的下载连接方便不能×××的朋友,32位 ,64位,网站不能访问,可是直接用下载连接是能够下载到的。编程

    安装好NDK后,就须要在Eclipse上进行配置了。
windows

      一、windows-preferences-android-ndk-ndklocation  选择ndk的安装目录
ide

       二、配置builder环境在须要进行ndk开发的项目上右键-properties-builder-new - program 在出现的弹窗中作如下配置
学习

        

wKioL1Uva7bxkgyqAAHHkSQdv6o361.jpg

wKiom1UvamKgeEteAAE299U2L3w010.jpg

wKioL1Uva7eRmrMdAAIIeisqxW0452.jpg

    三、右键项目工程Android tools - Add Native Support  
测试

wKioL1UvbF_Cvl6KAAAst-L9hxw144.jpg

出现jni目录以及Android.mk,xx.cpp就说明添加成功了。就能够进行NDK开发了。网站


二、Java调用C++中的方法。ui

例如:获取从C++文件中获取字符串并打印google

在Activity类A中:

static{
    System.loadLibrary("xx");//xx是Android.mk文件中LOCAL_MODULE 的字段
}
//必须和ndk中的方法名同样
public native String getString();

//onclick方法
public void click(View v){
    String str = getString();
    System.out.println("调用JNI中的方法:"+str);
}

在ndk.cpp中

#include <jni.h>
#include<string.h>
/**
* extern "C" 是必须加的,经测试不加的话方法调用不成功,也没找到答案,有知道为何的请* 告知,方法名称必须按照JNI的规范来Java_包名_类名_方法名,都必须以'_'隔开。
*/
extern "C" jstring Java_com_test_ndk_A_getString(JNIEnv* env,jobject thiz){
    jstring str ;
    //在C中的是以(*env)->调用的,网上大部分的博客文档也是这种状况。
    str = env->newStringUTF("hello world");//不能使用中文,否则会报错。
    return str;
}

运行工程便可看到效果。

三、C++中调用Java方法

在ClassB中

static{
    System.loadLibrary("ndk");
}
public native void loadJavaMethod();

public void f1(){
    String str ;
    str = "hello world from java";
    System.out.println(str);
}

public String f2(){
    String str ;
    str = "f2: hello world from java";
    System.out.println(str);
    return str;
}

public void f3(String str,int i){
    System.out.println("f3 内容为:"+str+",数字为:"+i);
}

在ndk.cpp中

#include <jni.h>
#include<string.h>
extern "C" void Java_com_test_ndk_B_loadJavaMethod(JNIEnv *env,jobject thiz){

    //调用无参无返回值的方法
    jclass cls = env->GetObjectClass(thiz);
    //GetMethodID("jclass对象","方法名","方法参数")
    jmethodID mID = env->GetMethodID(cls,"f1","()V");
    if(mID != NULL){
	 env->CallVoidMethod(thiz,mID);
    }
    //调用有参无返回值得方法
     //参数类型除了基本数据类型外,其余的都须要按照这样的格式
     //L包名/类名;  包名用/分割,必须以;结束
     //详情请参考这篇文章     
     jclass cls = env->GetObjectClass(thiz);
    jmethodID mID = env->GetMethodID(cls,"f3","(Ljava/lang/String;I)V");
    jstring content = env->NewStringUTF("hehe");
    jint i = 10;
    if(mID != NULL){
	 env->CallVoidMethod(thiz,mID,content,i);
    }
    //调用有返回值无参的方法
    jclass cls = env->GetObjectClass(thiz);
    jmethodID mID = env->GetMethodID(cls,"f2","()Ljava/lang/String;");
     if(mID != NULL){
	 env->CallObjectMethod(thiz,mID);
    }
    //调用其余类中的方法假设有一个Student类,若是要使用Student类中的内部类A,格式为
    //com/test/ndk/Student$A
    jclass stu = env->FindClass("com/test/ndk/Student");
    //实例化无参构造方法
    jobject stuObj = env->NewObject(stu,env->GetMethodID(stu,"<init>","()V"));
    jmethodID getNameId = env->GetMethodID(stu,"getName","()V");
    if(getNameId !=NULL){
	env->CallVoidMethod(stuObj,getNameId);
    }
}

四、在本身的 so文件中调用第三方的so文件

这种状况通常是由于第三方的C/C++中的方法不是按照JNI的规范来写,这时就须要进行从新包装,并使用,固然前提是有了第三方的说明文档。

将第三方的so文件配置到预编译环境

在工程的jni文件下新建prebuilt文件夹(名称随意)将第三方的so文件放到里面例如libthird.so,而后在这个文件夹下新建Androdid.mk文件,文件内容为

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := libthird
LOCAL_SRC_FILES := libthird.so

include $(PREBUILT_SHARED_LIBRARY)

打开jni下的Android.mk文件,加入如下字段

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := ndk
LOCAL_SRC_FILES := ndk.cpp

#名称和第三方mk中LOCAL_MODULE定义的名称同样
LOCAL_SHARED_LIBRARIES := libthird

include $(BUILD_SHARED_LIBRARY)

#添加路径
include $(LOCAL_PATH)/prebuilt/Android.mk

 配置完成后,在工程的libs\armeabi目录下能够看到第三方的so文件,注意不能直接将第三方的so文件放到这个目录下。不然在builde的时候会删除。

假设在第三方的C/C++文件中有这样一个方法

//extern "C"在第三方的包中的方法也必须添加,测试时,若是不添加方法调用不成功,但这个是不能限//制到第三方的,有待解决
extern "C" int f1(){
	return 101;
}

 在本身的C/C++文件中调用第三方的方法

  

#include <jni.h>
#include <dlfcn.h>
#include <fcntl.h>
void *filehandle = NULL;
jstring (*f1)() =NULL;
extern "C" jint Java_com_test_ndk_classA_f1(JNIEnv * env,jobject thiz){
    jint i ;
    filehandle = dlopen("/data/data/com.fly.ndk2/lib/libndk.so", RTLD_LAZY);
    if(filehandle){
	f1 = (int(*)())dlsym(filehandle,"f1");
    }
    if(f1){
        i = f1();
        dlclose(filehandle);
	filehandle = NULL;
    }
    return i;
}

以上内容除了没有涉及到真正的C/C++编程外,JNI开发的一些知识点都涉及到了,仅属入门的一些知识,在彻底不了解C/C++编程的状况下耗费了2天时间才积累了以上知识。若是还须要更深刻的学习就须要学习C/C++的语法知识以及编译。

以上的代码以及操做不必定在其余的环境中有效,谨记。

相关文章
相关标签/搜索