NDK 开发入门

来源:互联网 发布:阿里云 cn2 编辑:程序博客网 时间:2024/05/18 21:46

之前都是在同时写好的基础上进行开发,今天自己写了一个jni(也参考了网上的源码)把大概的流程搞清楚了,在此记录一下。

    • 一概述
    • 二本文主要内容
    • 三具体实现
      • 布局文件
      • java代码
      • makefile
      • jni代码
        • 1手打方案
        • 2 javah命令生成c文件方案
      • 给工程添加ndk依赖

一、概述


ndk可以帮助我们在android下用java 调用c/c++代码。目前遇到的“套路”一般都是java调用c++,然后c++再回调java把结果返回。即 java–>c/c++ –>java;或者c/c++直接调用java:c/c++–>java.

二、本文主要内容


用NDK实现Java与C/C++互相调用。实现int,string,byte[]这三种类型的变量传递。

三、具体实现


前提条件:eclipse已经配好了ndk,androidsdk。

1 布局文件


我们建立工程jnitest。在布局文件热死、layout、activity_main.xml中加入以下代码。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="fill_parent"     android:layout_height="fill_parent"     android:orientation="vertical" >     <Button         android:id="@+id/intbutton"         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:text="传给JNI一个整数1"         />     <TextView         android:id="@+id/inttextview"         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:text="接收到的整数:"         />    <Button         android:id="@+id/stringbutton"         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:text="传给JNI一个字符A"         />     <TextView         android:id="@+id/stringtextview"         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:text="接收到的字符:"         />     <Button         android:id="@+id/arraybutton"         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:text="传给JNI一个数组12345"         />     <TextView         android:id="@+id/arraytextview"         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:text="接收到的数组:"         /></LinearLayout>

2 java代码


在src目录下新建包com.example.jnitest,并创建文件MainActivity.java. 源码如下:

package com.example.jnitest;import com.example.jintest.R;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.support.v7.app.ActionBarActivity;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.Button;import android.widget.TextView;public class MainActivity extends ActionBarActivity {    private Button intButton = null;    private Button stringButton = null;    private Button arrayButton = null;    private TextView intTextView = null;    private TextView stringTextView = null;    private TextView arrayTextView = null;     private Handler mHandler = null;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        intButton = (Button)this.findViewById(R.id.intbutton);        intButton.setOnClickListener(new ClickListener());        stringButton = (Button)this.findViewById(R.id.stringbutton);        //注册按钮监听        stringButton.setOnClickListener(new ClickListener());        arrayButton = (Button)this.findViewById(R.id.arraybutton);        //注册按钮监听        arrayButton.setOnClickListener(new ClickListener());        intTextView = (TextView)this.findViewById(R.id.inttextview);        stringTextView = (TextView)this.findViewById(R.id.stringtextview);        arrayTextView = (TextView)this.findViewById(R.id.arraytextview);        mHandler = new Handler(){            @Override            public void handleMessage(Message msg) {                switch(msg.what){                //int                case 0 :                {                    intTextView.setText(msg.obj.toString());                    break;                }                case 1:                    stringTextView.setText(msg.obj.toString());                    break;                case 2:                {                    byte [] b = (byte[])msg.obj;                    arrayTextView.setText(Byte.toString(b[0])+Byte.toString(b[1])                            +Byte.toString(b[2]));                    break;                }                }            }        };    }    public class ClickListener implements View.OnClickListener{        @Override        public void onClick(View v) {            switch(v.getId()){                case R.id.intbutton:                {                    callJNIInt(1);                    break;                }                case R.id.stringbutton:                {                    callJNIString("你好啊");                    break;                }                case R.id.arraybutton:                {                    callJNIByte(new byte[]{1,2,3,4,5});                    break;                }            }        }    }    private void callBackInt(int i ){        Message msg = new Message();        msg.what = 0;        msg.obj = i;        mHandler.sendMessage(msg);    }    private void callBackString(String s){        Message msg = new Message();        msg.what = 1;        msg.obj = s;        mHandler.sendMessage(msg);    }    private void callBackByte(byte[] b){        Message msg = new Message();        msg.what = 2;        msg.obj = b;        mHandler.sendMessage(msg);    }    private native void callJNIInt(int i);    private native void callJNIString(String s);    private native void callJNIByte(byte[] b);    static{        System.loadLibrary("myjni");    }}

3 makefile


在工程根目录下新建jni目录。并新建Android.mk文件。写入以下代码:

TOP_LOCAL_PATH:=$(call my-dir)include $(call all-subdir-makefiles)LOCAL_PATH := $(TOP_LOCAL_PATH)include $(CLEAR_VARS)LOCAL_MODULE := myjniLOCAL_SRC_FILES := com_example_jnitest_MainActivity.cLOCAL_LDLIBS :=-lloginclude $(BUILD_SHARED_LIBRARY)

4 jni代码


4.1手打方案

在jni文件夹下,再新建com_example_jnitest_MainActivity.c文件(也可以用javah命令创建)

#include <stdio.h>#include <jni.h>#include <android/log.h>#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO,"native-activity",__VA_ARGS__))//#define LOGW(...) ((void)__android_LOG_print(ANDROID_LOG_WARN,"native-activity",__VA_ARGS__)) /**********传输整数**************/JNIEXPORT void JNICALL Java_com_example_jnitest_MainActivity_callJNIInt(JNIEnv* env,jobject obj,jint i){    //找到java类    jclass cls = (*env)->FindClass(env,"com/example/jnitest/MainActivity");    //找到方法    jmethodID mid = (*env)->GetMethodID(env,cls,"callBackInt","(I)V");    if(mid==NULL){        LOGI("int error can't find method callBackInt");    }    LOGI("from java int:%d",i);    //回调java中的方法    (*env)->CallVoidMethod(env,obj,mid,i);}/********传输字符串**************/JNIEXPORT void JNICALL Java_com_example_jnitest_MainActivity_callJNIString(JNIEnv* env,jobject obj,jstring s){    //找到java类    jclass cls = (*env)->FindClass(env,"com/example/jnitest/MainActivity");    //找到方法    jmethodID mid = (*env)->GetMethodID(env,cls,"callBackString","(Ljava/lang/String;)V");    if(mid==NULL){        LOGI("String error can't find method callBackString");        return;    }    //获取java传过来的字符串    const char *ch;    ch = (*env)->GetStringUTFChars(env,s,NULL);    //打印    LOGI("from java string:%s",ch);    (*env)->ReleaseStringUTFChars(env,s,ch);    //回调java中的方法    (*env)->CallVoidMethod(env,obj,mid,s);}/********传输数组(byte[])*************/JNIEXPORT void JNICALL Java_com_example_jnitest_MainActivity_callJNIByte(JNIEnv* env, jobject obj, jbyteArray b){    //找到java中的类    jclass cls = (*env)->FindClass(env,"com/example/jnitest/MainActivity");    //找到类中的方法    jmethodID mid = (*env)->GetMethodID(env,cls,"callBackByte","([B)V");    if(mid == NULL){        LOGI("byte error can't find callBackByte");        return;    }    //获取数组长度    jsize length = (*env)->GetArrayLength(env,b);    LOGI("length:%d",length);    int i;    jbyte* p = (*env)->GetByteArrayElements(env,b,NULL);    //打印    for(i=0;i<length;i++){        LOGI("%d",p[i]);    }    char c[5];    char ch = 1;    for(;ch<6;ch++){        c[ch-1]=ch;    }    jbyteArray carr = (*env)->NewByteArray(env,length);    (*env)->SetByteArrayRegion(env,carr,0,length,c);    (*env)->CallVoidMethod(env,obj,mid,carr);}

4.2 javah命令生成c++文件方案

windows下使用cmd cd到工程src目录,然后
javah -classpath . -jni 包名.文件名

javah -classpath .  -jni com.example.jnitest.MainActivity

如果有提示:错误: 编码GBK的不可映射字符。

那么说明文件中包含了中文。
需要用记事本打开java文件,然后另存为ANSI格式。再运行就ok了。
命令会在src下生成头文件:com_example_jnitest_MainActivity.h然后你就可以把文件拷贝到jni中,然后再添加cpp文件了。

5 给工程添加ndk依赖


对工程右键,选择Android Tools –>Add Native Support…

这里写图片描述
**然后在给c/c++代码要编译成的so取名。
这里写图片描述
此时你会发现,右键工程后,菜单里面多出来了c/c++ general
这里写图片描述

通过以上几个步骤,基本上就可以跑起来了。一下是运行示意图:

这里写图片描述

0 0
原创粉丝点击