Android NDK JNI之HelloWorld两种方法汇总

来源:互联网 发布:淘宝crm软件排名 编辑:程序博客网 时间:2024/05/21 14:06

 建立一个JNI工程的步骤:

  • 一。新建Android程序工程。
  • 二。生成.h头文件,编写.c文件。
  • 三。编写mk文件,使用Cygwin编译出so文件。
  • 四。加载so文件,运行程序。
  • {方法一:} 自动生成jni文件
  • (1)新建android工程


    (2) 添加NDK路径

    (3) 添加本地支持

    (4) 给本地库起名

    此时工程目录下会自动生成jni文件夹


    此时Makefile也自动生成

    LOCAL_PATH := $(call my-dir)    include $(CLEAR_VARS)  LOCAL_MODULE    := hello  LOCAL_SRC_FILES := hello.cpp    include $(BUILD_SHARED_LIBRARY) 
    (5) 编写准备生成本地库的cpp文件:hello.cpp
    #include <jni.h>  #include <string.h>     extern "C" {       JNIEXPORT jstring JNICALL Java_com_snail_helloworld_MainActivity_myhello(JNIEnv * env, jobject obj);   };     JNIEXPORT jstring JNICALL Java_com_snail_helloworld_MainActivity_myhello(JNIEnv * env, jobject obj)   {       return env->NewStringUTF("Hello From CPP");   } 
    注意

    Java_com_snail_hello_MainActivity_myhello

    Java                             为固定的

    com_snail_helloworld  为包名

    MainActivity                为Activity名称

    myhello                        为上层调用的函数名

    这几个命名一定要对应,否则上层调用会出现错误:

    “java.lang.UnsatisfiedLinkError: Native method not found”

       (1)JNIEnv * env:这个env可以看做是Jni接口本身的一个对象,在上一篇中提到的jni.h头文件中存在着大量被封装好的函数,这些函数也是Jni编程中经常被使用到的,要想调用这些函数就需要使用JNIEnv这个对象。例如:env->GetObjectClass()。(详情请查看jni.h)

    (2)jobject obj:如在Test类的main方法中有这样一段代码: 

        Test t=new Test(); t.firstTest();

    这个jobject需要两种情况分析。上段代码中firstTest方法是一个非静态方法,在Java中要想调用它必须先实例化对象,然后再用对象调用它,那这个时候jobject就可以看做Java类的一个实例化对象,也就是obj就是t。如果firstTest是一个静态方法,那么在Java中,它不是属于一个对象的,而是属于一个类的,Java中用Test.firstTest()这样的方式来调用,这个时候jobject就可以看做是java类的本身,也就是obj就是Test.class。


    (6)编译本地cpp生成库文件

    在cmd下进入工程目录:

     执行 ndk-build 进行编译(前提是NDK路径已经加入到Path环境变量中)


    (6)在Activity中调用本地函数库

    package com.snail.helloworld;  import android.app.Activity;  import android.os.Bundle;  import android.view.Menu;  import android.widget.TextView;    public class MainActivity extends Activity {        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);          TextView myTextField = (TextView)findViewById(R.id.myText);          myTextField.setText(myhello());       }            public native String myhello();     static {          System.loadLibrary("hello");      }       @Override      public boolean onCreateOptionsMenu(Menu menu) {          // Inflate the menu; this adds items to the action bar if it is present.          getMenuInflater().inflate(R.menu.main, menu);          return true;      }    }  
    运行,OK了.

    {方法二:} 手动生成jni文件

    (1) 新建Android工程.

    (2) 生成.h头文件

    编译工程之后,进入工程目录文件夹下,在控制台运行:
    javah -classpath bin/classes -d jni com.example.hellojni.MainAcitivity  ,然后就会在工程目录下生成一个jni文件夹,里面就会有.h的头文件了。网上很多都这么说,但实际上这里会遇到一个问题:


    1. 有人提出方法,在工程目录下运行命令:javah -classpath src -d jni com.example.hellojni.MainAcitivity 
    就OK了。是的,这个是OK的。

    2.还有一种方法:在工程目录下,上述命令中加上android.jar的classpath。也是可行的。也就是运行如下命令:javah -classpath F:\JNI\env\platforms\android-17\android.jar;bin/classes -d jni com.example.hellojni.MainActivity
    这个命令,就是把android.jar的路径加了进去。这样,就能找到Activity类了。

    头文件生成好了,刷新一下工程,就会看到如下的目录结构:


    (3) 接下来编写.c的实现文件。

    在jni文件夹右击,选择file,命名文件名字为HelloJni.c,确定。

    然后打开新建的HelloJni.c文件,输入如下语句并保存:

    #include <stdio.h>#include "HelloJni.h"jstring Java_com_example_hellojni_MainActivity_getHelloJniString  (JNIEnv * env, jobject clazz){    return (*env)->NewStringUTF(env, "Hello Jni!");}
     这里要说明 一下,在方法一中是CPP文件,方法二中是.C文件.它们在使用JNIEnv时是有区别的,即
  • (*env)->NewStringUTF(env, "Hello from JNI!");    //.c
  •  env->NewStringUTF("Hello from JNI!");    //.cpp
  • 原因:参见jni.h中对于JNIEnv的定义:

    #if defined(__cplusplus)typedef _JNIEnv JNIEnv;#elsetypedef const struct JNINativeInterface* JNIEnv;#endif
  • (4)编写mk文件,使用Cygwin编译出so文件。
    下面开始编写mk文件。在jni目录下创建一个Android.mk的文件.加入如下代码并保存.
    LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := HelloJniLOCAL_SRC_FILES := HelloJni.cinclude $(BUILD_SHARED_LIBRARY)

    这里,主要注意两个地方:
    LOCAL_MODULE    := HelloJni 。这里的HelloJni就是你的库的名字,也就是你loadLibrary的字符串。生成出来的库是libHelloJni.so。
    LOCAL_SRC_FILES := HelloJni.c 。这里的HelloJni.c就是c文件的名字。

    下面打开Cygwin,进入到工程目录下,输入如下命令,并回车:

    $NDK/ndk-build

    然后我们刷新工程,会发现,多了一个obj文件夹,和libs文件夹里面多了armeabi文件夹和里面的libHelloJni.so库。obj文件夹是没有用的,可以删掉了。

    (5)加载so文件,运行程序

    同方法一.


  •  遇到的问题:
      1. Eclipse 中没有NDK 标签
      解决:要加入一个jar包到 Eclipse文件夹下的 “plugins”下面
      http://jingyan.baidu.com/article/4d58d5413000a09dd4e9c0fe.html

      2. 在xx.cpp中加入 jni方面的代码 就报错,到处是红线
        - Type 'JNIEnv' could not be resolved
        - Type 'JNICALL' could not be resolved
      解决:是由于没有将jni.h 导入的缘故,而这个文件在ndk的目录下面。所以,参照以下步骤:
    Project Properties -> C/C++ General -> Path and Symbols
    选择include标签,Add -> $Android_NDK_HOME/platforms/android-14/arch-arm/usr/include
    且选中All languages.最后Apply -> OK
    这样错误就解决了。

  • 3. uint16  uint8    Type 'uint16' could not be resolved 
    解决: http://bbs.csdn.net/topics/330246620

  • 0 0