Android ndk开发

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

1、准备

    做NDK开发是非常要注意开发环境和开发版本的(个人认为)。我使用的是Eclipse (Luna 4.4.0),NDK版本r10,应该是在<=r6版本的NDK还需要安装cygwin(这这里就不讨论,网上大把资料),附上NDK的下载链接方便不能翻墙的朋友,32位 ,64位,网站不能访问,但是直接用下载链接是可以下载到的。

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

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

       2、配置builder环境在需要进行ndk开发的项目上右键-properties-builder-new - program 在出现的弹窗中做以下配置

        

wKioL1Uva7bxkgyqAAHHkSQdv6o361.jpg

wKiom1UvamKgeEteAAE299U2L3w010.jpg

wKioL1Uva7eRmrMdAAIIeisqxW0452.jpg

    3、右键项目工程Android tools - Add Native Support  

wKioL1UvbF_Cvl6KAAAst-L9hxw144.jpg

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


2、Java调用C++中的方法。

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

在Activity类A中:

1
2
3
4
5
6
7
8
9
10
11
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中

1
2
3
4
5
6
7
8
9
10
11
#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;
}

运行工程即可看到效果。

3、C++中调用Java方法

在ClassB中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#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);
     }
}

4、在自己的 so文件中调用第三方的so文件

这种情况一般是因为第三方的C/C++中的方法不是按照JNI的规范来写,这时就需要进行重新包装,并使用,当然前提是有了第三方的说明文档。

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

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

1
2
3
4
5
6
7
8
LOCAL_PATH := $(call my-dir)
 
include $(CLEAR_VARS)
 
LOCAL_MODULE    := libthird
LOCAL_SRC_FILES := libthird.so
 
include $(PREBUILT_SHARED_LIBRARY)

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

1
2
3
4
5
6
7
8
9
10
11
12
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++文件中有这样一个方法

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

 在自己的C/C++文件中调用第三方的方法

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值