Android NDK开发学习(六)

最后更新于:2022-04-01 16:21:40

Android NDK开发学习(六):C调用java中的方法 首先说一下这一次的事例demo时在github上找到的,但是过后忘记了原链接了(实在抱歉),所以会在最后附上我上传的下载链接。 闲言少叙,进入正题。 之前的介绍中就是很常见的java调用C代码,但是实际应用中也存在反向调用。 1、先上运行效果 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24eb854e5.jpg) 在界面上有三个Button,他们的点击事件如下: ~~~ public class MainActivity extends Activity { static{ System.loadLibrary("jni"); } DataProvider dp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); dp = new DataProvider(); } public void onClick(View view) { int id = view.getId(); switch (id) { case R.id.call_void_method: dp.callCcode(); break; case R.id.call_string_parameter_method: dp.callCcode1(); break; case R.id.call_int_parameter_method: dp.callCcode2(); break; default: break; } } } ~~~ DataProvider类: ~~~ public class DataProvider { public native void callCcode(); public native void callCcode1(); public native void callCcode2(); //C调用java中空方法 shulaing.han.ndk_callback.DataProvider public void helloFromJava(){ System.out.println("hello from java"); } //C调用java中的带两个int参数的方法 public int Add(int x,int y){ System.out.println("the add result is : " + (x + y)); return x + y; } //C调用java中参数为string的方法 public void printString(String s){ System.out.println("in java code :" + s); } } ~~~ C中callCcode方法: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24eb9f414.jpg) 执行结果: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24ebb66eb.jpg) 类似的带参数的方法也是一样的原理。这里就不重复介绍了。 Demo下载链接   [点击打开链接](http://download.csdn.net/detail/qq_17766199/9136515) --------------------------------------------------------------------------------------------------------------------- 这个NDK的系列就到这里了,因为我在学习中发现了NDK的一个专栏,上面讲的很深入,所以我就不重复的制造 轮子了,附上链接 :[点击打开链接](http://blog.csdn.net/column/details/blogjnindk.html)
';

Android NDK开发学习(五)

最后更新于:2022-04-01 16:21:37

**Android NDK开发学习(五):JNI数据类型** 调用一个Java native方法的时候,方法中的参数需要传给C/C++本地函数中。 首先可以看之前的demo,stringFromJNI方法中传入一个String类型参数。 ~~~ public class GetString { public native String stringFromJNI(String string); } ~~~ 接下来是com_example_jnitest_GetString.h文件中的接收 ~~~ #include <jni.h> /* Header for class com_example_jnitest_GetString */ #ifndef _Included_com_example_jnitest_GetString #define _Included_com_example_jnitest_GetString #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_jnitest_GetString * Method: stringFromJNI * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_example_jnitest_GetString_stringFromJNI (JNIEnv *, jobject, jstring); #ifdef __cplusplus } #endif #endif ~~~ 从头文件函数的原型可以得知,stringFromJNI方法中形参的数据类型自动转换成了JNI中相应的数据类型(String ····> jstring) 剩余的类型就不一一的赘述了。可以参考下表。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24eb4cc40.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24eb645d6.jpg)
';

Android NDK开发学习(四)

最后更新于:2022-04-01 16:21:35

[Android NDK开发学习(一):环境的配置](http://blog.csdn.net/qq_17766199/article/details/48174875) [Android NDK开发学习(二):学习官方Demo : HelloJni](http://blog.csdn.net/qq_17766199/article/details/48179073) [Android NDK开发学习(三):创建第一个项目](http://blog.csdn.net/qq_17766199/article/details/48241815) **Android NDK开发学习(四):NDK配置介绍** NDK程序可以使用两个配置文件:Android.mk和Application.mk,其中Android.mk文件主要描述了如何编译C/C++代码,而Application文件用于描述当前应用程序需要哪些模块。(因为本人解除NDK时间也不长,所以相关的关键字遇到的也不多。这里介绍一些自己遇到的。以后有新的会持续更新。) 这里我采取的方法时导入官方Demo:HelloNeon和NativeActivity这个项目。查看Android.mk和Application.mk文件。对遇到的关键词进行查找资料。这里汇总一下。 1、首先是HelloNeon项目的Android.mk(导入方法见前面的教程方法) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24ea694dc.jpg) 由上到下: (1).第一行LOCAL_PATH:该变量用于指定当前Android.mk文件所在的路径。必须在Android.mk文件第一行定义。 (2).第三行CLEAR_VARS: 指定一个用于**清空几乎**所有以LOCAL_开头的变量(除了LOCAL_PATH变量)。在Android.mk文件的第二行**必须**执行这个脚本,这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。如:include $(CLEAR_VARS)。 (3).第五行LOCAL_MODULE:该变量指定模块名字。此名称**必须是所有模块名中唯一存在的,并且不包括空白分隔符**。模块名决定生成的库文件名,如:模块名位Hello,生成的动态库文件名就为libHello.so。我们在引用模块的时候,只能使用定义的模块名,不应使用库文件名。 (4).第七行与第十四行LOCAL_SRC_FILES:该变量制定了参与模块编译的C/C++源文件名。文件名都相对于LOCAL_PATH,如果指定多个文件,中间用空格分隔。 (5).第九行和第十一行TARGET_ARCH_ABI:用于分析Android.mk的目标CPU+ABI的名称(ABI,即应用程序二进制接口)。**所有基于ARM的ABI都必须将TARGET_ARCH变量的值设为arm,但可以设置不同的TARGET_ARCH_ABI变量值**。 (6).第十行和第十二行LOCAL_CFLAGS += -DXXX   相当于在所有源文件中增加一个宏定义#define XXX。 例如:代码第十行为LOCAL_CFLAGS := -DHAVE_NEON=1  所以在helloneon.c文件中有如图一段代码: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24eab7384.jpg) (7).第十七行LOCAL_STATIC_LIBRARIES表示该模块需要使用哪些静态库,以便在编译时进行链接。 (8).第十九行LOCAL_LDLIBS链接的库不产生依赖关系,一般用于不需要重新编译的库,如库不存在,则会报错找不到。且貌似只能链接那些存在于系统目录下本模块需要连接的库。如果某一个库既有动态库又有静态库,那么在默认情况下是链接的动态库而非静态库。这里是链接log库,用于在文件中打印信息。 (9).第二十一行BUILD_SHARED_LIBRARY指定一个建立共享库的GNU Make脚本文件。该脚本文件会根据以“LOCAL_”开头的变量决定如何生成共享库,其中LOCAL_MODULE和LOCAL_SRC_FILES是必须设置的两个变量。该变量的用法:include $(BUILD_SHARED_LIBRARY),生成的共享库文件名是$(LOCAL_MODULE).so。 (10).要想导入一个模块,放置如下所示的一行指令,最好放在你的Android.mk文件结束处:$(call import-module,<tag>)。这里导入 cpufeatures用于第十七行的编译。 (11).对于第九行至第十五行的简单理解:如果是armeabi-v7a和x86平台则编译helloneon-intrinsics.c.neon文件。编译结果如下图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24eaccbcd.jpg) 2、NativeActivity项目的Application.mk ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24eae3761.jpg) (1).APP_ABI在默认情况下,NDK会使用'armeabi' ABI 来生成二进制机器码,这是基于ARMv5TE的浮点运算CPU,这可以通过使用此变量来选项不同的ABI. (2).APP_PLATFORM 制定编译Android平台名称。 3、HelloNeon项目编译后: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24eb05146.jpg) 4、补充 (1).BUILD_STATIC_LIBRARY:指定一个简历静态库的GNU Make脚本。静态库不能被复制到Android应用程序包(apk)中,但可以用于建立共享库。使用该变量的方法:include $(BUILD_STATIC_LIBRARY),生成的静态库文件名是$(LOCAL_MODULE).a。 (2).TARGET_ARCH:编译Android的目标CPU架构的名称。如:arm。 (3).TARGET_PLATFORM:指定分析Android.mk文件的Android平台名称。 (4).TARGET_ABI:用于连接目标平台和ABI,也就是$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI),主要用来测试真是设别中特定的目标系统映像。 最后附上参考链接:[点击打开链接](http://blog.csdn.net/kwuwei/article/details/19428993)   [点击打开链接](http://blog.csdn.net/kwuwei/article/details/21718097)
';

Android NDK开发学习(三)

最后更新于:2022-04-01 16:21:33

[Android NDK开发学习(一):环境的配置](http://blog.csdn.net/qq_17766199/article/details/48174875) [Android NDK开发学习(二):学习官方Demo : HelloJni](http://blog.csdn.net/qq_17766199/article/details/48179073) Android NDK开发学习(三):创建第一个项目 1、首先新建一个Android项目。(不用细说了吧!) 2、项目右键····>Android Tools ·····> Add Native Support... ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e9485aa.jpg) 填写你要生成的so文件名。点击Finish。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e95fe87.jpg) 之后按照第二篇的配置方法进行配置,结果如图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e970bf3.jpg) 3、实现功能 这里测试一个很简单的功能,传入一个字符串,输出结果前拼接“Hello!” (1).首先创建一个GetString类用于书写jni方法。 ~~~ package com.example.jnitest; public class GetString { public native String stringFromJNI(String string); } ~~~ (2).MainActivity:调用jni方法 ~~~ public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView text1=(TextView) findViewById(R.id.text1); GetString string = new GetString(); text1.setText(string.stringFromJNI("JNI")); } static { System.loadLibrary("JniTest"); } } ~~~ (3).生成头文件 这里方法很多,我介绍一种简单的。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e989880.jpg) 首先在项目根目录下创建一个xml文件。用Ant 编辑器打开。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e99c814.jpg) 打开后Alt+/  快捷键选择第一个。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e9b3ac0.jpg) 之后进行文件内容的填写:填写结果如下 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e9f30a1.jpg) 之后双击文件(如果没有这个Ant可以在Window ····> Show View中添加) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24ea14b25.jpg) 双击后刷新项目在jni中会多出这个文件 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24ea267de.jpg) 文件内容如下: ~~~ /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_jnitest_GetString */ #ifndef _Included_com_example_jnitest_GetString #define _Included_com_example_jnitest_GetString #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_jnitest_GetString * Method: stringFromJNI * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_example_jnitest_GetString_stringFromJNI (JNIEnv *, jobject, jstring); #ifdef __cplusplus } #endif #endif ~~~ (4).编写.C文件 在jni中新建名为jnitest.c文件,内容如下: ~~~ <pre name="code" class="java">#include <jni.h> #include <android/log.h> #include <stdio.h> #include <string.h> #include <com_example_jnitest_GetString.h> #define LOG_TAG "MYJNI" #define LOGE(...)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) jstring Java_com_example_jnitest_GetString_stringFromJNI(JNIEnv* env, jobject thiz, jstring j_str) { const char *c_str = NULL; char buff[128] = { 0 }; jboolean isCopy; // 返回JNI_TRUE表示原字符串的拷贝,返回JNI_FALSE表示返回原字符串的指针 c_str = (*env)->GetStringUTFChars(env, j_str, &isCopy); //访问字符串 LOGE("%d", isCopy); //1为true if (c_str == NULL) { return NULL ; } sprintf(buff, "Hello! %s", c_str); (*env)->ReleaseStringUTFChars(env, j_str, c_str); //释放字符串 LOGE("return: %s", buff); return (*env)->NewStringUTF(env, buff); //创建字符串 } ~~~ ~~~ ~~~ 最后修改Android.mk文件 ~~~ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_LDLIBS := -lm -llog LOCAL_MODULE := JniTest LOCAL_SRC_FILES := jnitest.c include $(BUILD_SHARED_LIBRARY) ~~~ (5).结果: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24ea370c8.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24ea49d75.jpg)
';

Android NDK开发学习(二)

最后更新于:2022-04-01 16:21:30

[Android NDK开发学习(一):环境的配置](http://blog.csdn.net/qq_17766199/article/details/48174875) Android NDK开发学习(二)学习官方Demo : HelloJni 根据第一篇的学习,我们已经成功的配置了NDK,那么接下了就是上手实战的时刻了。 1、导入官方Demo 导入方法就不多说:导入成功后如下图 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e7453db.jpg) <1>导入的项目直接时不能运行的,需要进行设置 ![](image/56a4ee6b3a72c.jpg) ![](image/56a4ee6bd7ca5.jpg) ![](image/56a4ee6c80c61.jpg) ![](image/56a4ee6d2b283.jpg) ![](image/56a4ee6dc5d11.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e791af5.jpg) 接下来是Build的设置: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e7c51f0.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e7dd6f4.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e80377d.jpg) 点击Specify Resources 后勾选你的资源文件。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e83cbf0.jpg) 最后注意的事:如果你配置的编译器在其他的编译器下边,记得要点击up按钮,把他排到第一位。 否则C代码的编译晚于Java的代码编译,会造成你的C代码要编译两次才能看到最新的修改。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e86c2d2.jpg) <2>其他的配置参考我的第一篇。这里我就不重复了。 <3>查看代码 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e886d97.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e8a0ede.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e8dbd16.jpg) 运行结果:(这个demo是判断出你手机的构架,从而显示出来,如图我的手机是armeabi-v7a)。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e90b465.jpg) 在编译时控制台打印如下信息: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e92800d.jpg) 可以看出编译时生成了各种构架的so文件。这个的控制是Application.mk文件完成的。 demo中Application.mk 文件中的APP_ABI := all 就是编译出所有平台。 不写这句默认是只编译armeabi。 最后贴出一个连接:这个是用来解决ndk项目有时报Unresolved inclusion: <jni.h>类似配置成功但是找不到头文件的错误。[点击打开链接](http://blog.csdn.net/zhubin215130/article/details/39347873)
';

Android NDK开发学习(一)

最后更新于:2022-04-01 16:21:28

**前言:** 这几天闲的没事干,突然对android 的NDK开发有了点兴趣,所以准备学一学, 因为是业余时间学习,不定期更新。因为水平有限,有错误的理解部分,希望指出。 Android NDK开发学习(一):环境的配置。 1、工具包下载 [点击打开链接](https://github.com/inferjay/AndroidDevTools) 这里面关于Android所需的资料、工具很多。 本人是Windows 系统 下载版本如图。(虽说好多人不建议下载最新版本,说是bug比较多,根据个人喜好哈!) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24d1f3564.jpg) 这里多提一句:使用最新ndk,直接抛弃cygwin,以前做Android的项目要用到NDK就必须要下载NDK,下载安装Cygwin(模拟Linux环境用的),下载CDT(Eclipse C/C++开发插件),还要配置编译器,环境变量,特别麻烦,新版就不需要了。ADT版本在20以上,就能安装NDK插件,另外NDK集成了CDT插件。注:NDK版本在r7以上之后就集成了Cygwin,而且还是十分精简版。 2、eclipse的配置。 1.系统NDK环境变量。(就不细说了如图) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e58cffa.jpg) 2.打开Eclipse,点Window->Preferences->Android->NDK,设置NDK路径。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e5ea787.jpg) 3.新建一个Android工程,在工程上右键点击Android Tools->Add Native Support...,然后给我们的.so文件取个名字,例如:test-ndk ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e61e6f0.jpg) 这时候工程就会多一个jni的文件夹,jni下有Android.mk和test-ndk.cpp文件。Android.mk是NDK工程的Makefile,test-ndk.cpp就是NDK的源文件。 4.配置C、CPP头文件及ndk-build工具 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e63178a.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e67b794.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e6c56fc.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-26_571f24e6e0a1e.jpg) 最后一张是解决编译时报Symbol "xxx" could not be resolved、Method "xxx" could not be resolved 等错误的。 其实类似有Type "xxx" could not be resolved等都是类似解决方法。 以上这些都是学习过程中搜集到的,本人通过以上步骤已经成功配置了NDK。 相信你也可以。
';

前言

最后更新于:2022-04-01 16:21:26

> 原文出处:[Android NDK开发学习](http://blog.csdn.net/column/details/zlndk.html) 作者:[qq_17766199](http://blog.csdn.net/qq_17766199) **本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!** # Android NDK开发学习 > Android NDK开发学习,讲解一些入门的知识,如配置,导入项目及官方demo。
';