zoukankan      html  css  js  c++  java
  • AndroidStudio NDK环境3种搭建方式

    AndroidStudio NDK环境3种搭建方式

    转载。 https://blog.csdn.net/zhang_jun_ling/article/details/85621427

    一、前言

    如今Android开发IDE都是使用的AndroidStudio,之前我写过一篇文章介绍的是如何在Eclipse中搭建NDK环境 Android NDK --初始android NDK
    这边博客介绍下在AndroidStudio中搭建NDK环境的三种方式。

    二、知识点概述

    本片我们将从以下几点初步认识、创建Android NDK:
    1.Java加载/调用NDK端的代码;
    2.本地 c++代码的编写;
    3.编写构建系统文件(android.mkapplication.mk
    4.通过构建系统编译c++代码
    4.1、通过Gradle搭建NDK环境;
    4.2、通过NDKBuild搭建NDK环境(重点介绍);
    4.3、通过CMake搭建NDK环境;

    三、知识点详解

    (1)Java加载/调用NDK端的代码

    1、Java端代码:

    public class MainActivity extends AppCompatActivity {
    
        static {
            System.loadLibrary("helloworld");
        }
    
        private TextView mDataView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initView();
        }
    
        private void initView() {
            mDataView = (TextView) this.findViewById(R.id.tv_data);
            mDataView.setText(getStrFromNative());
        }
    
        private native String getStrFromNative();
    }
    
    

    2、在AndroidStudio打开命令行界面,cd app/src/main/java 运行

    javah com.zhangjunling.ndk_environment_gradle.MainActivity
    
    • 1

    这时会自动在目录下生成一个com_zhangjunling_ndk_environment_gradle_MainActivity.h文件,把文件拷贝到 main/jni 目录中。

    (2) 本地 c++代码的编写

    由于本编只是介绍NDK环境的搭建问题,所以代码越简单越容易把所有的精力都放在环境搭建上,所以c++代码只是简单的 HelloWrold程序;

    helloworld.cpp

    #include "com_zhangjunling_ndk_environment_gradle_MainActivity.h"
    
    JNIEXPORT jstring JNICALL Java_com_zhangjunling_ndk_1environment_1gradle_MainActivity_getStrFromNative
      (JNIEnv *env, jobject obj){
          return env->NewStringUTF("Hello. I'm form native");
    }
    
    

    (3)编写构建系统文件

    在jni目录下创建Android.mk、Application.mk文件内容如下:
    Android.mk

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

    Application.mk

    APP_STL := gnustl_static
    APP_ABI := armeabi
    

    关于构建系统里面的键值对的含义,现在先不关心,下篇文章我会详细介绍;

    (4)通过构建系统编译c++代码

    通过Gradle搭建NDK环境

    Gradle是androidstudio上的编译工具,我们可以通过从项目下的local.properties获取ndk.dir=xxxxxxxx,获取ndk-build路径,然后执行ndk-build便可以编译出需要的动态库文件;gradle的语法这里不在进行讲解,感兴趣的可以从网络上获取资料学习;
    build.gradle代码如下:

    import org.apache.tools.ant.taskdefs.condition.Os
    
    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 28
        defaultConfig {
            applicationId "com.zhangjunling.ndk_environment_gradle"
            minSdkVersion 19
            targetSdkVersion 28
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    
        sourceSets {
            main {
                jniLibs.srcDir 'src/main/libs'
                jni.srcDirs = []
            }
        }
    }
    
    tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn ndkBuild
    }
    
    String getNdkBuildPath() {
        Properties properties = new Properties()
        properties.load(project.rootProject.file('local.properties').newDataInputStream())
        def ndkBuildingDir = properties.getProperty("ndk.dir")
        def ndkBuildPath = ndkBuildingDir
        if (Os.isFamily(Os.FAMILY_WINDOWS)) {
            ndkBuildPath = ndkBuildingDir + '/ndk-build.cmd'
        } else {
            ndkBuildPath = ndkBuildingDir + '/ndk-build'
        }
        return ndkBuildPath
    }
    
    task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {
        println('executing ndkBuild')
        def ndkBuildPath = getNdkBuildPath();
        commandLine ndkBuildPath, '-j8', '-C', file('src/main').absolutePath
    }
    
    task ndkClean(type: Exec, description: 'clean JNI libraries') {
        println('executing ndkBuild clean')
        def ndkBuildPath = getNdkBuildPath();
        commandLine ndkBuildPath, 'clean', '-C', file('src/main').absolutePath
    }
    clean.dependsOn 'ndkClean'
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'com.android.support:appcompat-v7:28.0.0'
        implementation 'com.android.support.constraint:constraint-layout:1.1.3'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    }
    
    • 1过工具栏 Build/ReBuild Project,观察到libs目录、obj目录自动产生,没有报错。这可以说明我们的配置没有什么问题;可以运行项目看到:
    Hello. I'm form native
    
    通过NDKBuild搭建NDK环境(重点介绍)

    通过ndk-build交叉编译c++本地代码是我们重点学习的,后面我会重点介绍通过ndk-build交叉编译出我们需要的动态库。本篇只介绍环境的搭建。
    Android.mk构建好了之后,ndk-build环境就比较简单了,步骤:

    项目右键->Link C++ Project With Gradle 
    路径选择Android.mk 就OK 了。
    
    通过CMake搭建NDK环境

    CMake搭建NDK环境有两种方式:
    1、与ndk-build相同

    项目右键->Link C++ Project With Gradle 
    路径选择CMakeList.txt 就OK 了。
    

    2、在Create Android Project的时候底部勾选Include C++ support,项目创建好了之后,自动创建好了NDK环境。我们可以在此基础上开发NDK。

    项目路径:AndroidStudio环境搭建源码

     
    三种方法 app/build.gradle文件内容如下:
    import org.apache.tools.ant.taskdefs.condition.Os
    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 28
        defaultConfig {
            applicationId "com.example.myapplication"
            minSdkVersion 16
            targetSdkVersion 28
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    
            ndk {
                moduleName "Test"
                ldLibs "log"
    //          abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库,目前可有可无
            }
    
    
            // 使用Cmake工具-way1
    //start way1
    //        externalNativeBuild {
    //            cmake {
    //                cppFlags ""
    //                abiFilters 'arm64-v8a','armeabi-v7a','x86','x86_64'
    //            }
    //        }
        }
    
    //    // 配置CMakeLists.txt路径-way1
    //    externalNativeBuild {
    //        cmake {
    //            path "CMakeLists.txt"   // 设置所要编写的c源码位置,以及编译后so文件的名字
    //        }
    // end way2
    
    // 设置按android.mk 进行编译-way2
    //start way2
        externalNativeBuild {
            ndkBuild {
                path "src/main/jni/Android.mk"
            }
        }
    //end way2
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    
            }
        }
    
    //    sourceSets.main {
    //        jni.srcDirs = ['src/main/jni', 'src/main/jni/']
    //        jniLibs.srcDirs "src/main/libs"
    //    }
        sourceSets {
            main {
                jniLibs.srcDir 'src/main/libs'
                jni.srcDirs = []
            }
        }
        compileOptions {
            sourceCompatibility = '1.8'
            targetCompatibility = '1.8'
        }
        buildToolsVersion = '28.0.3'
    
    }
    /*
    //begin -- way3
    tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn ndkBuild
    }
    
    String getNdkBuildPath() {
        Properties properties = new Properties()
        properties.load(project.rootProject.file('local.properties').newDataInputStream())
        def ndkBuildingDir = properties.getProperty("ndk.dir")
        def ndkBuildPath = ndkBuildingDir
        if (Os.isFamily(Os.FAMILY_WINDOWS)) {
            ndkBuildPath = ndkBuildingDir + '/ndk-build.cmd'
        } else {
            ndkBuildPath = ndkBuildingDir + '/ndk-build'
        }
        return ndkBuildPath
    }
    
    task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {
        println('executing ndkBuild')
        def ndkBuildPath = getNdkBuildPath();
        commandLine ndkBuildPath, '-j8', '-C', file('src/main').absolutePath
    }
    
    task ndkClean(type: Exec, description: 'clean JNI libraries') {
        println('executing ndkBuild clean')
        def ndkBuildPath = getNdkBuildPath();
        commandLine ndkBuildPath, 'clean', '-C', file('src/main').absolutePath
    }
    clean.dependsOn 'ndkClean'
    //end-way3
    */
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'com.android.support:appcompat-v7:28.0.0'
        implementation 'com.android.support.constraint:constraint-layout:2.0.0-alpha4'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    }

     在app/build.gradle同目录下的CMakeLists.txt文件内容如下:

    # For more information about using CMake with Android Studio, read the
    # documentation: https://d.android.com/studio/projects/add-native-code.html
    
    # Sets the minimum version of CMake required to build the native library.
    #CMakeLists.txt
    #指定需要CMake的最小版本
    cmake_minimum_required(VERSION 3.4.1)
    # Creates and names a library, sets it as either STATIC
    # or SHARED, and provides the relative paths to its source code.
    # You can define multiple libraries, and CMake builds them for you.
    # Gradle automatically packages shared libraries with your APK.
    
    add_library( # Sets the name of the library.
                # 设置so文件名称.
                 Test
    
                 # Sets the library as a shared library.
                 SHARED
                 # 设置这个so文件为共享.
    
                 # Provides a relative path to your source file(s).
                 # 设置这个so文件的源码文件.
                 src/main/jni/Test.cpp)
    
    # Searches for a specified prebuilt library and stores the path as a
    # variable. Because CMake includes system libraries in the search path by
    # default, you only need to specify the name of the public NDK library
    # you want to add. CMake verifies that the library exists before
    # completing its build.
    
    find_library( # Sets the name of the path variable.
                  log-lib
    
                  # Specifies the name of the NDK library that
                  # you want CMake to locate.
                  log )
    
    # Specifies libraries CMake should link to your target library. You
    # can link multiple libraries, such as libraries you define in this
    # build script, prebuilt third-party libraries, or system libraries.
    
    target_link_libraries( # Specifies the target library.
                           # 制定目标库.
                           Test
    
                           # Links the target library to the log library
                           # included in the NDK.
                           ${log-lib} )

     在jni目录下的Android.mk内容如下:

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

    在jni目录下的Application.mk内容如下:

    APP_MODULES := Test
    APP_PLATFORM := android-16
    APP_ABI := all
  • 相关阅读:
    代码规范总结
    git记住提交密码的技巧
    php foreach遍历
    flight学习笔记
    the resource is not on the build path of a php project
    Google安装postman插件
    PHP开发框架CodeIgniter
    eclipse中php项目开发的环境配置说明
    MyBatis入门篇
    mybatis学习(十二)——mybatis逆向工程
  • 原文地址:https://www.cnblogs.com/it-tsz/p/10804556.html
Copyright © 2011-2022 走看看