一步一步学习androidNDK编程(hello world)

一步一步学习androidNDK编程(hello world)上一篇博客,已经搭建好了windows下的linux环境(cygwine),这次我们试着写一个helloworld。首先需要去android的官网下载android-ndk压缩包,之后解压,进入解压后的目录,我们发现有一个ndk-build的脚本文件,这个脚本文件就是我们用交叉编译的文件。我们通过 “./ndk-build” 来运行该命令,如下图:    因为目前我们没有

大家好,又见面了,我是你们的朋友全栈君。

         上一篇博客,已经搭建好了windows下的linux环境(cygwine),这次我们试着写一个hello world。首先需要去android的官网下载android-ndk压缩包,之后解压,进入解压后的目录,我们发现有一个ndk-build的脚本文件,这个脚本文件就是我们用交叉编译的文件。我们通过  “./ndk-build”  来运行该命令,如下图:

一步一步学习androidNDK编程(hello world)

        因为目前我们没有编译任何c代码,所以会提示”could not find application project directory”这样的错误,这说明我们的ndk的环境,已经是ok的。但是如果我们每次执行该命令”ndk-build”,难道都必须进入ndk的解压缩目录下来运行吗?答案是”no”,我们可以配置ndk的环境变量,就像配置java环境变量一样。

        我们打开cygwine的安装目录,我的是在c盘下的cygwine目录下,也是默认的目录,在该目录下有一个etc文件夹,在etc文件夹下有一个profile的文件,我们打开它

将PATH原先的路径:”PATH=”/usr/local/bin:/usr/bin:” ,我们在”bin:”之后添加ndk的解压缩的目录,我的是在f:盘下,如下图:红色标注的就是我新添加的ndk的路径:

一步一步学习androidNDK编程(hello world)

         完成之后,保存,然后重新打开cygwine,在任意目录输入”ndk-build” ,查看是否配置好了“ndk-build”的环境变量。

===============================================================================================

       接下来,我们来写一个hello world,首先在eclipse下新建一个android工程,这里我取名为”helloworld”,创建好工程以后,我们需要在java代码中申明一个native方法,如下:

public native String helloWorldNdk();

这里注意,括号后边不能添加大括号,因为我们只是声明而并未实现该方法,native关键字,表明该方法的实现是在c语言层面实现的。

      接下来我们呢需要在helloworld工程下创建一个jni目录。在该目录下新建一个hello.c文件,在编写hello.c文件之前,我们需要用javah生成public native String helloWorldNdk(); 方法对应的头文件,由于我们在MainActivity中声明该方法,当我们用javac编译的时候,由于用到了R文件,导致生成字节码失败,由于我们只是需要.h头文件,所以我们可以新建一个java工程,来生成.h文件,如下图:

一步一步学习androidNDK编程(hello world)

其中JavahTest.java中的内容,就是我们在Mainactivty中声明的native方法,如下:

package com.test.example;

public class JavahTest {
	public native String helloWorldNdk();
	
}

接下来,我们生成.h文件,首先运行javac生成.class字节码。

javac JavahTest.java

运行以上命令,会生成.class字节码,接下来生成.h文件,如下图:

一步一步学习androidNDK编程(hello world)

此时,会生成一个com_test_example_JavahTest.h文件,该文件内容如下:

#include <jni.h>
/* Header for class com_test_example_JavahTest */

#ifndef _Included_com_test_example_JavahTest
#define _Included_com_test_example_JavahTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_test_example_JavahTest
 * Method:    helloWorldNdk
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_test_example_JavahTest_helloWorldNdk
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

其中jstring JNICALL Java_com_test_example_JavahTest_helloWorldNdk (JNIEnv *, jobject);

就是我们需要在hello.c中声明的方法,这里需要注意,由于我们的native方法是在MainActivity中声明的,所以,我们需要将jstring JNICALL Java_com_test_example_JavahTest_helloWorldNdk (JNIEnv *, jobject);中的JavahTest替换成MainActivity,如下:

jstring Java_com_example_helloworld_MainActivity_helloWorldNdk(JNIEnv* env ,jobject obj)

     接下来就是完整实现hello.c的代码,如下:

#include<stdio.h>
#include<jni.h>

jstring Java_com_example_helloworld_MainActivity_helloWorldNdk(JNIEnv* env ,jobject obj) {

	return (*env)->NewStringUTF(env,"hello world");

} 

可以看到这里我们返回”hello world”字符串。

      记住,需要编译该android工程中的c文件,我们还需要编写Android.mk文件,同样在jni目录下,新建一个Android.mk文件,内容如下:

   LOCAL_PATH := $(call my-dir)

   include $(CLEAR_VARS)

   LOCAL_MODULE    := hello
   LOCAL_SRC_FILES := hello.c

   include $(BUILD_SHARED_LIBRARY)

其中LOCAL_MODULE是我们需要编译的模块名称,这个名称随便命名的,LOCAL_SRC_FILES是我们需要编译的源文件

       当hello.c和Android.mk文件都创建好了以后,我们就可以编译该hello.c文件了,打开cygwine,进入该android工程,运行”ndk-build”命令,即可生成libhello.so文件,如下图:

一步一步学习androidNDK编程(hello world)

        同时,我们发现在helloworld的android工程中,生成了以下文件:

一步一步学习androidNDK编程(hello world)
          在libs目录下生成的libhello.so文件就是一个可以执行的二进制文件。下面我们就要在java代码中使用该二进制文件。我们通过静态代码块经该二进制文件加载进来。如下:

static{
		
		System.loadLibrary("hello");
}

        这里需要注意的是:这里的”hello”,就是我们在Android.mk文件中的 LOCAL_MODULE的值

       接下来就是,调运之前生成的二进制文件,我们只需要在MainActivity.java中这样写即可

Toast.makeText(this,helloWorldNdk(),Toast.LENGTH_LONG).show();

 此时,当运行我们的helloworld工程,即会弹出toast,显示我们在hello.c中返回的字符串。

       到这里,一个最基本的ndk实现就完成了,现在我在加上一个声明的方法:

public native String hello_World_Ndk();

      那么,我们的hello.c中的方法应该怎么写呢?参照之前的写法:

jstring Java_com_example_helloworld_MainActivity_hello_World_Ndk

这里需要注意,这种写法是错误的,ndk会以为我们是在MainActivity中的内部类hello,以及hello中的内部类World中的方法Ndk,这样显然是不对的,ndk为这种情况提供了一个标准,我们需要在方法中的每一个下划线之后加上数字1即可,如下:

jstring Java_com_example_helloworld_MainActivity_hello_1World_1Ndk(JNIEnv* env ,jobject obj) {

	return (*env)->NewStringUTF(env,"i am from china");

} 

这一点,我们可以通过javah来生成,我在d:盘下新建一个MainActivity.java,内容如下:

public class MainActivity {
	public native String hello_World_Ndk();
}

然后,我们进入d:盘运行如下命令,生成.h文件,如下图:

一步一步学习androidNDK编程(hello world)

此时在d:盘下生成了一个MainActivity.h文件,内容如下:

JNIEXPORT jstring JNICALL Java_MainActivity_hello_1World_1Ndk
  (JNIEnv *, jobject);

可以看到是以这样命名的。

        这里有一点需要注意的是,如果我们的类是有包名的话,此时运用javah来生成.h文件的时候,首先要将生成的.class文件拷贝到对应的包地下,然后运行如下命令:

javah   包名.类名      这样才可以生成.h文件。

       那么现在呢,有了以上这些基础之后呢,就可以为MainActivity.java中声明的native方法直接生成.h头文件了,cmd进入命令行,首先进入helloworld工程的bin/classes目录下,执行如下命令即可:

javah com.example.helloworld.MainActivity

此时,会在bin/classes文件夹下新生成一个com_example_helloworld_MainActivity.h文件,我们将该文件拷贝到jni目录下,如下图:

一步一步学习androidNDK编程(hello world)

这个时候,我们的hello.c就可以这样写了:

#include<stdio.h>
#include<jni.h>
#include "com_example_helloworld_MainActivity.h"

/*
jstring Java_com_example_helloworld_MainActivity_helloWorldNdk(JNIEnv* env ,jobject obj) {

	return (*env)->NewStringUTF(env,"hello world");

} 

jstring Java_com_example_helloworld_MainActivity_hello_1World_1Ndk(JNIEnv* env ,jobject obj) {

	return (*env)->NewStringUTF(env,"i am from china");

} 
*/

JNIEXPORT jstring JNICALL Java_com_example_helloworld_MainActivity_helloWorldNdk
  (JNIEnv * env, jobject obj) {
  
	return (*env)->NewStringUTF(env,"hello world two");
}

JNIEXPORT jstring JNICALL Java_com_example_helloworld_MainActivity_hello_1World_1Ndk
  (JNIEnv * env, jobject obj) {
	
	  return (*env)->NewStringUTF(env,"i am from china two");
  
}

      此时运行helloworld工程,toast会一次弹出”hello world two”和”i am from china two”

总结一下:

1.首先需要声明native方法:

public native String helloWorldNdk();
public native String hello_World_Ndk();

2.然后运用javah生成对应的.h头文件

3.根据.h头文件,编写hello.c代码

4.编写Android.mk文件

#交叉编译编译c/c++代码所依赖的配置文件

#获取当前Android.mk的路径  
LOCAL_PATH := $(call my-dir)

#变量初始化操作
include $(CLEAR_VARS)

#libhello.so 其实生成的libhello.so就是在我们这个模块的名称前面加上lib后边加上.so
LOCAL_MODULE    := hello
LOCAL_SRC_FILES := hello.c

include $(BUILD_SHARED_LIBRARY)

5.在java中通过静态快引入二进制文件:

static{
       System.loadLibrary("hello");
}


源码下载

     

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/125116.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • mysql和sql server一样吗_sql视图和查询的区别

    mysql和sql server一样吗_sql视图和查询的区别导读:接下来的网上商城的项目,需要用到MySQL数据库了。这个对于我来说,是一个新接触的东西,按照惯例,在刚开始学习一个东西的时候,先从宏观上去了解它。本篇博客,先介绍SQLServer的基本内容,然后介绍MySQL的基本内容,最后介绍两者之间的区别。一、SQLServer基本简介1.1,概述SQLServer是Microsoft公司推出的关系型数据库管理系统。具有使

    2022年9月27日
    0
  • for()循环语句_for next循环语句

    for()循环语句_for next循环语句一、for语句结构:for(初始化表达式;循环条件表达式;循环后的操作表达式){执行语句;}循环条件表达式,必须是true或false示例:输出结果:第0次你好第1次你好第2次你

    2022年8月5日
    6
  • 数据结构之二叉树的前序遍历、中序遍历、后序遍历、层序遍历「建议收藏」

    数据结构之二叉树的前序遍历、中序遍历、后序遍历、层序遍历「建议收藏」最近也是在准备笔试,由于没有系统的学过数据结构,所以每次在考到二叉树的遍历的时候都是直接跪,次数多了也就怒了,前些天也是准备论文没时间整这些,现在提交了,算是稍微轻松点了,所以花了半天的时间来学了下二叉树。现在记下来,以便后序查阅。一、二叉树的遍历概念  1. 二叉树的遍历是指从根结点触发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问一次且仅被访问一次。(1).前(

    2022年9月14日
    0
  • 联想Win10安装Ubuntu双系统教程

    联想Win10安装Ubuntu双系统教程前言:最近为了更好的做一名程序员(猿),所以准备装一个双系统,也就是Ubuntu系统,网上坑太多,所以决定自己写一点操作步骤首先看一下我的计算机配置,联想小新700Tip:这里的安装步骤仅仅针对联想Win10改型号或者相关型号,其他品牌型号安装过程可能有所差异,在这里不多说(因为穷,没用过其他的)首先要明确装双系统有一个步骤,在这里分为:(1)下载Ubuntu镜像文件;(2…

    2022年7月24日
    24
  • python编程爱心-如何用python画爱心「建议收藏」

    python编程爱心-如何用python画爱心「建议收藏」用python绘制爱心的基本步骤如下:首先先下载安装好python程序。在我们自己的电脑上找到python的IDLE工具。2.然后打开IDLE,新建一个文件,命名为test1.py。3.接着我们就开始导入turtle库,然后编辑代码。importturtleimporttime#画心形圆弧defhart_arc():foriinrange(200):turtle.right(1)t…

    2022年9月7日
    0
  • QCustomPlot使用心得五:坐标轴常用属性设置[通俗易懂]

    QCustomPlot使用心得五:坐标轴常用属性设置[通俗易懂]先看轴部分的名称约定,根据名称就可以修改对应的属性了1.显示坐标轴默认只显示左y轴和下边的x轴,调用setVisible(bool)设置轴是否显示customplot->yAxis2->setVisible(true);//显示y轴2customplot->xAxis2->setVisible(true);//显示x轴2调用se…

    2022年10月16日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号