天天看點

我的NDK之旅-- (2) 第一個NDK程式(基本開發流程)前言相關概念認知工具準備第一個NDkDemo代碼分析實踐:開發流程總結

前言

完成C基本文法的學習之後,就進入了NDK的正式開發,在Android Studio2.2及以上時android支援了Android Studio + CMake來開發 NDK,我們将用這兩個工具進行NDK開發。

沒有接觸過c/c++ 基礎的可以看下我上一篇文章 我的NDK之旅– (1) c語言基礎

可以科學上網的可以參照 android官方NDK開發文檔

相關概念認知

  • 交叉編譯
    • 在一個平台上去編譯另一個平台上可以執行的本地代碼
    • 在NDK中指針對cpu平台編譯 arm x86 mips
  • .so檔案 (動态連結庫)

    編譯c或c++代碼生成的檔案

  • native 關鍵字

    本地方法聲明。

工具準備

  • 需要工具
    • NDK
    • CMake
  • 工具擷取
    1. 打開android studio 2.2 以上版本
    2. 打開settings
    3. 打開Android SDK
    4. 切換到SDK tools
    5. 勾選 CMake LLDB NDk
    6. 點選應用,等待安裝完成
      我的NDK之旅-- (2) 第一個NDK程式(基本開發流程)前言相關概念認知工具準備第一個NDkDemo代碼分析實踐:開發流程總結

CMAke :CMake是一款開源的跨平台自動化建構系統,它通過CMakeLists.txt來聲明建構的行為,控制整個編譯流程,我們在接下來的NDK開發中将會使用它配合Gradle來進行相關開發。

LLDB:LLDB是一個高效的c/c++的調試器

第一個NDkDemo

現在就讓我們打開android studio開始第一個NDK項目吧

勾選 include c++ support

我的NDK之旅-- (2) 第一個NDK程式(基本開發流程)前言相關概念認知工具準備第一個NDkDemo代碼分析實踐:開發流程總結

選擇C++ standard

我的NDK之旅-- (2) 第一個NDK程式(基本開發流程)前言相關概念認知工具準備第一個NDkDemo代碼分析實踐:開發流程總結

* 這裡選擇預設的CMake的設定

* Exceptions Support是添加C++中對于異常的處理,如果選中,Android Studio會

将 -fexceptions标志添加到子產品級build.gradle檔案的cppFlags中,Gradle會将其傳遞到CMake。

  • Runtime Type Information Support是啟用支援RTTI,如果選中,Android Studio會将-frtti标志添加到子產品級build.gradle檔案的cppFlags中,Gradle會将其傳遞到 CMake。

自動建構完成

點選Finish按鈕等待android studio 自動建構完成,運作程式即可看到效果,這樣就完成了第一個NDK項目:

我的NDK之旅-- (2) 第一個NDK程式(基本開發流程)前言相關概念認知工具準備第一個NDkDemo代碼分析實踐:開發流程總結

代碼分析

将代碼切換成Project模式

我的NDK之旅-- (2) 第一個NDK程式(基本開發流程)前言相關概念認知工具準備第一個NDkDemo代碼分析實踐:開發流程總結

代碼改變

我們可以發現在代碼中增加了CMakeLists.txt,以及main下cpp的檔案夾。接下來我們将逐個分析

CMakeLists.txt

CMakeLists.txt 是在NDK是定義打包.so 檔案建構行為

# 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.
# 設定在編譯本地庫時最小的CMake版本
cmake_minimum_required(VERSION .)


add_library( # Sets the name of the library.
            # 用來設定編譯生成的本地庫的名字為native-lib
             native-lib

             # Sets the library as a shared library.
             # SHARED表示編譯生成的是動态連結庫
             SHARED

             # Provides a relative path to your source file(s).
             # 表示參與編譯的檔案的路徑,這裡面可以寫多個檔案的路徑。
             src/main/cpp/native-lib.cpp )


# find_library:添加一些我們在編譯我們的本地庫的時候需要依賴的一些庫 ,cmake已經知道系統庫的路徑,這裡的意思是指定使用log庫,然後給log庫起别名為log-lib便于我們後面引用
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 )


# 關聯我們自己的庫和一些第三方庫或者系統庫,這裡把我們把自己的庫native-lib庫和log庫關聯起來。
target_link_libraries( # Specifies the target library.
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.

                       ${log-lib} )
           

子產品下 build.gradle

  • 在android 的defaultConfig大括号内:cmake的配置資訊如果勾選了異常支援和RTTI支援,這裡就會有相關的配置資訊。
externalNativeBuild {
    cmake {
        cppFlags ""
    }
}
           
  • android 大括号内:CMakeLists.txt檔案的路徑,這裡是指檔案相對于build.gradle檔案的位置,由于build.gradle檔案和CMakeLists.txt檔案在同一目錄下,是以此處就直接寫檔案名。
externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
           

MainActivity

  • 在靜态代碼塊中加載編譯生成的動态庫,native-lib,即我們在CMakeLists.txt檔案中指定的名稱
static {
        System.loadLibrary("native-lib");
    }
           
  • 聲明需要實作的本地方法,即 native 方法
public native String stringFromJNI();
           

FirstNDKDemo\app\src\main\cpp

#include <jni.h>
#include <string>

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_aj_firstndkdemo_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
           

cpp : 使用c++語言編寫

方法名命名規則:Java_包名類名方法名 的形式

JNIEnv *env :是JniNativeInterface這個結構體的一級指針,JniNativeInterface這個結構體定義了大量的函數指針,env 就是結構體JniNativeInterface這個結構體的二級指針,(*env)->調用結構體中的函數指針

jobject: 調用本地函數的java對象就是這個jobject

實踐:

  • 上面的demo都是由android studio 自動建構的,對于一個動手能力的強的程式猿來說肯定不夠,接下來我們就一起寫個hello world的NDK程式。
  • 首先我們在cpp檔案夾下建立一個helloworld.c ,代碼如下
    #include <jni.h>
    JNIEXPORT jstring JNICALL
    Java_com_aj_firstndkdemo_MainActivity_helloworld(JNIEnv *env, jobject instance) {
    
    return (*env)->NewStringUTF(env,"hello world !");
    }
               
    • 修改CMakeLists.txt 檔案,加入我們添加的類
      add_library( # Sets the name of the library.
              # 用來設定編譯生成的本地庫的名字為native-lib
               native-lib
      
               # Sets the library as a shared library.
               # SHARED表示編譯生成的是動态連結庫
               SHARED
      
               # Provides a relative path to your source file(s).
               # 表示參與編譯的檔案的路徑,這裡面可以寫多個檔案的路徑。
               src/main/cpp/native-lib.cpp
               src/main/cpp/helloworld.c
                )
                 
    • 在activity中聲明native方法

      ` public native String helloworld();

    • 接下來調用就好了,然後就可以運作了
    我的NDK之旅-- (2) 第一個NDK程式(基本開發流程)前言相關概念認知工具準備第一個NDkDemo代碼分析實踐:開發流程總結

    開發流程總結

    1. 在CMakeLists.txt 聲明編譯成的本地庫名字
    2. 建立c或c++檔案并在CMakeLists.txt中聲明
    3. 在java代碼中加載編譯生成的本地庫(可用靜态代碼塊)
    4. 在java中聲明需要用到的本地方法,并在對應的c檔案中根據命名規則建立對應的方法(android studio中按住Alt + Enter 可自動建立避免錯誤)

繼續閱讀