android ndk-build 編譯靜態庫libxx.a 以及Android studio openssl 靜態庫配置(cmake)

android ndk-build 編譯靜態庫libxx.ajava

需求場景:android

目前有安卓編碼好的如今的openssl的兩個.a,咱們須要調用openssl的函數,並把功能再封裝成.a;app

這樣使用時,在android studio jni項目 cmake 裏面,須要先引用openssl的.a再引用 上面封裝的.a;ide

若是使用so,那麼,直接在android studio jni項目的 cpp裏面直接調用openssl的方法,對外提供jni java接口,打包成so便可;函數

 

先來講用ndk-build 打包 libxx.a吧,並在打包的時候引用openssl的靜態庫.a測試

1. 首先當前目錄下準備好 編碼好的openssl靜態庫,以下圖示,安卓平臺的gradle

   

2. 測試使用的源文件,我這裏在.h聲明一個封裝的方法 ssl_sha,而且在.c 實現裏面,調用 openssl 的SHA256接口;以下 ui

  加 #ifdef __cplusplus 是爲了在jni調用時,cpp裏面出現未定義的錯誤,以下 ssl_hash.hthis

#ifndef ssl_hash_h
#define ssl_hash_h


# ifdef  __cplusplus
extern "C" {
#endif


#include <stdio.h>

/*
 * openssl sha256
 * */
int ssl_sha256(const char *in_data,int in_len,char *out_hash);


# ifdef  __cplusplus
}
# endif


#endif /* ssl_hash_h */

 

 以下 ssl_hash.c 實現文件編碼

#include "ssl_hash.h"
#include "openssl/sha.h"

int ssl_sha256(const char *in_data,int in_len,char *out_hash)
{
    if (!in_data) {
        return -100;
    }
    
    if (!SHA256((const unsigned char *)in_data, in_len, (unsigned char *)out_hash)) {
        return -1001;
    }
    return 1;
}

一樣這兩文件也要放在 .mk的同一目錄;

3. 開始編寫 Android.mk,Application.mk, 以下示例

#Android.mk文件

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#編碼後生成的.a的名稱
LOCAL_MODULE    := sslhash 
#要編碼的源文件c或cpp
LOCAL_SRC_FILES := ssl_hash.c
#依賴的靜態庫.a,若要使用動態庫使用LOCAL_SHARED_LIBRARIES .so
LOCAL_STATIC_LIBRARIES := libs/${TARGET_ARCH_ABI}/lib/libssl.a libs/${TARGET_ARCH_ABI}/lib/libcrypto.a
#依賴的靜態庫的頭文件
LOCAL_C_INCLUDES := libs/${TARGET_ARCH_ABI}/include
#最後生成靜態庫
include $(BUILD_STATIC_LIBRARY)
#Application.mk 這裏測試,只編譯出x86的

APP_ABI := x86

4. 全部文件都準備好以後以下圖示:

 

5. 調用ndk-build 開始編譯

~/Library/Android/sdk/ndk-bundle/ndk-build NDK_PROJECT_PATH=./ NDK_LIBS_OUT=./ APP_BUILD_SCRIPT=./Android.mk NDK_APPLICATION_MK=./Application.mk

 

6. 成功以後會在當前目錄下生成 obj目錄,裏面包含生成的 靜態庫libxx.a

   

 

7. 編譯好以後,下面須要在Android studio 中測試;用as 建立一個jni項目;

8.在工程build.gradle(Module:app) 裏面添加 libs目錄 (Android 視圖)

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

    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

  而且在指定測試只編譯 x86

externalNativeBuild {
            cmake {
                cppFlags ""
                abiFilters "x86"
            }
        }

        ndk{
            abiFilters "x86"
        }

9. 將以前libs目錄的openssl庫所有copy到 工程 jnilibs目錄 (Android 視圖)

   並把生成的libsslhash.a放到 x86/lib下

   並把ssl_hash.h頭文件放到x86/include下

   放到哪都行,須要在cmake裏面指定引用好

   

10. 打開CmakeList.txt 配置openssl靜態庫的引用,以及配置引用生成的libsslhash.a

以下完善的cmakelist

cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
#這裏配置指定目錄libs
set(OpenSSL_DIR ${CMAKE_SOURCE_DIR}/libs)

# 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.

#這裏引用三個靜態.a, ssl,sslhash,crypto
add_library(crypto STATIC IMPORTED)
add_library(ssl STATIC IMPORTED)
add_library(sslhash STATIC IMPORTED)


# 這裏加載,而且找到相應的 libxxx.a
set_target_properties( # Specifies the target library.
                       crypto

                       # Specifies the parameter you want to define.
                       PROPERTIES IMPORTED_LOCATION

                       # Provides the path to the library you want to import.
                       ${OpenSSL_DIR}/${ANDROID_ABI}/lib/libcrypto.a )

set_target_properties( # Specifies the target library.
                       ssl

                       # Specifies the parameter you want to define.
                       PROPERTIES IMPORTED_LOCATION

                       # Provides the path to the library you want to import.
                       ${OpenSSL_DIR}/${ANDROID_ABI}/lib/libssl.a )

 set_target_properties( # Specifies the target library.
                        sslhash

                        # Specifies the parameter you want to define.
                        PROPERTIES IMPORTED_LOCATION

                        # Provides the path to the library you want to import.
                        ${OpenSSL_DIR}/${ANDROID_ABI}/lib/libsslhash.a)

add_library( # Sets the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             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.
              log-lib

              # 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.

#這裏openssl須要 zlib庫,加載系統的
find_library( z-lib z )

#這裏指定一下咱的頭文件目錄,openssl頭文件,以及咱封裝的ssl_hash.h頭文件
include_directories( ${OpenSSL_DIR}/${ANDROID_ABI}/include
                     ${OpenSSL_DIR}/${ANDROID_ABI}/
)

#最後一步鏈接,這裏注意,必定要把sslhash,咱封裝的這個.a放到ssl,crypto的前面,否則報錯說方法未定義,可能由於sslhash引用了openssl的東西,
target_link_libraries( # Specifies the target library.
                       native-lib

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

 

11. 配置完成,若是編譯不出問題就能夠寫jni調用測試了;

   在 MainActitity.java裏面,添加一下jni方法  

    public native String stringFromJNI();

    //添加的測試方法
    public native int sslsha(byte[] indata,int inlen,byte[] outhash);

12. 在native-lib.cpp 裏面實現jni方法

#include "ssl_hash.h"


extern "C"
JNIEXPORT jint JNICALL
Java_androidapp_cocoajin_com_tjni_MainActivity_sslsha(JNIEnv *env, jobject instance,
                                                      jbyteArray indata_, jint inlen,
                                                      jbyteArray outhash_) {
    jbyte *indata = env->GetByteArrayElements(indata_, NULL);
    jbyte *outhash = env->GetByteArrayElements(outhash_, NULL);

    int ret = ssl_sha256((const char *)indata,inlen,(char *)outhash);

    env->ReleaseByteArrayElements(indata_, indata, 0);
    env->ReleaseByteArrayElements(outhash_, outhash, 0);

    return ret;
}

//默認系統的
extern "C"
JNIEXPORT jstring JNICALL
Java_androidapp_cocoajin_com_tjni_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

 

13. 最後調用 ,這裏把byte[] 轉成了hexString顯示在了app上

        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);

        String he = "hello";
        byte[] habb = new byte[32];
        sslsha(he.getBytes(),he.length(),habb);

        tv.setText(ByteHexUtil.bytesToHexString(habb));

 

14. 執行結果,以及驗證結果

 

15: 參考資料與 工程下載

相關文章
相關標籤/搜索