1. 程式人生 > >NDK在Android中的進階操作

NDK在Android中的進階操作

一、建立一個專案名字叫做JNIDemo,在專案中建立一個類名字叫做JNIDemo,我們編寫如下程式碼:

public class JNIDemo {

    //建立一個方法名字叫做sayHello
    public  native  void sayHello();

}

二、我們要生成JNIDemo類的標頭檔案,輸入命令是javah 類的全類名
,具體操作如下圖:

這裡寫圖片描述

這樣,已經生成標頭檔案,我們來檢視標頭檔案的位置.

這裡寫圖片描述

我們來檢視一下生成的標頭檔案內容:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_xgkj_jnidemo_JNIDemo */ #ifndef _Included_com_xgkj_jnidemo_JNIDemo #define _Included_com_xgkj_jnidemo_JNIDemo #ifdef __cplusplus extern "C" { #endif /* * Class: com_xgkj_jnidemo_JNIDemo * Method: sayHello * Signature: ()V; */ JNIEXPORT void JNICALL Java_com_xgkj_jnidemo_JNIDemo_sayHello (JNIEnv **, jobject); #ifdef __cplusplus
} #endif #endif

在生成標頭檔案的時候我們常遇見的問題進行總結:

(1)第一個錯誤,我們進行到 app/build/intermediates/classes中我們進行把類的全類名拷貝出來。app/build/intermediates/classes/debug/com/xgkj/jnidemo/JNIDemo.class

在上面標紅的內容中存在兩個錯誤,第一個錯誤,我們不能帶.class字尾,當我們把.class字尾去掉後去執行命令,會報錯如下圖:
這裡寫圖片描述

(2)第二個錯誤,有許多人在 app/src/包名 這個裡面進行生成標頭檔案,報錯如下圖:

這裡寫圖片描述

同時,在src中生成也是如上錯誤。

三、我們在main下面來進行建立一個jni資料夾,裡面建立一個檔案,名字叫做jnidemo.cpp

在這步我們要進行引入標頭檔案和使用的c庫。具體程式碼如下

// jnidemo.cpp : Defines the entry point for the DLL application.
//

#include "../../../src/main/jni/com_xgkj_jnidemo_JNIDemo.h"
#include <stdlib.h>
#include <jni.h>
#include <android/log.h>
#include <stdio.h>

#define  LOG_TAG    "native-dev"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

JNIEXPORT void JNICALL Java_com_xgkj_jnidemo_JNIDemo_sayHello
        (JNIEnv ** env, jobject obj){
    LOGE("Hello World");
}

(1)在引入標頭檔案的時候我們常範的錯誤

no implementation found for native應用包名 ()v

會報上述型別的錯誤,意思就是說在沒有實現該方法的簽名。那這個問題如何解決呢?

我們檢查一下我們實現生成的標頭檔案方法與生成的標頭檔案方法一樣,務必要保證實現的方法與生成的方法一樣。

四、我們要安裝一下CMake和 LLDB外掛

這裡寫圖片描述

我們按照如圖的三步操作,就可以把這兩個外掛生成出來了呢?

(1)那為什麼要安裝這兩個外掛呢?

在Android Studio中2.3版本以後我們要引用 .cpp 檔案需要建立一個CMakeLists.txt 檔案;
LLDB外掛是主要我們在建立專案的時候可以讓系統幫助我們生成CMakeLists.txt並配置好的操作。

(2)我們來介紹一下LLDB在專案建立的時候進行自動給我們生成CMakeLists.txt等相關的配置操作

步驟一:我new project ,具體的操作我們看下圖
這裡寫圖片描述

通過這三步操作,編譯器就會給我們自動生成CmakeLists.txt等相關的配置。

五、我們在app的目錄下面進行建立一個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.

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.
             sayHello #本地庫的名字,即使你即將編譯出來的.so庫名字

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/jni/jnidemo.cpp ) #C/C++在專案中的位置

# 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  #這個是新增的log輸出庫,可以進行log輸出

              # 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.
                       sayHello #輸出的目標庫

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

六、在app/build.gradle進行相關的配置

(1)app/build.gradle中進行配置,在defaultConfig中新增如下程式碼:

       ndk {
            moduleName "sayHello"
            ldLibs "log"
            abiFilters "armeabi","armeabi-v7a","x86"
        }

        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }

(2)在app/build.gradle中進行配置,在android中新增如下程式碼:

    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }

(3)進行如下圖操作:

這裡寫圖片描述

(4)編輯成功我們會在下圖看見,如下cmake檔案並在intermediates

這裡寫圖片描述

七、在MainActivity中載入.so檔案,我們可以看一下MainActivity的程式碼:

public class MainActivity extends AppCompatActivity {

    static {
        System.loadLibrary("sayHello");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        try{
            JNIDemo jniDemo = new JNIDemo();
            jniDemo.sayHello();
        }catch (Exception e){
            Log.e("JNIDemo", "onCreate: "+e.toString() );
        }

    }
}

執行成功我們可以看一下列印結果:

這裡寫圖片描述

到此,Android中NDK操作進階操作介紹完成。

下載Demo請點選此處文字:JNIDemo