Android_ndk_jni_hello-jni_hacking

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: /*************************************************************************** * Android_ndk_jni_hello-jni_hacking * 声明: * 1.
/***************************************************************************
 *                      Android_ndk_jni_hello-jni_hacking 
 *  声明:
 *      1. 本文用的是android-2.2_froyo的源代码;
 *      2. 本文仅仅是对Android自带的ndk中的samples中的jni_hello示例的解读;
 *      3. 本文更多的是想通过这个自带的简单示例来了解jni的框架结构,所以没
 *          有提供除此之外的更多的内容解读.  :)
 *
 *                      2015-4-19 周日 晴 深圳 南山 西丽平山村 曾剑锋
 **************************************************************************/

        \\\\\\\\\\\\\\\\\\\\\\\\* 目录 */////////////////////////
        |  一. 参考文章:                                        |
        |  二. 分析源码来源及文件结构:                          |
        |  三. 解析流程:                                        |
        |  四. 解析src/com/example/hellojni/HelloJni.java文件:  |
        |  五. 解析jni/Android.mk文件:                          |
        |  六. 解析jni/hello-jni.c文件:                         |
        \\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////
        
一. 参考文章:
    主要参考ndk自带的文档(ndk根目录下的docs文件夹):
    .
    |-- ANDROID-MK.TXT
    |-- APPLICATION-MK.TXT
    |-- CHANGES.TXT
    |-- CPU-ARCH-ABIS.TXT
    |-- CPU-ARM-NEON.TXT
    |-- CPU-FEATURES.TXT
    |-- DEVELOPMENT.TXT
    |-- HOWTO.TXT
    |-- INSTALL.TXT
    |-- LICENSES.TXT
    |-- NDK-BUILD.TXT
    |-- NDK-GDB.TXT
    |-- OVERVIEW.TXT
    |-- STABLE-APIS.TXT
    `-- SYSTEM-ISSUES.TXT
    
二. 分析源码来源及文件结构:
    1. 本文是用NDK自带的samples中的hello-jni来分析jni的编写流程;
    2. NDK提供的hello-jni示例文件结构:
        .
        |-- AndroidManifest.xml
        |-- default.properties
        |-- jni
        |   |-- Android.mk                              ---> jni makefile
        |   |-- Android_ndk_jni_hello-jni_hacking.c
        |   `-- hello-jni.c                             ---> jni C文件
        |-- libs
        |   `-- armeabi
        |-- res
        |   `-- values
        |       `-- strings.xml
        `-- src
            `-- com
                `-- example
                    `-- hellojni
                        `-- HelloJni.java               ---> java源文件
    3. 从文件结构上分析可知,这是一个Android工程项目;

三. 解析流程:
    1. 本文采用java程序-->jni接口-->C程序的解析流程,这也比较符合常规需求分析;
    2. 解析文件流程:
        1. src/com/example/hellojni/HelloJni.java
        2. jni/Android.mk
        3. jni/hello-jni.c

四. 解析src/com/example/hellojni/HelloJni.java文件:
    1. cat src/com/example/hellojni/HelloJni.java
        ......
        package com.example.hellojni;    //javah会利用包名生成jni C函数名

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

        public class HelloJni extends Activity
        {
            /** Called when the activity is first created. */
            @Override
            public void onCreate(Bundle savedInstanceState)
            {
                super.onCreate(savedInstanceState);

                /* Create a TextView and set its content.
                 * the text is retrieved by calling a native
                 * function.
                 */
                TextView  tv = new TextView(this);
                tv.setText( stringFromJNI() );
                setContentView(tv);
            }

            /* A native method that is implemented by the
             * 'hello-jni' native library, which is packaged
             * with this application.
             */
            /**
             * 这个本地方法在hello-jni库中已经实现了, 
             * 并且hello-jni库,已经被打包进这个应用里.
             */
            public native String  stringFromJNI(); //本地方法声明方式,多加个native

            /* This is another native method declaration that is *not*
             * implemented by 'hello-jni'. This is simply to show that
             * you can declare as many native methods in your Java code
             * as you want, their implementation is searched in the
             * currently loaded native libraries only the first time
             * you call them.
             *
             * Trying to call this function will result in a
             * java.lang.UnsatisfiedLinkError exception !
             */
            /**
             * 这是另一个本地方法,但是没有在hello-jni库中实现,
             * 这仅仅是为了告诉你,你可以声明很多本地方法在你的Java
             * 代码中,只有当你调用这个函数的时候,才会去查找这个本地
             * 是否实现了.
             *
             * 如果你去调用这个没有实现的本地方法,你将会得到:
             * java.lang.UnsatisfiedLinkError异常.
             */
            public native String  unimplementedStringFromJNI();

            /* this is used to load the 'hello-jni' library on application
             * startup. The library has already been unpacked into
             * /data/data/com.example.HelloJni/lib/libhello-jni.so at
             * installation time by the package manager.
             */
            /**
             * 在应用程序启动的时候加载hello-jni库.这个库在你的安装这个app的
             * 时候已经解压放到了/data/data/com.example.HelloJni/lib/libhello-jni.so
             */
            static {
                System.loadLibrary("hello-jni");        //本地方法所在的库文件名
            }
        }
    2. 获取jni头文件的方法:
        1. 我们一般会觉得,拿着工程中的.class文件就可以直接获取jni头文件: javah HelloJni,
            经过测试,结果是不行的.
        2. 将HelloJni.class要放在com/example/hellojni文件夹下,在android的工程bin目录下
            是这么放置的,个人猜测是为了得到包名.
        3. 在com目录下的同一级目录下执行: javah com.example.hellojni.HelloJni,这样就可以
            获得文件: com_example_hellojni_HelloJni.h,也就是我们想要的头文件.
4. 在src目录也是可以直接用javah来获取jni头文件的,尤其是遇到javah 找不到类Android.app.Activity的时候可以一试.
.
            

五. 解析jni/Android.mk文件:
    1. cat jni/Android.mk
        ......
        /**
         * Android.mk文件,必须在开始就定义LOCAL_PATH变量,指定源文件的目录,
         * my-dir这个宏函数,是由系统提供的,会返回当前文件夹的绝对路径
         */
        LOCAL_PATH := $(call my-dir)

        /**
         * CLEAR_VARS是由系统提供的变量,会清空绝大多数的的LOCAL_XXX变量,
         * 但是LOCAL_PATH是一个例外
         */
        include $(CLEAR_VARS)

        /**
         * 定义模块名,生成的共享库,会自动加上lib前缀,和.so后缀
         */
        LOCAL_MODULE    := hello-jni
        /**
         * 指定生成模块的所需要的C/C++源文件,不需要列出头文件
         */
        LOCAL_SRC_FILES := hello-jni.c

        /**
         * BUILD_SHARED_LIBRARY是由系统提供的变量,这个是用创建出一个动态
         * 共享库的方式,还有一种生成静态库的变量是:BUILD_STATIC_LIBRARY
         */
        include $(BUILD_SHARED_LIBRARY)

六. 解析jni/hello-jni.c文件:
    1. cat jni/hello-jni.c
        ......
        #include <string.h>
        #include <jni.h>

        /* This is a trivial JNI example where we use a native method
         * to return a new VM String. See the corresponding Java source
         * file located at:
         *
         *   apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java
         */
        /**
         * 在这个简单的JNI示例中,我们是用了一个本地方法返回一个新的VM字符串
         */
        jstring
        Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                          jobject thiz )
        {
            return (*env)->NewStringUTF(env, "Hello from JNI !");
        }
    2. JNI命名规则:
        1. 前缀:     Java
        2. 类的包名: 上例是---com.example.hellojni
        3. 类名:     上例是---HelloJni
        4. 方法名:   上例是---stringFromJNI
        5. 第一个参数: JNIEnv* env
        6. 第二个参数: jobject thiz
        7. 实际的Java参数: 上例没有
        8. 返回值的参数:   上例没有
    3. 如果第一次写jni函数,尤其是当我们很多时候工作中是复制别人的函数内容的时候,
        很可能会忘记了给自动生成的jni头文件函数声明的参数起名字,您可能回到如下
        错误(这是本人生成另一个共享库犯的低级错误 :) ),错误原因也指出来了:
        APLEX@APLEX-PC /cygdrive/e/android_app/myserial
        $ $NDK/ndk-build
        Android NDK: WARNING: APP_PLATFORM android-18 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml
        [armeabi] Compile thumb  : serialPort <= SerialPort.c
        jni/SerialPort.c: In function 'Java_com_android_aplex_SerialPort_open':
        jni/SerialPort.c:77:3: error: parameter name omitted    ---> 省略了参数名称
           (JNIEnv *, jclass, jstring, jint, jint)
           ^
        jni/SerialPort.c:77:3: error: parameter name omitted
        jni/SerialPort.c:77:3: error: parameter name omitted
        jni/SerialPort.c:77:3: error: parameter name omitted
        jni/SerialPort.c:77:3: error: parameter name omitted
        jni/SerialPort.c: In function 'Java_com_android_aplex_SerialPort_close':
        jni/SerialPort.c:155:3: error: parameter name omitted   ---> 省略了参数名称
           (JNIEnv *, jobject)
           ^
        jni/SerialPort.c:155:3: error: parameter name omitted   ---> 省略了参数名称
        /cygdrive/d/ndk/android-ndk-r10d/build/core/build-binary.mk:455: recipe for target 'obj/local/armeabi/objs/serialPort/SerialPort.o' failed
        make: *** [obj/local/armeabi/objs/serialPort/SerialPort.o] Error 1

 

目录
相关文章
|
Web App开发 机器学习/深度学习 Java
Android C++系列:认识JNI
JNI不仅仅是Android特有的,它是属于Java平台的,它允许在Java虚拟机内运行的java代码与其他编程语言(如c, c++和汇编语言)编写的程序和库进行交互。Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是并不是说不能使用其他编程语言,只要调用约定受支持就可以了。不同语言编写的程序之间调用也不是Java和C++特有的,Java可以调用C++,python、go语言都可以。
143 0
|
Java Android开发 C++
android 源码下的JNI编译
android 源码下的JNI编译
221 0
|
Java 编译器 Android开发
使用NDK和Android.mk进行JNI开发
使用NDK和Android.mk进行JNI开发
221 0
|
编译器 Linux Android开发
Android:JNI与NDK(二)交叉编译与动态库,静态库
Android:JNI与NDK(二)交叉编译与动态库,静态库本篇目录 一、前言本篇主要以window开发环境为背景介绍一下NDK开发中需要掌握的交叉编译等基础知识,选window系统主要是照顾大多数读者,mac ,linux操作系统基本是同样适用的。
2084 0
|
Android开发
Android JNI相关
1). 打印jstring #include #define TAG "AES_CPP" #define LOGD(FORMAT, ...) __android_log_print(ANDROID_LOG_DEBUG,TAG,FORMAT,##__...
1088 0
|
Android开发 C++ Windows
|
Linux Android开发 Windows
|
Java 开发工具 Android开发
Android JNI遇到的问题
ndk编译时异常: D:\java\androidstudio\sdk\ndk-bundle>ndk-build.cmd Android NDK: Could not find application project directory ! Andro...
1114 0
|
算法 Java API
Android JNI 和 NDK
  1、Android NDK  一、NDK产生的背景   Android平台从诞生起,就已经支持C、C++开发。众所周知,Android的SDK基于Java实现,这意味着基于Android SDK进行开发的第三方应用都必须使用Java语言。
1333 0
|
Java Linux Android开发
android JNI的.so库调用
在一篇博客中看到一篇文章,感觉描述的还可以: 在前面的博客中介绍的都是使用java开发Android应用,这篇博客将介绍java通过使用jni调用c语言做开发 为了更加形象的介绍jni,先观察下面的图片,下图表示的是整个android系统架构 图中从上到下的结构依次是:Applicati...
1199 0