NDK开发笔记(二) 开发入门

话说上回贫道看到了令全世界二分之一人都胆战心惊的四字真言,不禁仰天长叹,“难道绝学只是残疾人的专利”。贫道万念俱灰,为了不再危害人间,准备将书付之一炬。这时一阵小风嗖嗖地吹过,只见书页的下半部分又漏了出来,只见上面完整地写道“欲练神功,只需用功”。天不负我,贫道仰天长笑。

话说是福利就要收,贫道一边哼着“今天是个好天气”的小曲儿,一边撸起袖管开始干了起来。

首先通过Eclipse创建一个Android工程,命名为TestNDK。贫道以后会就用这个工程来演示NDK的开发(详图和目录结构图请参见图1)。对于NDK的开发,在创建工程时,我们不需要额外的设置。和其他普通工程一样。

图1

2.贫道在这里先举一个简单的例子,这样能使大家对NDK有个简单直观的了解。这个例子演示了从底层返回一个字符串,然后显示到界面上。

先在MainActivity.java里申明JNI调用函数stringFromJNI,它的功能就是从底层返回一个字符串,注意要添加native关键字以表示这个函数通过JNI调用。与此同时,我们还注意到为了能调用stringFromJNI,我们还需要载入包含stringFromJNI函数的模块,所以在MainActivity类里我们需要通过System.loadLibrary函数静态调用模块。我们将这个底层模块取名ndktest。

package com.example.testndk;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        TextView  tv = new TextView(this);
        String str = stringFromJNI();
        tv.setText( str );
        setContentView(tv);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
    
    private native String stringFromJNI();
    

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

}

3.在工程目录下,建立一个jni目录(在本文里就是d:\workspace\TestNDK,见图1)。

4.在jni目录里,创建一个c文件名叫ndktest.c。此时,众人开始欢呼雀跃,终于可以不用再看VM的脸色办事了,为了表达自己的喜悦之情,写了以下一段测试代码以兹留念。在这个普天同庆的日子里,贫道却发现了一丝不和谐的气氛。

  a.首先是怪异的函数名,在NDK中,Native Code的函数名是有一定规则的,即 Java+package名称+调用的java文件名+申明的函数名,其中连接和package名称中的"."用下划线表示。

       所以在本例中的函数名Java_com_example_testndk_MainActivity_stringFromJNI,         

      Java: 表示被Java调用。

      com_example_testndk:表示package的名称(com.example.testndk),其中的"."被下划线替代。

      MainActivity:申明调用函数的类名。

      stringFromJNI:申明的函数名。

 b.怪异的返回值,在NDK中,不管是从Java传过来的传递值,还是传回Java的返回值,都是专门的参数(比如java中的string对应ndk的jstring,int[]对应jintarray,具体可参见jni.h)。

   c.多出来的传递参数,JNIEnv* env和jobject thiz是底层函数,必须要带的参数。env开发者利用此参数做查询和传化数据类型(比如将jintarray转换成int数组,在以后的章节中会详细说明)。thiz表示这个调用这个函数的类对象,本文中就是MainActivity的对象。

#include <string.h>
#include <jni.h>

jstring
Java_com_example_testndk_MainActivity_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
     return (*env)->NewStringUTF(env, "Hello from JNI ! We are free !");
}

5.在JNI目录里创建Android.mk,其中LOCAL_MODULE设置的是模块名称(与上面MainActivty.java中加载的模块名相同),LOCAL_SRC_FILES设置的是要编译的文件名。

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := ndktest
LOCAL_SRC_FILES := ndktest.c

include $(BUILD_SHARED_LIBRARY)

4.在Windwos下进入Command模式,然后进入工程目录,最后输入ndk-build(详见图2)。编译通过后,会自动在工程目录中的libs目录中生成armeabi目录,里面包含了底层模块libndktest.so(在本文就是d:\workspace\TestNDK\libs\armeabi\libndktest.so)。Eclipse编译工程时自动会把这个文件打入安装包内。

  图2

万事俱备,只欠东风。贫道轻捻胡须,拂尘在运行键上一抖,在阵阵仙乐声中,运行得到如下结果。

顿时台下,掌声雷动。不少C/C++籍人士热泪盈眶,边舞哈达,边唱起了“翻身农奴把歌唱”。希望社发表评论《即消除南非种族隔离后,又一伟大人权胜利》。在一片膜拜声中,贫道挥手致意,激动之余,不禁喊道:“同志们辛苦了”。就在贫道等着众人回应的时候,不知道从哪窜出一个死胖子,头上挂着两个角,身上穿着毛茸茸的羊毛外衣,嘴上叼着一块青青草原蛋糕,奶声奶气地问道,“输命令行太累了,还有更轻松的方法吗?”。贫道顿时一脸的黑线,但为了能保持儒雅的形象,贫道露出了一个旭日阳光般的笑容,拍了拍死胖子的头道:“懒羊羊同学提了一个很好的问题。” 这时只见贫道一个难度系数4.0的720度后拱翻回到了讲台上,点开了Eclipse界面,然后唰唰的在TestNDK项目上打开菜单,点击Android Tools->>Add Native Support... (详见图3)。随后会有一个对话框弹出,在输入框里输入模块名称,重新然后按照3,4步骤开发。当最后贫道轻点运行键时,又一个奇迹诞生了,只见底层模块被Eclipse自动编译,再也不用手工输入命令行操作了。此时的懒羊羊同学,吃惊地张开了大嘴,一大滩口水落在了贫道的键盘上。恶寒

 图3

 全场再次起立鼓掌,不少C/C++籍人士高举贫道的头像,成了贫道的忠诚粉丝。在这万众拥戴的时刻,一丝玻璃的光芒划过,一个稚嫩而又镇定的声音响了起来:“这就是全部的真相吗”?

欲知后事如何,请待下回分解。

原文地址:https://www.cnblogs.com/andreitang/p/2782479.html