用Eclipse 建立 JNI 的專案, 示範怎样在 JAVA 調用 cpp 的函數.

我們將建立一個名稱為 jnidemo的專案, 在主Activity 將調用一個名為libHello.so 的 cpp 函數庫的 getVersion() 的函數, 將其返回字串寫在主Activity 的TextView 上.

首先用Eclipse建立一個新的 Android Activity 專案.  其它選項都用預設值就能够.

1. 略微改动主活動配置 layout/activity_main.xml,  的在TextView 添�名為 title 的id(行12)以便稍候引用

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" > <TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" /> </RelativeLayout>

2. 在MainActivity.java添�載入函式庫的動作並添加�一個native 函數名稱為 getVersion.

改寫例如以下:

package com.example.jnidemo;

import android.os.Bundle;
import android.app.Activity;
import android.widget.TextView; public class MainActivity extends Activity {
static {
System.loadLibrary("Hello"); // Hello.dll (Windows) or libHello.so (Unixes)
}
private native String getVersion(); @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); TextView tv = (TextView) findViewById(R.id.title);
tv.setText( getVersion()); } }

3. 新增一個 jni 的目錄. 在jni 底下添�一個名為 HelloJni.cpp 的文件.

/jni/HelloJni.cpp 內容例如以下

#include <jni.h>
#include <stdio.h> #define JNIREG_CLASS "com/example/jnidemo/MainActivity"//指定要注冊的类 extern "C" JNIEXPORT jstring JNICALL native_getVersion(JNIEnv *env, jobject thisObj) {
jstring szRet;
szRet = env->NewStringUTF("V1.0");
return szRet;
} /**********************************************************************************/
static JNINativeMethod gMethods[] = {
{ "getVersion", "()Ljava/lang/String;", (void*)native_getVersion },
}; /*
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
clazz = env->FindClass( className);
if (clazz == NULL) {
return JNI_FALSE;
}
if (env->RegisterNatives( clazz, gMethods, numMethods) < 0) {
return JNI_FALSE;
} return JNI_TRUE;
}
/*
* Register native methods for all classes we know about.
*/
static int registerNatives(JNIEnv* env)
{
if (!registerNativeMethods(env, JNIREG_CLASS, gMethods,
sizeof(gMethods) / sizeof(gMethods[0])))
return JNI_FALSE; return JNI_TRUE;
}
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
if (!registerNatives(env)) {//注冊
return -1;
}
/* success -- return valid version number */
result = JNI_VERSION_1_4; return result;
} //onUnLoad方法,在JNI组件被释放时调用
extern "C" void JNI_OnUnload(JavaVM* vm, void* reserved){
}

4. 在jni 底下添�一個名為 Android.mk 的文件.

/jni/Android.mk 內容例如以下

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) LOCAL_MODULE := libHello
LOCAL_SRC_FILES := HelloJni.cpp include $(BUILD_SHARED_LIBRARY)

5.  專案的檔案結構例如以下:

6. 執行結果

Note:

編譯過程, 若發生例如以下錯誤

Cannot run program "ndk-build": Unknown reason
Error: Program "ndk-build" is not found in PATH PATH=[/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/lib/jvm/jdk1.6.0_38/bin]

請到Window->Preferences->Android->NDK->NDL Location 填入ndk 安裝路徑

若出現例如以下錯誤

/opt/android/android-ndk-r9b/ndk-build clean
Android NDK: WARNING: APP_PLATFORM android-19 is larger than android:minSdkVersion 17 in /{project_folder}/AndroidManifest.xml

請改动AndroidManifest.xml 的minSdkVersion 或是到File->Properties->Android 改選 SDK 的版本号

其它可能影響編譯結果的設定:

C/C++ Build Toolchain 必須選 Android GCC Compiler

確認C/C++ Build command 是 ndk-build

延伸話題:

在cpp中怎样把log 打印到logcat 的輸出呢? 在 cpp 檔及 Android.mk 要改动幾個地方

1. 在cpp 檔添� ALOGD, ALOGE 等函數的定義

#include <android/log.h>
#define LOG_TAG "JniDemo"
#define ALOGE(...) \
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__);
#define ALOGW(...) \
__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__);
#define ALOGD(...) \
__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__);
#define ALOGV(...) \
__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__);

使用 debug level 的log輸出函數 ALOGD 範比例如以下

extern "C" JNIEXPORT jstring JNICALL native_getVersion(JNIEnv *env, jobject thisObj) {
jstring szRet;
szRet = env->NewStringUTF("V1.0");
ALOGD("native_getVersion");
return szRet;
}

2. 在 Android.mk 指定載入liblog.so 函數庫

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) LOCAL_MODULE := libHello
LOCAL_SRC_FILES := HelloJni.cpp LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)

Android JNI programming demo with Eclipse的更多相关文章

  1. android JNI 简单demo(2)它JNI demo 写

    android JNI 简单demo(2)它JNI demo 写 一.搭建Cygwin 环境:http://blog.csdn.net/androidolblog/article/details/25 ...

  2. Android JNI学习(五)——Demo演示

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

  3. android JNI调用(转)

    Android jni开发资料--NDK环境搭建 android开发人员注意了 谷歌改良了ndk的开发流程,对于Windows环境下NDK的开发,如果使用的NDK是r7之前的版本,必须要安装Cygwi ...

  4. 利用gdb 调试android jni c动态库

    http://blog.dornea.nu/2015/07/01/debugging-android-native-shared-libraries/ Since I haven't done thi ...

  5. Android Jni(Java Native Interface)笔记

    首先记录一个问题,关于如何用javah生成头文件. 为什么要生成头文件?在含有 static{ System.loadLibrary("hellojni"); } 这样代码的类下面 ...

  6. Android Jni 调用

    Chap1:JNI完全手册... 3 Chap2:JNI-百度百科... 11 Chap 3:javah命令帮助信息... 16 Chap 4:用javah产生一个.h文件... 17 Chap5:j ...

  7. Android JNI使用方法

    经过几天的努力终于搞定了android JNI部分,下面将我的这个小程序和大家分享一下.android JNI是连接android Java部分和C/C++部分的纽带,完整使用JNI需要Java代码和 ...

  8. android jni——helloworld

    看了网上好多牛人写的学习系列都是用HelloWorld作为开始,我们这里也用HelloWorld来开始我们的学习,首先我们来介绍下JNI吧. JNI作为java代码和C/C++的桥梁而存在的,为了让j ...

  9. android jni 总复习(转载)

    本文全文转载自:http://www.cnblogs.com/shuqingstudy/p/4909089.html,非常感谢 package com.test.androidjni; import ...

随机推荐

  1. js 实现图片间隔循环轮播以及没有间隔的循环轮播

    链接地址:http://blog.sina.com.cn/s/blog_75cf5f32010199dn.html 最近做了个图片循环轮播的功能.就是几张图片不断的循环滚动显示. 感觉这个方法不错所以 ...

  2. 转百度前辈的Trados使用心得

    我用Trados的时间不长,可以说是一个新手.但我在较短的时间内就已经初步掌握这个工具,说明它并不是那么神秘,并不是那么深不可测.这里,我说一说学习它的一点体会.在我转发的文章中有的内容,我就少讲一些 ...

  3. HDU2527:Safe Or Unsafe(哈弗曼树)

    Problem Description Javac++ 一天在看计算机的书籍的时候,看到了一个有趣的东西!每一串字符都可以被编码成一些数字来储存信息,但是不同的编码方式得到的储存空间是不一样的!并且当 ...

  4. ZOJ 2856 Happy Life 暴力求解

    因为是Special Judge 的题目,只要输出正确答案即可,不唯一 暴力力求解, 只要每次改变 happiness 值为负的人的符号即可. 如果计算出当前人的 happiness 值为负,那么将其 ...

  5. 开源的Delphi性能调试工具

    官网:http://dbg-spider.net/源码:https://github.com/yavfast/dbg-spider Real time profiler for Delphi appl ...

  6. thiscall仅仅应用于“C++”成员函数(this指针存放于CX寄存器,参数从右到左压)

    _stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,函数采用从右到左的压栈方式,自己在退出时清空堆栈.VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上" ...

  7. aliyun 主机Nginx 上配置Drupal 伪静态

    网上找了好久没有正确的,后面直接在http://wiki.nginx.org/Drupal 上找到原文.但原文中复制过来会出现个 'root' rewrite directive is duplica ...

  8. 网页制作之html基础学习1-简介

    学习网页制作主要分为三大块 1.HTML    超文本标记语言( 全称:Hyper Text  Markup Language) 专门编辑静态网页 2.CSS      网页美化:是HTML控制的样式 ...

  9. 关于 Swift

    摘自:http://numbbbbb.gitbooks.io/-the-swift-programming-language-/chapter1/01_swift.html Swift 是一种新的编程 ...

  10. 演练5-8:Contoso大学校园管理系统(实现存储池和工作单元模式)

    在上一次的教程中,你已经使用继承来消除在 Student 和 Instructor 实体之间的重复代码.在这个教程中,你将要看到使用存储池和工作单元模式进行增.删.改.查的一些方法.像前面的教程一样, ...