Android NDK 开发入门例子

刚开始接触NDK,折腾了好久,以免以后又忘了,故记录下,方便以后需要用时再看看。

附上例子源码http://download.csdn.net/detail/crz082/9093273

NDK开发环境配置

1. 下载NDK

  • NDK 官网下载地址https://developer.android.com/ndk/downloads/index.html
    这里写图片描述
    可根据需要下载相应的版本。

  • 下载后放到硬盘的某个目录下(比如:C:/ProgramFile),并解压,解压后的文件目录就是直接可以用的NDK了,NDK所在的目录最后不要包含空白符(PS:空格),有空白符的话,可能在后续的编译中会出错。

  • 由于在NDK r7之后就已经集成了ndk-build.cmd,所以并不需要另外下载Cygwin来模拟Linux环境来编译。当然你也可以通过Cygwin来编译。

2. 环境变量配置

  • 配置系统环境变量,如图
    这里写图片描述
    变量名称随意,变量值就是上面下载的NDK加压后,NDK的目录。

  • 接着在Path里面添加%NDK_HOME%,因为都是在eclipse上有插件自动编译,不用自己敲打命令行,所以这一变量有没有配置都没什么影响,如果不用Cygwin的话,估计是不需要用到NDK下面的编译程序的,如果使用Cygwin好像还需要配置Cygwin的环境变量。

3. eclipse配置NDK

  • 导入NDK到eclipse,Window->Preferences->Android->NDK,如图:
    这里写图片描述

使用NDK开发

(eclipse已经安装了,ADT已经CDT插件)

1. 创建Android项目JNITest

  • 测试NDK开发的例子大概功能是,在Activity界面输入两个整型数字,用NDK C++代码实现+,-,*,/ 简单的四则运算,并返回结果显示在Activity中。

  • 编写布局文件:
    布局文件包含+,-,*,/ 四个运算符button在第一行,第二行则是两个文本输入框EditText,以及两个TextView来显示选择的运算符以及运算结果,第三行是一个按钮,点击按钮则计算。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:layout_margin="5dp"
    >

    <LinearLayout 
        android:id="@+id/operator"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_alignParentTop="true"
        >
        <Button 
               android:id="@+id/add"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
             android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:text="+"
            />

        <Button 
           android:id="@+id/sub"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:text="-"
            />

        <Button 
              android:id="@+id/mul"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
             android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:text="*"
            />

        <Button 
            android:id="@+id/div"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
             android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:text="/"
            />

    </LinearLayout>

    <LinearLayout 
        android:id="@+id/cal_linaer"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_alignParentLeft="true"
        android:layout_below="@id/operator"
        >
        <EditText 
            android:id="@+id/num1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:gravity="center"
             android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
             android:digits="1234567890"
            />
        <TextView 
              android:id="@+id/select_op"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
             android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:gravity="center"
            android:text="+"
             android:textSize="20sp"
            android:textColor="#000000"
            />

        <EditText 
            android:id="@+id/num2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:gravity="center"
             android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:digits="1234567890"
            />

        <TextView 
              android:id="@+id/result"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:gravity="center"
             android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:textSize="20sp"
            android:textColor="#000000"
            />

    </LinearLayout>

    <Button 
        android:id="@+id/cal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_alignParentLeft="true"
        android:layout_below="@id/cal_linaer"
        android:layout_margin="10dp"
        android:text="计算"
        />
</RelativeLayout>
  • Activity代码:
package org.tonny.jni;


import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class JNITest extends Activity implements OnClickListener {


    //在对象创建之前加载本地方法
    static {
        System.loadLibrary("jni_test");
    }
    //用关键字native定义本地方法,即需要使用C或者C++实现的部分
    private native String GetReply(String operation, int num1, int num2);

    private Button btnAdd;
    private Button btnSub;
    private Button btnMul;
    private Button btnDiv;

    private EditText etNum1;
    private EditText etNum2;

    private TextView tvOp;
    private TextView tvResult;

    private Button btnCal;

    private TextView tvReturn;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnAdd = (Button)findViewById(R.id.add);
        btnSub = (Button)findViewById(R.id.sub);
        btnMul = (Button)findViewById(R.id.mul);
        btnDiv = (Button)findViewById(R.id.div);

        etNum1 = (EditText)findViewById(R.id.num1);
        etNum2 = (EditText)findViewById(R.id.num2);

        tvOp = (TextView)findViewById(R.id.select_op);
        tvResult = (TextView)findViewById(R.id.result);

        btnCal = (Button)findViewById(R.id.cal);

//      tvReturn = (TextView)findViewById(R.id.tv_return);

        btnAdd.setOnClickListener(this);
        btnSub.setOnClickListener(this);
        btnMul.setOnClickListener(this);
        btnDiv.setOnClickListener(this);

        btnCal.setOnClickListener(this);

        etNum1.setInputType(EditorInfo.TYPE_CLASS_PHONE);
        etNum2.setInputType(EditorInfo.TYPE_CLASS_PHONE);


    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        int btnId = v.getId();
        switch(btnId){
        case R.id.add:
            tvOp.setText(btnAdd.getText());
            break;
        case R.id.sub:
            tvOp.setText(btnSub.getText());
            break;
        case R.id.mul:
            tvOp.setText(btnMul.getText());
            break;
        case R.id.div:
            tvOp.setText(btnDiv.getText());
            break;

        case R.id.cal:
            tvResult.setText(GetReply(tvOp.getText().toString(), 
                    Integer.valueOf(etNum1.getText().toString()),
                    Integer.valueOf(etNum2.getText().toString())));


            break;
        }
    }
}
 static {
        System.loadLibrary("jni_test");
    }

2. 添加Native Support

项目右键,Android Tools->Add Native Sopport…,如图:
这里写图片描述
在这里填写的名称需要更Activity里的加载的一样。

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

经过这一步之后会在项目的目录文件下生成jni目录文件,文件中包含有Android.mk和jni_test.cpp文件。Android.mk是NDK工程的Makefile,my-ndk.cpp就是NDK的源文件。

4. 生成C的头文件

打开cmd,并cd到项目下的src目录下,使用javah org.tonny.jni.JNITest来生成org_tonny_jni_JNITest.h C的头文件,此处的类必须使用类的全称,即加上包名和类名。接着把头文件拷到jni目录下。还有种方法是cd到bin/class目录下使用javah org.tonny.jni.JNITest来生成头文件,但是我使用这种发放时提示
这里写图片描述
我也不知道为什么,因为在src目录下同样可以生成头文件,也就没有深究这个出错的原因。
头文件代码:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_tonny_jni_JNITest */

#ifndef _Included_org_tonny_jni_JNITest
#define _Included_org_tonny_jni_JNITest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     org_tonny_jni_JNITest
 * Method:    GetReply
 * Signature: (Ljava/lang/String;II)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_org_tonny_jni_JNITest_GetReply
  (JNIEnv *, jobject, jstring, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

5. 添加NDK Builder

  • 项目右键,Properties->Builder->New->Program,如图
    这里写图片描述

  • 接着
    这里写图片描述

  • 切换到Refresh选项卡,在Refresh resources upon completion前面打钩,如果想要在整个工作空间起作用的话,就行第一个,如果只想作用于当前项目则选择第三方。
    这里写图片描述

  • 切换到Build Options选项卡,选上After a “Clean”、During manual builds 、During auto builds及最下面的specify working set of relevant resource,选择当前工程里的jni文件夹,即ndk编译时的源代码和mk文件所在目录。
    这里写图片描述
    然后Finish。

5. 添加依赖库

项目右键,Properties->C/C++ General->Paths and Symbos->Add
这里写图片描述
比如我的include文件所在目:C:\SoftWare\android-ndk-r10e\platforms\android-21\arch-arm\usr\include。这个路径比较长,为了使用方便,可以设置环境变量。

6. C++代码实现计算

#include<jni.h>
#include<string.h>
#include <stdio.h>
#include <stdlib.h>
#include"org_tonny_jni_JNITest.h"

JNIEXPORT jstring JNICALL Java_org_tonny_jni_JNITest_GetReply(JNIEnv * evn,
        jobject, jstring jop, jint jn1, jint jn2) {
    const char *op = evn->GetStringUTFChars(jop, 0);
    jdouble result = 0.0;
    if (strcmp(op, "+") == 0) {
        result = jn1 + jn2;
    }
    if (strcmp(op, "-") == 0) {
        result = jn1 - jn2;
    }
    if (strcmp(op, "*") == 0) {
        result = jn1 * jn2;
    }
    if (strcmp(op, "/") == 0) {
        if (jn2 == 0) {
            result = 0;
        } else {
            result = ((jdouble)jn1) / jn2;
        }
    }

    evn->ReleaseStringUTFChars(jop, op);

    char str[100];
//  itoa(result, str, 10);
    sprintf(str, "%.2f", result);

    jstring jstr = evn->NewStringUTF(str);
    return jstr;
}

7. 实例效果图

这里写图片描述

可能遇到的问题

1. Type ‘JNICALL’ could not be resolved或者找不到头文件“Unresolved inclusion”之类的

如果已经导入了依赖包,依然出现这个问题,这时可以试试考虑:
NDK Project -> New -> Folder -> Advanced -> Link to alternate location(Linked Folder),添加:C:\SoftWare\android-ndk-r10e\platforms\android-21\arch-arm\usr\include;
这里写图片描述

2. 如论做什么,只要打开.c或者.cpp文件就会出现未识别关键字之类的问题

这个时候,可以试试,project->clean,如果项目没有错误,但是一点开.c或者.cpp文件,则又会出现红叉,从而造成无法通过编译。这个问题,我在网上找了很久,有些说法是CDT插件的BUG,解决这个问题可以通过关闭CDT插件的语法分析,这样就不会报语法错误了,但是同时在写代码时又带来了很大的不便。
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值