<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ## C++(CPP)在Android開發中的應用 ## #### 使用純Java開發App的缺點 ### - 在某些場合下,使用純Java開發Android應用程序不完美,比如: - 有高性能算法,Java語言無法滿足 - 有跨平臺需求,希望將App移植到iOS(現在很多設計都是C語言和C++來寫底層,Android來寫界面) - 已有代碼的重用 #### 為什么使用NDK #### 1. 代碼的保護。由于apk 的java 層代碼很容易被反編譯,而C/C++庫反編譯難度較大。 2. 可以方便地使用現存的開源庫。大部分現存的開源庫都是用C/C++代碼編寫的。 3. 提高程序的執行效率。將要求高性能的應用邏輯使用C 開發,從而提高應用程序的執行效率。 4. 便于移植。用C/C++寫得庫可以方便在其他的嵌入式平臺上再次使用。 ### 引入NDK #### - 早在Android 1.6(2009年)時,google就提供了NDK(native development kit),NDK包括了一套Android的交叉編譯環境和開發庫,利用它可以編寫C/C++程序,并編譯成Android環境下使用的動態庫,Java代碼通過Jni規范,調用C/C++寫的動態庫。 - NDK - NDK是一系列工具的集合。 - 它提供了一系列的工具,幫助開發者快速開發C(或C++)的動態庫,并能自動將so和java應用一起打包成apk。這些工具對開發者的幫助是巨大的。它集成了交叉編譯器,并提供了相應的mk文件隔離CPU、平臺、ABI等差異,開發人員只需要簡單修改mk文件(指出“哪些文件需要編譯”、“編譯特性要求”等),就可以創建出so。它可以自動地將so和Java應用一起打包,極大地減輕了開發人員的打包工作。 - NDK 提供了一份穩定、功能有限的API 頭文件聲 - Google 明確聲明該API 是穩定的,在后續所有版本中都穩定支持當前發布的API。從該版本的NDK中看出,這些API 支持的功能非常有限,包含有:C 標準庫(libc)、標準數學庫(libm)、壓縮庫(libz)、Log 庫(liblog)。 - JNI - JavaNative Interface (JNI)標準是java平臺的一部分,JNI是Java語言提供的Java和C/C++相互溝通的機制,Java可以通過JNI調用本地的C/C++代碼,本地的C/C++的代碼也可以通過JNI調用java代碼。JNI 是本地編程接口,Java和C/C++互相通過的接口。Java通過C/C++使用本地的代碼的一個關鍵性原因在于C/C++代碼的高效性。 - 總結 - NDK就是為我們生成了c/c++的動態鏈接庫而已,JNI只不過是java和c溝通的工具,兩者與Android沒有半毛錢關系,只因為安卓是java程序開發然后jni又能與c溝通,所以使“Java+C”的開發方式終于轉正。 - Android是JVM架設在Linux之上的架構。所以無論如何,在Linux OS層面,都應該可以跑C/C++程序。 - Android Native C就是使用C/C++程序直接跑到Linux OS層面上的程序。與其它平臺類似,只需要交叉編譯后。并得到Linux OS root權限,就可以直接跑起來了。 - 官方定義:Android NDK 是一套允許您使用原生代碼語言(例如 C 和 C++)實現部分應用的工具集。在開發某些類型應用時,這有助于您重復使用以這些語言編寫的代碼庫。 - 目前最新的Android Studio 2.2中,集成了C/C++開發環境,開發人員在使用C/C++更加簡單了。(以前,寫Android的jni庫時,需要用到Android.mk,Application.mk這些配置,來交叉編譯) - Android.mk,負責配置如下內容: - (1) 模塊名(LOCAL_MODULE) - (2) 需要編譯的源文件(LOCAL_SRC_FILES) - (3) 依賴的第三方庫(LOCAL_STATIC_LIBRARIES,LOCAL_SHARED_LIBRARIES) - (4) 編譯/鏈接選項(LOCAL_LDLIBS、LOCAL_CFLAGS) - Application.mk,負責配置如下內容: - (1) 目標平臺的ABI類型(默認值:armeabi)(APP_ABI) - ![](https://i.imgur.com/KZFxWSR.png) - (2) Toolchains(默認值:GCC 4.8) - (3) C++標準庫類型(默認值:system)(APP_STL) - (4) release/debug模式(默認值:release) - [NDK中文官方開發技術文檔 ](https://developer.android.google.cn/ndk/index.html) - NDK下載地址 - [NDK 下載 ](https://developer.android.google.cn/ndk/downloads/index.html) - [AndroidDevTools](http://www.androiddevtools.cn/)(隨時更新官網最新版本) - [官方下載](https://developer.android.com/ndk/downloads/index.html)(需要翻墻,而且翻墻后網站的NDK版本都不是最新版本) - 網友找到的一些版本----[NDK各個版本鏈接](http://blog.csdn.net/shuzfan/article/details/52690554) - 也可以打開---AndroidDevTools網站的上各個大學的鏡像網站,找到Android,點擊repository。可以看到最新最全的各個版本(包括sdk、sdktools、platform、platform-tools、Android源碼等等官網上所持有的所有的資源),如下圖是打開的大連東軟信息學院鏡像服務器中的Android資源 - 注意:NDK的r10版本以上,就已經集成了Cygwin的UNIX虛擬機的功能,不需要安裝Cygwin的UNIX環境 - ![](https://i.imgur.com/KDcSXSQ.png) - - 下載完成,解壓到自己認為合適的目錄,**注意:目錄路徑中不能有中文和空格** ###創建NDK項目(支持 C/C++ 的新項目)(project) - 創建項目過程中,遇到問題,建議參考官網文章----[向您的項目添加 C 和 C++ 代碼](https://developer.android.com/studio/projects/add-native-code.html)(貌似需要翻墻,沒法翻墻的可以查看[在 Android Studio 2.2 中愉快地使用 C/C++ ](http://blog.csdn.net/wl9739/article/details/52607010)),而且這篇文章提到以下幾點 - Android Studio 用于構建原生庫的默認工具是 CMake。由于很多現有項目都使用構建工具包編譯其原生代碼,Android Studio 還支持 [ndk-build](https://developer.android.com/ndk/guides/ndk-build.html)。如果您想要將現有的 ndk-build 庫導入到您的 Android Studio 項目中,請參閱介紹如何配置 Gradle 以[關聯到您的原生庫](https://developer.android.com/studio/projects/add-native-code.html#link-gradle)的部分。不過,如果您在創建新的原生庫,則應使用 CMake。 - 下載 NDK 和構建工具 要為您的應用編譯和調試原生代碼,您需要以下組件: - [Android 原生開發工具包 (NDK)](https://developer.android.com/ndk/index.html):這套工具集允許您為 Android 使用 C 和 C++ 代碼,并提供眾多平臺庫,讓您可以管理原生 Activity 和訪問物理設備組件,例如傳感器和觸摸輸入。 - [CMake](https://cmake.org/):一款外部構建工具,可與 Gradle 搭配使用來構建原生庫。如果您只計劃使用 ndk-build,則不需要此組件。[使用CMake變量](https://developer.android.com/ndk/guides/cmake.html#variables) - [LLDB](http://lldb.llvm.org/):一種調試程序,Android Studio 使用它來[調試原生代碼](https://developer.android.com/studio/debug/index.html) - 您可以使用 SDK 管理器安裝這些組件: - 在打開的項目中,從菜單欄選擇 Tools > Android > SDK Manager。 - 點擊 SDK Tools 標簽。 - 選中 LLDB、CMake 和 NDK 旁的復選框,如圖所示。 - ![](https://i.imgur.com/eTN2W2Z.png) #### 創建NDK項目(支持 C/C++ 的新項目)(project)或者在一個已存在的項目中創建NDK module #### - 創建一個NDK項目 - 創建支持原生代碼的項目與創建任何其他 Android Studio 項目類似,不過還需要額外幾個步驟:把 Include C++ support的勾打上 ![](https://i.imgur.com/KLACA7L.png) - 一直next,直到出一個左邊一大白色C++的方形框時,表示這是一個C++的項目,右邊選擇C++標準,可以選擇默認的Toolchain Default,同時可以選擇C++11,因為C++11有更多的新特性和功能。,一般選擇C++11。 ![](https://i.imgur.com/24eT4pk.png) - 點擊Finish后,進入工程目錄,如圖所示,除了java文件夾外多了一個cpp文件夾,cpp就是存放c和c++代碼的文件夾,如下圖所示 ![](https://i.imgur.com/oA2Zpsi.png) - 同時,下面為CMakeLists.txt和build.gradle中的內容 - CMakeLists.txt(注釋部分已刪除) - ![](https://i.imgur.com/h3a4aqk.png) - build.gradle中的內容 - ![](https://i.imgur.com/4lDDu2j.gif) - PS:如果在創建project時,沒有勾選,就只是一個簡單的AS的Android項目,這時如果想要創建C++項目,可以參考下面的在module中 - 如何在一個module中添加CPP組件,創建原生源文件 - 一般,我們的項目創建時并不是一個C++項目,而是一個Android普通的項目,如果需要用到NDK,JNI方面的,這時就需要添加CPP組件,原生源文件,之前都是用ndk-build命令來進行NDK開發,所以正如上面這篇文章(向您的項目添加 C 和 C++ 代碼)所述---->由于很多現有項目都使用構建工具包編譯其原生代碼,Android Studio 還支持 ndk-build(已非主流,過時)。如果您想要將現有的 ndk-build 庫導入到您的 Android Studio 項目中,請參閱介紹如何配置 Gradle 以關聯到您的原生庫的部分。不過,如果您在創建新的原生庫,則應使用 CMake。但是還是推薦使用CMake,因為在Android2.2以后的版本,進行JNI開發,更方便 - 同樣,我們需要認真閱讀[《向您的項目添加 C 和 C++ 代碼》](https://developer.android.com/studio/projects/add-native-code.html)的---->”向現有項目添加 C/C++ 代碼“這一小章節,注意CMake構建的腳本 CMakeLists.txt中的內容和build.gradle中的注意細節,一定要認真閱讀[《向您的項目添加 C 和 C++ 代碼》](https://developer.android.com/studio/projects/add-native-code.html),或者可以參考上面創建C++項目的build.gradle和CMakeLists.txt中的內容。 #### 添加 NDK API #### - Android NDK 提供了一套實用的原生 API 和庫。通過將 [NDK 庫](https://developer.android.com/ndk/guides/stable_apis.html)包含到項目的 CMakeLists.txt 腳本文件中,您可以使用這些 API 中的任意一種。 - [NDK 庫(Android NDK 原生 API)](https://developer.android.com/ndk/guides/stable_apis.html) - [概覽](https://developer.android.com/ndk/guides/stable_apis.html#purpose) - [主要的原生 API 更新](https://developer.android.com/ndk/guides/stable_apis.html#mnu)([Android平臺版本對應的API等級](https://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels)) - [Android API 級別 3](https://developer.android.com/ndk/guides/stable_apis.html#a3) - [Android API 級別 4](https://developer.android.com/ndk/guides/stable_apis.html#a4) - [Android API 級別 5](https://developer.android.com/ndk/guides/stable_apis.html#a5) - [Android API 級別 8](https://developer.android.com/ndk/guides/stable_apis.html#a8) - [Android API 級別 9](https://developer.android.com/ndk/guides/stable_apis.html#a9) - 從 API 級別 9 開始,您可以使用原生代碼編寫整個 Android 應用,無需使用任何 Java。注:在原生代碼中編寫您的應用本身并不能讓您的應用在 VM 中運行。 此外,您的應用仍必須通過 JNI 訪問 Android 平臺的大部分功能 - [Android API 級別 14](https://developer.android.com/ndk/guides/stable_apis.html#a14) - [Android API 級別 18 ](https://developer.android.com/ndk/guides/stable_apis.html#a18) #### JNI規范 #### - 在進行NDK開發時,閱讀官網的《[向您的項目添加 C 和 C++ 代碼](https://developer.android.com/studio/projects/add-native-code.html)》涉及到的[Android 的 JNI 提示](https://developer.android.com/training/articles/perf-jni.html),而在[Android 的 JNI 提示](https://developer.android.com/training/articles/perf-jni.html)中又涉及到了[JNI規范](http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html),來了解JNI如何工作,以及JNI的特點。 - 早已有大神將官方的文檔翻譯(可以說是摘抄)到自己的博客了 - [《Java 本地接口規范》](http://blog.csdn.net/zhanghw0917/article/details/7000377) - [《Java 本地接口規范》- 簡介 ](http://blog.csdn.net/snowdream86/article/details/6886954) - [已整理的目錄篇](http://116.196.111.149:8080/jni.htm) #### APK分析儀 #### - 如果您想要驗證 Gradle 是否已將原生庫打包到 APK 中,可以使用[APK分析器 ](https://developer.android.com/studio/build/apk-analyzer.html) - 步驟 - 選擇 Build > Analyze APK。 - 從 app/build/outputs/apk/ 目錄中選擇 APK 并點擊 OK。 - 如下圖所示,您會在 APK 分析器窗口的 lib/<ABI>/ 下看到 編譯好的動態庫`libnative-lib.so`。 - ![](https://i.imgur.com/G3HpvJz.png) - 提示:如果您想要試驗使用原生代碼的其他 Android應用,請點擊 File>New>Import Sample 并從Ndk列表中選擇示例項目。 #### 指定 ABI #### - APP_ABI - ABI全稱是:Application binary interface,即:應用程序二進制接口,它定義了一套規則,允許編譯好的二進制目標代碼在所有兼容該ABI的操作系統和硬件平臺中無需改動就能運行。(具體的定義請參考 [百度百科](https://baike.baidu.com/item/ABI/10912305#viewPageContent) 或者 維基百科 ) - 由上述定義可以判斷,ABI定義了規則,而具體的實現則是由編譯器、CPU、操作系統共同來完成的。不同的CPU芯片(如:ARM、Intel x86、MIPS)支持不同的ABI架構,常見的ABI類型包括:armeabi,armeabi-v7a,x86,x86_64,mips,mips64,arm64-v8a等。 - 這就是為什么我們編譯出來的可以運行于Windows的二進制程序不能運行于Mac OS/Linux/Android平臺了,因為CPU芯片和操作系統均不相同,支持的ABI類型也不一樣,因此無法識別對方的二進制程序。 - 而我們所說的“**交叉編譯**(在一個平臺上去編譯另一個平臺上可以執行的本地代碼)”的核心原理也跟這些密切相關,交叉編譯,就是使用交叉編譯工具,在一個平臺上編譯生成另一個平臺上的二進制可執行程序,為什么可以做到?因為交叉編譯工具實現了另一個平臺所定義的ABI規則。我們在Windows/Linux平臺使用Android NDK交叉編譯工具來編譯出Android平臺的庫也是這個道理。 - 支持的 ABI(每個 ABI 支持一個或多個指令集。下圖提供每個 ABI 支持的指令集概覽。) - ![](https://i.imgur.com/DzKrRs9.png) - 默認情況下,Gradle 會針對 [NDK 支持的 ABI](https://developer.android.com/ndk/guides/abis.html#sa) 將您的原生庫構建到單獨的 .so 文件中,并將其全部打包到您的 APK 中。如果您希望 Gradle 僅構建和打包原生庫的特定 ABI 配置,您可以在模塊級 build.gradle 文件中defaultConfig節點內使用 ndk.abiFilters 標志指定這些配置,如下所示: ![](https://i.imgur.com/9Ot21no.png) - 在大多數情況下,您只需要在 ndk {} 塊中指定 abiFilters(如上所示),因為它會指示 Gradle 構建和打包原生庫的這些版本。不過,如果您希望控制 Gradle 應當構建的配置,并獨立于您希望其打包到 APK 中的配置,請在 defaultConfig.externalNativeBuild.cmake {} 塊(或 defaultConfig.externalNativeBuild.ndkBuild {} 塊中)配置另一個 abiFilters 標志。Gradle 會構建這些 ABI 配置,不過僅會打包您在 defaultConfig.ndk{} 塊中指定的配置。 - 為了進一步降低 APK 的大小,請考慮[配置 ABI APK 拆分](https://developer.android.com/studio/build/configure-apk-splits.html#configure-abi-split),而不是創建一個包含原生庫所有版本的大型 APK,Gradle 會為您想要支持的每個 ABI 創建單獨的 APK,并且僅打包每個 ABI 需要的文件。如果您配置 ABI 拆分,但沒有像上面的代碼示例一樣指定 abiFilters 標志,Gradle 會構建原生庫的所有受支持 ABI 版本,不過僅會打包您在 ABI 拆分配置中指定的版本。為了避免構建您不想要的原生庫版本,請為 abiFilters 標志和 ABI 拆分配置提供相同的 ABI 列表。 #### 從 ndkCompile 遷移 #### - 如果您使用已過時的ndkCompile ,你應該遷移---使用 CMake 或 ndk-build 生成。因為ndkCompile生成的中間文件Android.mk 給你,遷移到ndk-build 可能是一個簡單的選擇。 - 從ndkCompile遷移到ndk-build,進行如下操作: 1. 使用ndkCompile,至少一次,通過Build > Make Project, 來編譯項目,這將為您生成Android.mk文件。 2. 通過 `project-root/module-root/build/intermediates/ndk/debug/Android.mk. `到找到的自動生成的Android.mk 文件。 3. 遷移Android.mk 文件到其他的目錄,比如和module下的build.gradle同一等級的目錄,這將確保 clean時,Gradle 并不會刪除該腳本文件, 4. 打開Android.mk文件并編輯腳本中的任何路徑,這樣,他們是相對于當前腳本文件的位置。 5. [Link Gradle to the Android.mk file. ](https://developer.android.com/studio/projects/add-native-code.html#link-gradle) 6. 禁用ndkCompile 通過打開build.properties文件并刪除以下行:`android.useDeprecatedNdk = true` 7. 通過單擊工具欄中的Sync Project ![](https://i.imgur.com/dISdrfs.png),應用這些改變。 #### 需要注意的幾點 #### - CMakeLists.txt腳本文件,`Android.mk`,`Application.mk`,這2個文件全是通過CMakeLists.txt來寫;如果項目目錄的CPP文件夾下有N個原生源文件,那么CMakeLists.txt中的add_library中就要對應有N個路徑,類似于native-lib.cpp ,對應的add_library就對應的`src/main/cpp/native-lib.cpp`,如果CPP有test.cpp,則add_library對應有`src/main/cpp/test.cpp`;這就是編譯的配置,而且相互之間空格隔開; - 這配置和module目錄下的build.gradle的`android--->externalNativeBuild--->cmake--->path "CMakeLists.txt",`編譯build時,通過這個路徑path,找到CMakeLists.txt里面的構建命令,這是相互對應的。CMake是Unix自動化固件,跨平臺 - find_library是鏈接靜態庫,如果有其他的.so庫,就寫在find_library節點內。 - 在使用Cmake插件之前,是在module目錄下的build.gradle中配置NDK選項,以后就不需要在module目錄下的build.gradle中NDK,因為這些操作,都在CMakeLists.txt中配置好了 #### 具體的創建工程 #### - JNI知識總結 - cpp中原生源文件(.c、.cpp)方法名的命名規則 - 這里的命名規則只適用于跟java 文件中的native 方法相對應C 語言函數,而C 語言中的其他函數命名只要符合C 語言規則就行。java 文件中的native 方法有N個,對應的源文件中就有N個函數,來實現native方法。 - C++調用Java #### Java和C++字符串轉換 #### - JNI 基本類型和本地等效類型的對應表格如下: ![](https://i.imgur.com/oBMdtIY.png) - 引用類型,JNI 還包含了很對對應于不同Java 對象的引用類型,JNI 引用類型的組織層次如下圖 ![](https://i.imgur.com/DfLShli.png) - Java中任何一種類型,在Jni中都有一種對應的類型,比如:String--->jstring,但是Java中String是雙字節的,在C++中不是雙字節的,這就涉及到一個字符串轉換,編碼的轉換 - string轉換為jstring ~~~ jstring c2j(JNIEnv* env, string cstr) { return env->NewStringUTF(cstr.c_str()); } ~~~ - jstring轉換為string ~~~ string j2c(JNIEnv* env, jstring jstr) { string ret; jclass stringClass = env->FindClass("java/lang/String"); jmethodID getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B"); // 把參數用到的字符串轉化成java的字符 jstring arg = c2j(env, "utf-8"); jbyteArray jbytes = (jbyteArray)env->CallObjectMethod(jstr, getBytes, arg); // 從jbytes中,提取UTF8格式的內容 jsize byteLen = env->GetArrayLength(jbytes); jbyte* JBuffer = env->GetByteArrayElements(jbytes, JNI_FALSE); // 將內容拷貝到C++內存中 if(byteLen > 0) { char* buf = (char*)JBuffer; std::copy(buf, buf+byteLen, back_inserter(ret)); } // 釋放 env->ReleaseByteArrayElements(jbytes, JBuffer, 0); return ret; } ~~~ - jstring轉換成c語言的char* 類型 ![](https://i.imgur.com/5jKKxay.png) #### javah和javap - javah - 開發時,Java代碼中native聲明了本地方法,由于本地方法沒有方法體,需要到cpp文件中完善對應的本地方法,但是cpp中原生源文件(.c、.cpp)對應本地方法的方法名的命名很麻煩,如果一個一個來寫,可能會出錯,這時,可以使用javah來生成一個頭文件,該頭文件中直接寫好了Java代碼的本地方法對應的cpp中方法命名,可以直接復制到cpp文件中,這樣便捷高效。 - javah用于生成native接口定義,比如`javah com.wsc.wangsc.ndktest.Jni ` - ![](https://i.imgur.com/RgmTGee.png) - ![](https://i.imgur.com/OBXEJaw.png) - jni類中native方法和.h頭文件中對應的方法如下圖紅色方框 - ![](https://i.imgur.com/o7n4Sex.png) - ![](https://i.imgur.com/oZyD6XB.png) - 這樣可以直接復制.h頭文件中方法命名到cpp文件中 - javap - javap作用 1. 反編譯 2. 生成函數簽名 - javap用于生成java函數的簽名,比如 `javap -s Jni`
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看