1. 程式人生 > >在AndroidStudio中使用NDK配置方法

在AndroidStudio中使用NDK配置方法

配置Gradle生成so

在AndroidStudio2.1及以前我是通過下面的方式配置NDK的,不知道是從哪個版本開始的,我第一次在AS上使用NDK的時候用的就是AndroidStudio2.1了。

首先在gradle.properties裡面新增 Android.useDeprecatedNDK = true

android{}下的defaultconfig{}程式碼塊中新增ndk{}

ndk{
    moduleName = "xxx"
    //abiFilters("armeabi", "armeabi-v7a"..)
    //ldLibs = ["log"]
    //cFlags
    //stl(ie:gnustl_shared,stlport_static..)
}

預設在src/main/jni目錄下面找c/c++檔案編譯,也可以在android{}下新增sourceSet{}
sourceSet{
    main{
        jni.srcDirs=['src/main/cpp']
    }
}

就能將指定目錄下的c/c++檔案編譯成指定的模組名.so。

編譯多個模組

上面這種方式通過gradle無法編譯成多個模組,編譯多個模組還是要自己寫Android.mk檔案實現,通過手動執行ndk-build編譯成的*.so檔案預設在src/main/libs下面。

打包APK時,預設是尋找so的目錄是/build/intermediates/ndk和/build/intermediates/jniLibs,前者是使用原始碼由Gradle編譯成的so所處的位置,後者一般是一些第三方的so或者自己手動使用ndk編譯生成的so檔案所生成的,這個位置在src/main/jniLibs。

因此手動編譯好so檔案後,將其複製到jniLibs下面,或者在此放置第三方so,或者在build.gradle檔案裡面的android下面新增jniLib.srcDir定義了Gradle在哪裡尋找生成的so庫檔案

sourceSets{
  main{
    jniLib.srcDirs=['src/main/libs']  // jniLib.srcDirs定義了Gradle在哪裡尋找生成的so庫檔案
  }
}

上面就是使用ndk-build通過自己定義Android.mk生成so的方式,但是分析apk檔案(build->Analyze APK)發現打包進去來了兩個so,下面libnative-lib.so是我在Android.mk中設定的模組名。上面這個其實是Gradle構建的,Gradle構建so的時候預設模組名字就是app,並且預設的編譯c/c++的路徑是src/main/jni,要修改這兩個預設設定就需要像上面配置Gradle構建so的方式修改。

use_ndk--build1.png
為了在我們自己構建so的時候禁用Gradle需要做的是配置jni.srcDirs設定成一個空的陣列,這樣就可以禁用通過Gradle來編譯本地c/c++程式碼。
sourceSets{
  main{
    jni.srcDirs=[]  // jni.srcDirs禁用通過Gradle來編譯本地c/c++程式碼
  }
}

再看apk結構,由Gradle構建的so就不見了。

use_ndk--build2.png

關聯Android.mk到Gradle

AndroidStudio2.2以後的另一種使用Android.mk的方式,可以不用ndk-build手動構建。

不需要手動使用ndk-build編譯,只需要將其關聯到Gradle上,Gradle 會將 ndk-build作為一個依賴執行,然後將so打包到 apk 中,編譯好的so在目錄/build/intermediates/ndkBuild下面。

滑鼠右鍵要連結的本地庫所在的模組,選擇Link C++ Project with Gradle,在彈出的對話方塊中選擇Build System為ndk-build,再指定Amdroid.mk的路徑點選ok即可

select_ndk.png

這樣就不用在命令列中手動執行ndk-build編譯了,Gradle就會自動的構建寫好的Android.mk。

上面的操作實際是也可以直接在該模組的build.gradle中的android下面新增

android {
  ...
  defaultConfig {...}
  buildTypes {...}
  // add manually
  externalNativeBuild {
    ndkBuild {
      path "Android.mk"
      // arguments "-DCMAKE_VERBOSE_MAKEFILE=TRUE"
      // Sets optional flags for the C compiler.
      // cFlags "-D_EXAMPLE_C_FLAG1", "-D_EXAMPLE_C_FLAG2"
      // Sets a flag to enable format macro constants for the C++ compiler.
      // cppFlags "-D__STDC_FORMAT_MACROS"
    }
  }
}

使用cmake

AndroidStudio2.2以後還推出了使用cmake指令碼來構建so,方式為在模組根目錄下建立CMakeLists.txt
# Sets the minimum version of CMake required to build your native library.
# This ensures that a certain set of CMake features is available to
# your build.

cmake_minimum_required(VERSION 3.4.1)

# Specifies a library name, specifies whether the library is STATIC or
# SHARED, and provides relative paths to the source code. You can
# define multiple libraries by adding multiple add.library() commands,
# and CMake builds them for you. When you build your app, Gradle
# automatically packages shared libraries with your APK.

add_library( # Specifies the name of the library.
             native-lib

            # Sets the library as a shared library.
             SHARED

            # Provides a relative path to your source file(s).
            src/main/jni/native-lib.c )

然後和上面關聯ndk-build指令碼的方式類似,在彈出的對話方塊中選擇Build System為cmake,再指定CMakeLists.txt的位置。這樣操作類似與直接在該模組的build.gradle中的android下面新增
android {
  ...
  defaultConfig {...}
  buildTypes {...}
  // add manually
  externalNativeBuild {
    cmake {
      path "CMakeLists.txt"
    }
  }
}