Android 开发 DNK开发将.c文件打包成os 前言 第一步 创建用于引用本地os库的Java工具类 第二步 将Java工具类打包成.h文件 第三步 创建jni文件夹并且将.h文件移入 第四步 创建c语言函数文件 第五步 创建.mk文件 第六步 在build.gradle文件里添加部分代码 第七步  检查Android studio是否已经下载配置过ndk 第八步 编译SO文件 第九步 调用工具类方法,run APP

  不废话太多,Java与C之间联系的JNI的概念,这个要了解可以参考下面这个博客:

  https://www.jianshu.com/p/87ce6f565d37

  此博客只说明如何将.C文件通过NDK打包成so库并且使用的一个简单demo.

第一步 创建用于引用本地os库的Java工具类

目录

Android 开发 DNK开发将.c文件打包成os
前言
第一步 创建用于引用本地os库的Java工具类
第二步 将Java工具类打包成.h文件
第三步 创建jni文件夹并且将.h文件移入
第四步 创建c语言函数文件
第五步 创建.mk文件 
第六步 在build.gradle文件里添加部分代码
第七步  检查Android studio是否已经下载配置过ndk
第八步 编译SO文件
第九步 调用工具类方法,run APP

工具类代码

package zq.ndkdemo;

public class NDKTools {

    static {
        System.loadLibrary("ndkdemomk-jni");//这里的"ndkdemomk-jni"是下面.mk文件里局部模块的值,这个到后面我会解释
    }

    public static native String getNDKcontent();//您在Java里调用so库的静态方法
}

第二步 将Java工具类打包成.h文件

打开Android studio的Terminal准备用javah打包.h文件, cd进入到app/src/目录下 然后输入 javah -o ndkdemoHFile.h -jni -classpath ./main/java/  zq.ndkdemo.NDKTools 命令.(下面会解释这条命令)

Android 开发 DNK开发将.c文件打包成os
前言
第一步 创建用于引用本地os库的Java工具类
第二步 将Java工具类打包成.h文件
第三步 创建jni文件夹并且将.h文件移入
第四步 创建c语言函数文件
第五步 创建.mk文件 
第六步 在build.gradle文件里添加部分代码
第七步  检查Android studio是否已经下载配置过ndk
第八步 编译SO文件
第九步 调用工具类方法,run APP

解释一下这行命令

javah -o ndkdemoHFile.h -jni -classpath ./main/java/  zq.ndkdemo.NDKTools
javah -o 你要打包的.h文件名加后缀 -jni -classpath 中间的路径  app包名+工具类名

输入这条命令后,如果没报错,你就会在src目录下获得您的.h文件,如下图:

Android 开发 DNK开发将.c文件打包成os
前言
第一步 创建用于引用本地os库的Java工具类
第二步 将Java工具类打包成.h文件
第三步 创建jni文件夹并且将.h文件移入
第四步 创建c语言函数文件
第五步 创建.mk文件 
第六步 在build.gradle文件里添加部分代码
第七步  检查Android studio是否已经下载配置过ndk
第八步 编译SO文件
第九步 调用工具类方法,run APP

打开.h可以看到:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class zq_ndkdemo_NDKTools */

#ifndef _Included_zq_ndkdemo_NDKTools
#define _Included_zq_ndkdemo_NDKTools
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     zq_ndkdemo_NDKTools
 * Method:    getNDKcontent
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_zq_ndkdemo_NDKTools_getNDKcontent
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

第三步 创建jni文件夹并且将.h文件移入

在main目录下创建一个jni文件夹

Android 开发 DNK开发将.c文件打包成os
前言
第一步 创建用于引用本地os库的Java工具类
第二步 将Java工具类打包成.h文件
第三步 创建jni文件夹并且将.h文件移入
第四步 创建c语言函数文件
第五步 创建.mk文件 
第六步 在build.gradle文件里添加部分代码
第七步  检查Android studio是否已经下载配置过ndk
第八步 编译SO文件
第九步 调用工具类方法,run APP

将我们打包好的.h文件移动到jni文件夹里

Android 开发 DNK开发将.c文件打包成os
前言
第一步 创建用于引用本地os库的Java工具类
第二步 将Java工具类打包成.h文件
第三步 创建jni文件夹并且将.h文件移入
第四步 创建c语言函数文件
第五步 创建.mk文件 
第六步 在build.gradle文件里添加部分代码
第七步  检查Android studio是否已经下载配置过ndk
第八步 编译SO文件
第九步 调用工具类方法,run APP

第四步 创建c语言函数文件

进入到jni文件夹里,点击创建任意名称加.c后缀的文件

Android 开发 DNK开发将.c文件打包成os
前言
第一步 创建用于引用本地os库的Java工具类
第二步 将Java工具类打包成.h文件
第三步 创建jni文件夹并且将.h文件移入
第四步 创建c语言函数文件
第五步 创建.mk文件 
第六步 在build.gradle文件里添加部分代码
第七步  检查Android studio是否已经下载配置过ndk
第八步 编译SO文件
第九步 调用工具类方法,run APP

打开写入代码如下:

#include "ndkdemoHFile.h" 

JNIEXPORT jstring JNICALL Java_zq_ndkdemo_NDKTools_getNDKcontent
  (JNIEnv *env, jobject obj){
     return (*env)->NewStringUTF(env,"Hellow World,这是NDK的第一行代码");
  }

 注意!代码里最好别写注释特别是中文注释.

#include "ndkdemoHFile.h" 

这行代码引用的就是.h文件名称

 JNIEXPORT jstring JNICALL Java_zq_ndkdemo_NDKTools_getNDKcontent 

这行代码中 jstring 为返回值

Java_zq_ndkdemo_NDKTools_getNDKcontent  为 Java + 路径 + 类名 + 方法名称

第五步 创建.mk文件

 在jni目录下创建一个叫Android.mk的文件

Android 开发 DNK开发将.c文件打包成os
前言
第一步 创建用于引用本地os库的Java工具类
第二步 将Java工具类打包成.h文件
第三步 创建jni文件夹并且将.h文件移入
第四步 创建c语言函数文件
第五步 创建.mk文件 
第六步 在build.gradle文件里添加部分代码
第七步  检查Android studio是否已经下载配置过ndk
第八步 编译SO文件
第九步 调用工具类方法,run APP

内容如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := ndkdemomk-jni

LOCAL_SRC_FILES := ndkdemoCFile.c

include $(BUILD_SHARED_LIBRARY)

LOCAL_PATH := $(call my-dir)

每个Android.mk文件必须以定义开始。它用于在开发tree中查找源文件。宏my-dir则由Build System 提供。返回包含Android.mk目录路径。

include $(CLEAR_VARS)

CLEAR_VARS变量由Build System提供。并指向一个指定的GNU Makefile,由它负责清理很多LOCAL_xxx。例如LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_STATIC_LIBRARIES等等。但不是清理LOCAL_PATH。这个清理是必须的,因为所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能便面相互影响。

LOCAL_MODULE := ndkdemomk-jni

LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块。名字必须唯一且不包含空格。Build System 会自动添加适当的前缀和后缀。例如,demo,要生成动态库,则生成libdemo.so。但请注意:如果模块名字被定义为libabd,则生成libabc.so。不再添加前缀。另外我们一开始写的Java工具类里的System.loadLibrary("ndkdemomk-jni"); 就是这个值

OCAL_SRC_FILES := ndkdemCFile.c

这行代码表示将要打包的C/C++源码。不必列出头文件,build System 会自动帮我们找出依赖文件。缺省的C++ 源码的扩展名为.cpp。

include $(BUILD_SHARED_LIBRARY)

BUILD_SHARED_LIBRARY是Build System提供的一个变量,指向一个GUN Makefile Script。它负责收集自从上次调用include $(CLEAR_VARS)后的所有LOCAL_xxxxinx。并决定编译什么类型
  • BUILD_STATIC_LIBRARY:编译为静态库
  • BUILD_SHARED_LIBRARY:编译为动态库
  • BUILD_EXECUTABLE:编译为Native C 可执行程序
  • BUILD_PREBUILT:该模块已经预先编译

第六步 在build.gradle文件里添加部分代码

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "zq.ndkdemo"
        minSdkVersion 27
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        
        //需要添加的部分
        ndk{
            moduleName "ndkdemo-jni"
            abiFilters "armeabi-v7a", "x86"
        }


    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        //需要添加的部分
        externalNativeBuild {
            ndkBuild {
                path 'src/main/jni/Android.mk'
            }
        }
        //需要添加的部分
        sourceSets.main {
            jni.srcDirs = []
            jniLibs.srcDirs = ['src/main/jniLibs']
        }
    }
    //需要添加的部分
    sourceSets{
        main {
            jni.srcDirs = []
        }
    }

}

第七步  检查Android studio是否已经下载配置过ndk

点击local.properties打开

Android 开发 DNK开发将.c文件打包成os
前言
第一步 创建用于引用本地os库的Java工具类
第二步 将Java工具类打包成.h文件
第三步 创建jni文件夹并且将.h文件移入
第四步 创建c语言函数文件
第五步 创建.mk文件 
第六步 在build.gradle文件里添加部分代码
第七步  检查Android studio是否已经下载配置过ndk
第八步 编译SO文件
第九步 调用工具类方法,run APP

 
查看是否有ndk
ndk.dir=/media/E/tools/SDK/androidsdklinux/ndk-bundle
sdk.dir=/media/E/tools/SDK/androidsdklinux

如果没有就需要进入到File >> Settings  里下载ndk

Android 开发 DNK开发将.c文件打包成os
前言
第一步 创建用于引用本地os库的Java工具类
第二步 将Java工具类打包成.h文件
第三步 创建jni文件夹并且将.h文件移入
第四步 创建c语言函数文件
第五步 创建.mk文件 
第六步 在build.gradle文件里添加部分代码
第七步  检查Android studio是否已经下载配置过ndk
第八步 编译SO文件
第九步 调用工具类方法,run APP
 

第八步 编译SO文件

在Android studio的工具栏里,点击Build >> clean Project  先清理一下之前的编译

在点击Build >> Rebuild Project  重新创建编译文件

然后可以打开下图所示路径,就可以看到我们的so文件了

Android 开发 DNK开发将.c文件打包成os
前言
第一步 创建用于引用本地os库的Java工具类
第二步 将Java工具类打包成.h文件
第三步 创建jni文件夹并且将.h文件移入
第四步 创建c语言函数文件
第五步 创建.mk文件 
第六步 在build.gradle文件里添加部分代码
第七步  检查Android studio是否已经下载配置过ndk
第八步 编译SO文件
第九步 调用工具类方法,run APP

第九步 调用工具类方法,run APP

public class MainActivity extends AppCompatActivity {
    private TextView mDemoText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDemoText = findViewById(R.id.demo_text);
        String content = NDKTools.getNDKcontent();
        mDemoText.setText(content);
    }
}

运行APP 即可.