1. 程式人生 > >Android筆記之使用CMake進行JNI開發(Android Studio)

Android筆記之使用CMake進行JNI開發(Android Studio)

不知道有多少朋友像我一樣,被Android NDK開發的環境配置折騰到吐,然後放棄。從事Android工作幾年了,也不太願意接觸NDK開發。不過福利終於來了,新的AS中開始使用CMake開發jni,開發c跟開發java一樣簡單,你只需單純的執著於業務目標,跟折騰環境說拜拜。那我們現在就開始吧!

環境需求

要進行jni開發,AS需要以下環境:
這裡寫圖片描述

方式一、在工程建立的時候新增

首先使用AS(3.0)新建一個JniTest工程
在建立工程的過程中就有是否支援jni呼叫的選項
這裡寫圖片描述
當你把這個選項勾選上後,你會發現專案的App模組下自動就把cmake相關的內容配置好了,我們來看看與無jni呼叫的工程有什麼不同。
首先,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. # 配置so庫資訊 add_library( # Sets the name of the library. # 生成的so庫名稱,此處生成的so檔名稱是libnative-lib.so native-lib # Sets the library
as a shared library. # STATIC:靜態庫,是目標檔案的歸檔檔案,在連結其它目標的時候使用 # SHARED:動態庫,會被動態連結,在執行時被載入 # MODULE:模組庫,是不會被連結到其它目標中的外掛,但是可能會在執行時使用dlopen-系列的函式動態連結 SHARED # Provides a relative path to your source file(s). # 資原始檔,可以多個, # 資源路徑是相對路徑,相對於本CMakeLists.txt所在目錄 src/main/cpp/native-lib.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. # android系統每個型別的庫會存放一個特定的位置,而log庫存放在log-lib中 log-lib # Specifies the name of the NDK library that # you want CMake to locate. # android系統在c環境下打log到logcat的庫 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. # 目標庫 native-lib # Links the target library to the log library # included in the NDK. # 依賴於 ${log-lib} )

程式碼已經新增比較清晰的註釋,使用的時候只需要拷貝到模組目錄下,上方程式碼刪除註釋後一目瞭然,無需發愁!再看看app/build.gradle下又有什麼變化:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.test.jnitest2"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
}

主要的多了關於CMake的兩項配置:

// android下
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt" // cmake配置檔案路徑
        }
    }
// defaultConfig下
            cmake {
                cppFlags ""
                // 生成多個版本的so檔案
                abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
            }

具體的更多配置,請詳查官方文件,根據需要修改。ok,配置就這麼多,是不是很簡單。接著我們看看資源目錄:
這裡寫圖片描述

我們發現系統已經幫我們把native-lib.cpp原始檔寫好了,根據函式名可以知道,函式的native申明是在MainActivity中。我們再看看MainActivity檔案,與以前的jni呼叫方式完成一樣:

    // Used to load the 'native-lib' library on application startup.
    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()); // 發生jni呼叫
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI(); // native申明

上面的過程包括了庫的載入、native方法申明、jni方法呼叫三個過程。跟以往不同的是,你可以按住ctrl鍵滑鼠左鍵點選native方法,也能像java一樣跳轉到方法的定義了,即native-lib.cpp檔案中的Java_com_test_jnitest2_MainActivity_stringFromJNI方法。
現在我們在MainActivity中再宣告一個方法:

    public native String getStr(String s);

我們選中函式名,然後alt+enter:
這裡寫圖片描述

自動就出現了建立jni方法的選項,確定後你會在native-lib.cpp中發現函式定義框架已經寫好:
這裡寫圖片描述

so easy!你在函式中輸入env->居然提示:
這裡寫圖片描述

方式二、在專案開發過程中新增

有時候,我們的專案已經在進行中或者維護中了,突然需要使用jni呼叫怎麼辦呢?AS已經提供了相對便捷的方法。首先在要使用jni呼叫的工程模組下新建一個CMakeLists.txt:
這裡寫圖片描述
程式碼:

cmake_minimum_required(VERSION 3.6)

add_library( # Sets the name of the library.
             xjni

             # Sets the library as a shared library.
             SHARED

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

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 )

target_link_libraries( # Specifies the target library.
              xjni

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

CMakeLists.txt具體配置上面已經說過了,這個地方是去掉了註釋了的。需要注意的是,如果我們不在c原始碼檔案中輸出日誌到logcat,那麼我們是不需要依賴log庫的,也就是說find_library、target_link_libraries不是必須的。
接著配置模組支援jni呼叫,對專案模組右鍵:
這裡寫圖片描述
在彈出的提示框中選擇剛新建配置的CMakeLists.txt檔案:
這裡寫圖片描述
我們看看app/build.gradle有什麼變化:
這裡寫圖片描述
編譯完成,編譯器會報找不到XJni.c檔案錯誤。ok,那我們新建一個/app/src/main/jni/XJni.c:

#include <jni.h>

只有一行程式碼,ok,再編譯,沒問題!接下來新建jni呼叫java檔案XJni.java:

package com.test.jnitest4;

public class XJni {

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

    public native String getStr(String s);
}

getStr方法顯示錯誤紅色,不用著急,我們選中函式名,按快捷鍵alt+enter:
這裡寫圖片描述
選擇create function後,函式就自動在XJni.c檔案中生成了

#include <jni.h>

JNIEXPORT jstring JNICALL
Java_com_test_jnitest4_XJni_getStr(JNIEnv *env, jobject instance, jstring s_) {
    const char *s = (*env)->GetStringUTFChars(env, s_, 0);

    // TODO

    (*env)->ReleaseStringUTFChars(env, s_, s);

    return (*env)->NewStringUTF(env, returnValue);
}

需要注意的是,你最好讓.java檔名與.c檔名同名,否則你可能快捷鍵不會出現create function選項。修改.c檔名的時候記得對應將CMakeLists.txt中修改。

總之,JNI入門難度大大降低,AS在這方面還有很多適用的功能提供,例如debug、在c程式碼中輸入日誌到logcat等,只需簡單操作就可完成,非常人性。

相關推薦

Android筆記使用CMake進行JNI開發Android Studio

不知道有多少朋友像我一樣,被Android NDK開發的環境配置折騰到吐,然後放棄。從事Android工作幾年了,也不太願意接觸NDK開發。不過福利終於來了,新的AS中開始使用CMake開發jni,開發c跟開發java一樣簡單,你只需單純的執著於業務目標,跟折騰

手把手教你如何在Android進行JNI開發入門

在進行Android開發的過程中,我們必定會遇到視訊影象處理、高強度密集運算、特殊演算法等場景,這時我們就不得不需要去接觸一些C/C++程式碼,進行JNI開發。下面我將從Android.mk和CMake這兩種方式教大家如何進行開發。文章結尾將給出演示的專案程式碼,如果你能耐心地仔細看完,相信你一定能掌握

AndroidStudio3.0使用Cmake進行JNI開發

前言 最近專案上做到了直播和音視訊的播放,這裡不可避免的涉及到了Android JNI開發。於是去市面上找到一本資料《音視訊開發進階指南》,我看出版時間很近是2017年12月。結果遇到了大坑,裡面的所有demo都是基於eclipse。包括作者提供的原始碼也是e

AndroidVideoView 進行播放視訊 不更新

Android自帶了VideoView 一個可以播放本地視訊和網路視訊的類 所以說許可權我們一定不要忘記新增 <uses-permission android:name="android.permission.INTERNET"></uses-permi

在androidstudio中用cmake進行jni開發

    首先在建立專案的時候勾選c++支援     在建立好的專案中stuido會自動給gradle配置cmake     接下來只需要在main下面的cpp目錄中編寫你想要的c程式碼,然後引用就可以   直接通過System.loadLibrary("nati

JavaSE 學習筆記網絡編程二十三

-c 可能 nbsp blog col accept 接收 存儲 pri 端口: 物理端口: 邏輯端口:用於標識進程的邏輯地址,不同進程的標識;有效端口:0~65535,其中0~1024系統使用或保留端口。 java 中ip對象:InetAddress. import

Linux學習筆記四————Linux常用命令 待補充

-h http “.” 現實 人性化 快捷 我們 包括 無法 一、Linux命令——文件、磁盤管理 1.文件管理 <1>查看文件信息:ls ls是英文單詞list的簡寫,其功能為列出目錄的內容,是用戶最常用的命令之一,它類似於DOS下的dir命令。 Linu

ES6系列_13Proxy進行預處理簡單學習

預處理 當我 con bubuko 上下文對象 prope {} ons ive 1.理解什麽是預處理? 當我們在操作一個對象或者方法時會有幾種動作,比如:在運行函數前初始化一些數據,在改變對象值後做一些善後處理。這些都算鉤子函數,Proxy的存在就可以讓我們給函數加上這樣

《機器學習實戰》學習筆記樸素貝葉斯Naive Bayes

原理 假如郵箱中有n個單詞, 如果returnVec[i]=0代表這個單詞在這封郵件中不出現, returnVec[i]=1代表這個單詞在郵件中出現了。 設訓練集中每個郵件都有標記為是垃圾郵件和不是垃圾郵件,是垃圾郵件的分類為1,不是垃圾郵件的分類為0。 演算法原理:

Android專案開發筆記登入註冊模組實現客戶端+服務端

寫在前面   斷斷續續開發了幾個月的App終於告一段落,雖然它可能還很不完美,不過作為上手Android的第一個完整專案,確實從中學到了蠻多,所以開個系列記錄一下~本篇先從基本上每個App都會有的登入註冊講起,包含自動登入、記住密碼功能的實現=w= 實現

Android開發CriminalIntent項目開發其一

開發項目 1.0 enc 增加 委派 其他 date 應用 module 前言   這次的開發項目是一個叫做CriminalIntent的應用,該應用可以詳細記錄各種辦公室陋習。這個應用記載的陋習記錄包括標題、日期和圖片,支持在聯系人中查找當事人,通過E-mail、Twit

IDEA 學習筆記 Java項目開發深入學習1

java項目 bsp 重構 str 代碼提示 log pan ora tro Java項目開發深入學習(1): 定義編譯輸出路徑: 繼承以上工程配置 重新定義新的項目編譯路徑 添加source目錄:點擊添加,再點擊移除: 編譯項目: 常用快捷鍵總結: Ctr

android開發 OkHttp二次封裝android 訪問網路

 這個是本人在使用的一個網路請求,根據自己的需求進行修改的,對於自己完全夠用。大家有需要可以根據自己的專案修改成自己需要的。如果有什麼問題,還希望告知。 使用時繼承該類即可 import android.os.Handler; import android.os.Message;

【Visual C++】遊戲開發筆記十 基礎動畫顯示 透明動畫的實現

                作者:毛星雲    郵箱: [email protected]    歡迎郵件交流程式設計心得"透明動畫”是遊戲中一定會用到的基本技巧,它通過圖案的連續顯示及圖案本身背景的透明化處理,在背景圖上產生出栩栩如生的動畫效果。看過之前筆記的朋友們應該知道,在筆記六裡我們介紹

AndroidNDK初步開發安裝eclipse外掛支援jni開發

因為初次使用AndroidNDK開發,而且使用的是Google近乎遺棄的Eclipse,去jni開發,實在是一件實為苦惱的事,花了我2天的時間~下面把我會分2節來“完美”的說明使用eclipse進行jni開發的步驟。 首先當然是安裝NDK,這裡要說明一

Android Studio Jni開發實現Native呼叫java方法和Native呼叫Android API

這一篇主要內容是Native呼叫java方法和Native呼叫Android API,以及External Tools快速生成.h檔案,依然是使用NDK方式編譯,如果是複製貼上黨,建議跟本文用一樣的工程名,本文後面會提供demo連結 一、建立工程 1.建立名為Jnites

Android筆記圖片高斯+Glide實現微信圖片載入策略+仿微信進度條

很久以前就想自己實現一下仿微信圖片載入的那種策略了,先載入一張模糊的圖片,然後再載入清晰大圖,今天研究了一下,不過要是Glide支援進度條顯示就好了,不得不說Glide很強大, 不囉嗦了,直接上程式碼了。 首先看看高斯模糊到底怎麼實現,你問我我也不會(^__

Android基礎學習筆記-ListView進階用法item圓角效果實現

今天簡單用快取優化方式實現了listview的功能,下面讓我們實現一下上篇文章留下來的改進方案:     1).實現item佈局的圓角效果     2).對listview的item進行監聽

android使用CMake進行jni編寫遇到的一些問題

前言          android studio 2.2之後出的CMake 讓jni的編寫方便了很多,使用CMake讓我們不在煩惱函式的定義,以前我們需要通過javah命令生成,jni規定的函式名

【Visual C++】遊戲開發筆記四——遊戲畫面繪圖基本圖形繪製

毛星雲,網路ID「淺墨」,90後,熱愛遊戲開發、遊戲引擎、計算機圖形、實時渲染等技術,就職於騰訊互娛。 微軟最有價值專家 著作《Windows遊戲程式設計之從零開始》、《OpenCV3程式設計入門》 碩士就讀於南京航空航天大學航天學院(2013級碩士研究生),已於2016年三月畢業。本科