• Android 开发 DNK开发将.c文件打包成os


    前言

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

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

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

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

    目录

    工具类代码

    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 命令.(下面会解释这条命令)

    解释一下这行命令

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

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

    打开.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文件夹

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

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

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

    打开写入代码如下:

    #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的文件

    内容如下:

    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打开

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

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

     

    第八步 编译SO文件

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

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

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

    第九步 调用工具类方法,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 即可.

  • 相关阅读:
    第三次作业
    第二次作业
    第一次作业—编译原理概述
    第六次课堂作业——正规文法与正规式
    词法分析程序的设计与实现
    1702第四次作业(文法和语文总结与梳理)
    1702第三次作业(语法树,短语,直接短语,句柄)
    软工1702第一次作业(简述编译程序)
    random库的使用
    基本的字符串之切片
  • 原文地址:https://www.cnblogs.com/guanxinjing/p/10959567.html
Copyright © 2020-2023  润新知