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。