当前位置: 网学 > 编程文档 > Android > 正文

Android and C

来源:Http://myeducs.cn 联系QQ:点击这里给我发消息 作者: myeducs.cn 发布时间: 13/03/17

【网学网提醒】:网学会员为大家收集整理了Android and C提供大家参考,希望对大家有所帮助!


    编译环境:windows764bit+NDKr5+jdk6测试环境:htcG6因为工作需要,需要在C++代码下调用Android代码和Android代码下调用C++代码,故把实现方法记录下来。我尽量把步骤和应该注意的地方都提及,文笔不好,且代码风格皆为C++风格,请各位看官原谅。在本文章里,需要JDK,AndroidNDKr5,cygwin参与编译。简单起见,我用新的例子来说明这个过程。主要流程的说明如下(红色函数为Android代码,蓝色函数为C++代码):1.点击Button,Button响应函数里调用setName(String_strName)把EditText里的字符串传到C++代码在setName()中去。2·在C++的voidsetName()中,接收String,通过showNameInAndroidJNI()反向调用Android的voidshowNameInAndroid(String_strName),弹出对话框,显示String。★★★★★★Android端★★★★★★★★★以下为本程序的主界面:
    Main.xml界面和代码
     ////////////////////////////////////////////
    
    ////////////////////////////////////////////===========Android调用C++===============这个Android程序只有一个继承于Activity的类mainWnd:首先要mainWnd成员里声明要在Android调用的C++函数;publicnativevoidsetName(String_strName);native是修饰符必须的接着在mainWnd的onCreate函数加入按钮响应///////////按钮响应函数//////////////ButtonbtnSend=(Button)findViewById(R.id.ButtonSend);btnSend.setOnClickListener(newOnClickListener(){@OverridepublicvoidonClick(View_view){EditTextetName=(EditText)findViewById(R.id.EditTextName);//调用C++方法setName(etName.getText().toString());}});///////////////////////////////////
    ·找到JDK目录/bin/javah,生成mainWnd.class的头文件。我的javah所在目录:
     C:\ProgramFiles\Java\jdk1.6.0_23\bin我的bin文件所在目录:C:\Users\Crinson\Android_And_C\bin我的包名字:Crinson.Blog.mainWnd生成命令的格式如下:C:\ProgramFiles\Java\jdk1.6.0_23\bin>javah-classpathC:\Users\Crinson\Android_And_C\bin-jniCrinson.Blog.mainWnd接着会在C:\ProgramFiles\Java\jdk1.6.0_23\bin目录生成Crinson_Blog_mainWnd.h文件。如果这步生成失败,请注意一点,你的包所在的目录要和你的包名相同,例如我的Crinson.Blog.mainWnd就要在C:\Users\Crinson\Android_And_C\bin\Crinson\Blog\目录下。★★★★★C++端★★★★★在Android工程里新建jni文件夹存放c++代码。在jni目录里新建文件夹
    Android_to_C,把Crinson_Blog_mainWnd.h放在该目录下。Crinson_Blog_mainWnd.h的内容如下://///////////////////////////////////////////////////////*DONOTEDITTHISFILE-itismachinegenerated*/#include/*HeaderforclassCrinson_Blog_mainWnd*/#ifndef_Included_Crinson_Blog_mainWnd#define_Included_Crinson_Blog_mainWnd#ifdef__cplusplusextern"C"{#endif/**Class:Crinson_Blog_mainWnd*Method:setName*Signature:(Ljava/lang/String;)V*/JNIEXPORTvoidJNICALLJava_Crinson_Blog_mainWnd_setName(JNIEnv*,jobject,jstring);#ifdef__cplusplus}#endif#endif////////////////////////////////////////////////////////因为要用到传来的字符串参数,所以要把JNIEXPORTvoidJNICALLJava_Crinson_Blog_mainWnd_setName(JNIEnv*,jobject,jstring);修改成JNIEXPORTvoidJNICALLJava_Crinson_Blog_mainWnd_setName(JNIEnv*_pEnv,jobject_obj,jstring
     _strName);接下来新建Crinson_Blog_mainWnd.cpp文件,写函数Java_Crinson_Blog_mainWnd_setName的实现,代码如下:
    ///////////////Crinson_Blog_mainWnd.cpp/////////////////#include"Crinson_Blog_mainWnd.h"//下面这个头文件内容稍候解析#include"crinson_jni.h"JNIEXPORTvoidJNICALLJava_Crinson_Blog_mainWnd_setName(JNIEnv*,jobject,jstring){constchar*pName=_pEnv->GetStringUTFChars(_strName,0);//这里反向调用了Android的showNameInAndroid()函数showNameInAndroidJNI((char*)pName);_pEnv->ReleaseStringUTFChars(_strName,pName);}//endofJava_Crinson_Blog_mainWnd_setName/////////////////////////////////////////////////////////
    Android调用C++的代码到此为止,还有编译步骤就可以用了,但是因为还要演示反向调用Android代码,如上面的showNameInAndroidJNI()函数还没实现,所以先要把showNameInAndroidJNI()实现了才能一起编译。================C++调用Android================在jni目录里新建文件夹C_to_Android,在此文件夹新建crinson_jni.h,代码如下://////////////////crinson_jni.h///////////////#ifndef_CRINSON_JNI_2011_04_08#define_CRINSON_JNI_2011_04_08#defineCLASS_WANT_TO_JNI"Crinson/Blog/mainWnd"extern"C"{externvoidshowNameInAndroidJNI();}#endif////////////////////////////////////////////////////下面是crinson_jni.cpp文件的实现,代码量虽然不多,可能在网页上会很凌乱。如果你要使用的函数返回值和参数和我的不相同,只需要改voidshowNameInAndroidJNI(char*_pstrName)里面的实现就可以://///////////////crinson_jni.cp//////////////////#include"crinson_jni.h"#include
     extern"C"{staticJavaVM*g_pJavaVM=0;staticjclassg_ClassTarget=0;JNIEnv*g_pEnv=0;jintJNI_OnLoad(JavaVM*vm,void*reserved){g_pJavaVM=vm;returnJNI_VERSION_1_4;}staticjmethodIDgetMethodID(constchar*methodName,constchar*paramCode){//接口IDjmethodIDfuncID=0;if(JNI_OK!=g_pJavaVM->GetEnv((void**)&;g_pEnv,JNI_VERSION_1_4)){return0;}i
    f(0>g_pJavaVM->AttachCurrentThread(&;g_pEnv,0)){return0;}//想要调用的类,我用头文件的宏来代替了g_ClassTarget=g_pEnv->FindClass(CLASS_WANT_TO_JNI);if(!g_ClassTarget){return0;}if(0!=g_pEnv&;&;0!=g_ClassTarget){funcID=g_pEnv->GetStaticMethodID(g_ClassTarget,methodName,paramCode);}returnfuncID;}voidshowNameInAndroidJNI(char*_pstrName){//调用Android函数,参数1为想要调用的函数,我在头文件定义了;//参数2为调用的参数格式()V代表返回值为void,Ljava/lang/String代表要传入的参数//参数详细的解析请另找JNI的资料
     jmethodIDidshowName=getMethodID(FUNC_WANT_TO_JNI,"(Ljava/lang/String;)V");if(idshowName){jstringStringArg=g_pEnv->NewStringUTF(_pstrName);g_pEnv->CallStaticVoidMethod(g_ClassTarget,idshowName,StringArg);}}}///////////////////////////////////////////////////////C++的代码就这么多,现在要使用cygwin进行编译了,我说一下编译的过程,如果你知道cygwin编译文件的设置,可以跳过本部分。在工程文件夹的根目录下,建立一个build_native.sh文件。代码如下://///////////////////build_native.sh////////////////////////#设置编译所需文件的路径,#我的ndk是在e://Android/android-ndk-r5目录下#工程文件是在C:\Users\Crinson\Android_And_C目录下ANDROID_NDK_ROOT=/cygdrive/e/Android/android-ndk-r5CRINSON_ROOT=/cygdrive/c/Users/Crinson/Android_And_C#编译pushd$ANDROID_NDK_ROOT./ndk-build-C$CRINSON_ROOTpopd///////////////////////////////////////////////////////////////////接着进入jni目录,建立Application.mk文件,代码如下://////////////////////Application.mk////////////////////////////APP_STL:=stlport_static#要生成的链接库文件为C_to_Android.so和Android_to_CAPP_MODULES:=C_to_AndroidAndroid_to_C/////////////////////////////////////////////////////////////////////继续在jni目录下建立Android.mk文件,代码如下://////////////////////////////////////////////////////////////////////LOCAL_PATH:=$(callmy-dir)include$(CLEAR_VARS)#subdirs后添加要编译的文件的路径subdirs+=$(LOCAL_PATH)/C_to_Android/Android.mksubdirs+=$(LOCAL_PATH)/Android_to_C/Android.mkinclude$(subdirs)//////////////////////////////////////////////////////////////////////进入jni目录下的Android_to_C文件夹,建立Android.mk文件,代码如下:
     /////////////////////Android.mk//////////////////////////////LOCAL_PATH:=$(callmy-dir)include$(CLEAR_VARS)LOCAL_MODULE:=Android_to_C#要编译的cpp文件LOCAL_SRC_FILES:=Crinson_Blog_mainWnd.cpp#需要用到的头文件所在目录LOCAL_C_INCLUDES:=$(LOCAL_PATH)/../C_to_Android$(LOCAL_PATH)/../Android_to_C$(LOCAL_PATH)/.#需要用到的附加库LOCAL_LDLIBS:=-L$(callhost-path,$(LOCAL_PATH)/../../libs/armeabi)-lC_to_Androidinclude$(BUILD_SHARED_LIBRARY)////////////////
    //////////////////////////////////////////////////////进入jni目录下的C_to_Android文件夹,建立Android.mk文件,代码如下:///////////////////Android.mk/////////////////////////////////LOCAL_PATH:=$(callmy-dir)include$(CLEAR_VARS)LOCAL_MODULE:=C_to_AndroidLOCAL_SRC_FILES:=crinson_jni.cppLOCAL_C_INCLUDES:=$(LOCAL_PATH)/.#LOCAL_PRELINK_MODULE:=falseinclude$(BUILD_SHARED_LIBRARY)///////////////////////////////////////////////////////////////////////接着用cgywin进入到工程所在目录,执行bashbuild_native.sh编译文件就可以,如果顺利,可以看到libs\armeabi目录下有你所需要编译的so文件,如果不成功,请检查以下原因:1.如果出现的错误信息有cannotfind–lXXXX的关键字,请检查Application.mk文件的APP_MODULES选项,被依赖的库编译的顺序是否在前面。2.如果出现的错误信息有undefinedreferencetoXXXXX的关键字,请检查是否包含头文件,所包含的其他文件的cpp文件是否也在Android.mk文件的LOCAL_SRC_FILES选项下。C++端的工作完成,回到Android。★★★★★★★★Android端★★★★★★★★★
    \\
    \
     mainWnd类增加包含调用到的库的声明:注意,库加载有先后顺序,如果程序在onCreate函数前就崩溃了,请调换库加载顺序。/////////////////////mainWnd.java///////////////////////////////////
    static{System.loadLibrary("C_to_Android");System.loadLibrary("Android_to_C");}
    ////////////////////////////////////////////////////////////////////////////////////////////////如果可以顺序进入Android程序界面,恭喜你,你已经接近成功,但是你会发现你在点击按钮之后崩溃,因为你还没有加C++反向调用Android函数的函数体。在mainWnd下加上成员函数staticpublicvoidshowNameInAndroid(String_strName),这里的函数声明必须是static修饰的。这个函数主要是弹出窗体,你想怎么摆弄怎么摆弄,我在这个函数里用在thisActivity,在mainWnd声明个静态变量thisActivity,onCreate的时候赋值this就可以。////////////////////////////mainWnd.java///////////////////////////////////////////////
    staticpublicvoidshowNameInAndroid(String_strName){StringstrName="你的名字是"+_strName;DialogshowDialog=newAlertDialog.Builder(thisActivity).setTitle("此对话框为C++代码调出!").setMessage(strName).setPositiveButton("确定",newDialogInterface.OnClickListener(){publicvoidonClick(DialogInterfacedialog,intwhichButton){dialog.dismiss();}}).create();showDialog.show();}//endofshowNameInAndroid
    //////////////////////////////////////////////////////////////////////////////////////////////至此,文章完成。Eclipse打包测试就可以。
    
    
  • 上一篇资讯: android build子系统解析
  • 下一篇资讯: Android adb的使用略解
  • 网学推荐

    免费论文

    原创论文

    浏览:
    设为首页 | 加入收藏 | 论文首页 | 论文专题 | 设计下载 | 网学软件 | 论文模板 | 论文资源 | 程序设计 | 关于网学 | 站内搜索 | 网学留言 | 友情链接 | 资料中心
    版权所有 QQ:3710167 邮箱:3710167@qq.com 网学网 [Myeducs.cn] 您电脑的分辨率是 像素
    Copyright 2008-2015 myeducs.Cn www.myeducs.Cn All Rights Reserved
    湘ICP备09003080号