Android NDK開發-靜態注冊JNI Demo(二)

上文我們已經介紹了如何配置android studio環境來開發NDK,本篇實戰開發,寫一個簡單的Demo。

  • MainActivity.java
public class MainActivity extends AppCompatActivity {

    // 用于在應用程序啟動時加載“native-lib”庫。
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }
    //使用C/C++實現
    public native String stringFromJNI();
}

使用上篇介紹的javah -jni命令工具可以生成頭com_example_lynnlee_ndkdemo_MainActivity.h文件

  • com_example_lynnlee_ndkdemo_MainActivity.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_lynnlee_ndkdemo_MainActivity */

#ifndef _Included_com_example_lynnlee_ndkdemo_MainActivity
#define _Included_com_example_lynnlee_ndkdemo_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_lynnlee_ndkdemo_MainActivity
 * Method:    stringFromJNI
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_lynnlee_ndkdemo_MainActivity_stringFromJNI
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

函數名Java_com_example_lynnlee_ndkdemo_MainActivity_stringFromJNI組成:類名_方法名組成。參數JNIEnv *和jobject必須有,JNIEnv之jvm指針,jobject指調用該函數的java類引用。

在jni目錄下新建jnitest.c文件,剛才com_example_lynnlee_ndkdemo_MainActivity.h名字太長,改為jnitest.h。

//
// Created by LynnLee on 2018/8/5.
//
#include "jnitest.h"

JNIEXPORT jstring JNICALL Java_com_example_lynnlee_ndkdemo_MainActivity_stringFromJNI(JNIEnv *env, jobject obj)
{
    return (*env)->NewStringUTF(env, "LynnLee");
}

函數實現就返回了一個"LynnLee"字符串

在jni目錄下新建Android.mk文件,Android.mk文件是Android 的makefile文件

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := native-lib
LOCAL_SRC_FILES := jnitest.c
include $(BUILD_SHARED_LIBRARY)
  • LOCAL_PATH := $(call my-dir)

宏函數’my-dir’由編譯系統提供,返回當前包含Android.mk文件的目錄路徑

  • include $(CLEAR_VARS)

CLEAR_VARS由編譯系統提供,清除除LOCAL_PATH以外的其它LOCAL_XXX變量

  • LOCAL_MODULE :=native-lib

編譯的目標對象,LOCAL_MODULE變量必須定義,以標識你在Android.mk文件中描述的每個模塊。名稱必須是唯一的,而且不包含任何空格。
注意:編譯系統會自動產生合適的前綴和后綴,換句話說,一個被命名為native-lib的共享庫模塊,將會生成'libnative-lib.so'文件。

  • LOCAL_SRC_FILES :=hello-jni.c
    LOCAL_SRC_FILES變量必須包含將要編譯打包進模塊中的C/C++源代碼文件。這里不需要列出頭文件和包含文件,因為編譯系統將會自動為你找出依賴型的文件,僅僅列出直接傳遞給編譯器的源代碼文件就好。

include $(BUILD_SHARED_LIBRARY)

指定編譯出的庫類型1.BUILD_SHARED_LIBRARY:動態庫;2.BUILD_STATIC_LIBRARY:靜態庫;3.BUILD_EXECUTEABLE指:可執行文件

Application.mk

APP_ABI := all

APP_ABI有四種類型(默認armeabi),armeabi、armeabi-v7a、x86、mips,設置時以空格隔開,all表示所有。

生成庫

需要修改app/CMakeLists.txt文件,修改如下:


CMakeLists.txt.png

利用上篇創建的ndk -build命令工具生成庫


so庫.png

使用庫

  • 1.在main/libs目錄下生成的so文件(名字為lib+我們指定的庫名)復制到app/libs目錄下,并且在gradle添加加載so庫的設置,如下代碼:
sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
  • 2.刪除main目錄下jni、libs、obj三個文件夾。修改gradle文件,注釋掉如下代碼:
/*externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }*/

否則報錯:


錯誤.png

gradle修改如下圖


gradle.png
  • 3.然后在Activity中測試調用,在TextView上顯示我們通過C++代碼實現的方法getPackname獲取app的包名了。
運行效果.png

git代碼路徑:https://github.com/lynnleescz/NDKdemo

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。