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
通过以上几个步骤,基本上就可以跑起来了。一下是运行示意图:
- NDK入门:老码农谈NDK开发
- Android ndk开发入门
- Android NDK开发入门
- NDK开发入门1
- NDK开发入门2
- NDK入门开发3
- NDK开发入门4
- Android -- NDK开发入门
- Android NDK开发入门
- Android NDK开发入门
- Android NDK开发入门
- Android NDK开发入门
- NDK开发入门篇
- NDK 开发入门
- NDK开发入门
- 安卓下NDK开发入门
- Android NDK开发入门
- NDK开发入门
- 二分查找
- 高清播放之滤镜 – MadVR
- 堆栈的区别及增长方向
- Spring mvc使用注解@ResponseBody Ajax请求返回json报406错误
- 简单工厂模式
- NDK 开发入门
- java 抽象类与接口的区别
- HDU 5882 Balanced Game (脑筋急转弯)
- UML—用例图
- 全栈必备Linux 基础
- 《JAVA与模式》之简单工厂模式
- C语言创建BOOL类型
- [SolrCloud]linux安装JDK
- 五款最佳Linux下载管理器推荐