Android 簡單使用第三方提供的.so和.h (Android.mk和Application.mk方式)

前言:
剛來公司,接了一個項目(具體項目不便透露),其中涉及到一個socket數據傳輸的問題,這裏當然就不可避免的用到了.so動態庫進行實現。接觸過jni的應該都知道,Android調用.so庫其實很簡單,不就是直接static { System.loadLibrary(“aaron”); }嗎?其實我救算這麼想的,但是直到我拿到.so和.h文件之後才發現我錯了。好了,廢話不說了,進入正題:

實現步驟:
一、 分析你手上的.so文件(你可以看.h頭文件,我的理解就是,這個.h文件其實就是c的一個接口類,c纔是具體實現功能的):
     如果.h文件中的方法名類似 Java_com_aaron_demo_JniUtil_getString ,那麼恭喜你,你可以直接到最後一步(五、使用符合Java規範的.so庫);
     如果.h文件中的方法名類似 getString ,你還是老老實實的看第二步吧

二 、大家都知道,Android想要調用C,C暴露給我們的方法名就必須按照我們的規範來寫,如第一步中給出的 Java_com_aaron_demo_JniUtil_getString ,AndroidStudio調用C方法的介紹(JNI),所以,我們如果拿到方法名不規範的C代碼(或者.so文件),就需要把方法名變成規範的名稱。那麼問題來了,很多時候第三方就是不想讓別人看到他的源代碼,所以纔打成.so庫,我們沒有C/C++的源代碼,又怎麼去修改他的方法名呢? 針對這個問題,答案是,我也沒有辦法去修改。
三、 我們寫java的應該都知道“封裝”,對,要改變這個方法名,我們其實只需要在這中間架一座橋樑,就是我們接下來需要介紹的 NDK對第三方.so庫的二次封裝
四、NDK對第三方.so庫的二次封裝:
1. 新建Android項目,用來生成我們要的.so庫
新建一個Android Project ,命名隨意,這裏的包名還是需要注意一下,最好是用你實際項目中的包名,比如我公司的項目包名是 “com.xyw.aaron” ,那麼你new Android Project的時候也改成這個,當然,不該也不會有什麼影響(爲什麼?後面再說 1)

2.新建一個類JniUtil
我們這裏以 JniUtil 爲例(類的名字沒有規定,個人喜好),這個類的位置也是有講究的(後面再說 2),聲明幾個方法,以public static native 開頭(static非必要),具體方法看第三方的.h文件(test.h),我這裏給一個簡單的demo代碼:

#pragma once

extern   int add(int a, int b); 
extern   int sub(int a, int b);

我建的JniUtil類代碼(這個方法其實是我們要用的,也沒有必要完全和test.h一樣,我們只需要在自己的C裏面調test.h的方法即可):

package com.xyw.aaron;

public class JniUtil {
    static {
        System.loadLibrary("aaron");
    }

    public static native int jiafa(int a, int b);

    public static native int jianfa(int a, int b,String className);
}

3.編譯JniUtil類

如圖所示,點擊按鈕即可,完成之後在build文件夾裏面找到生成的JniUtil.class文件(低版本的Android studio在 build->intermediates->classes裏面)


4.生成自己的.h文件(com_xyw_aaron_JniUtil.h)
右鍵複製其路徑(Copy Path):
D:\as_space…\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes\com\xyw\aaron\JniUtil.class
在編輯器裏面改成
D:\as_space…\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes com.xyw.aaron.JniUti
打開window或mac終端,cd到項目的main目錄下面,執行下面的命令
javah -d jni -classpath D:\as_space…\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes com.xyw.aaron.JniUti
在src/main/jni下面生成了 com_xyw_aaron_JniUtil.h文件

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

#ifndef _Included_com_xyw_aaron_JniUtil
#define _Included_com_xyw_aaron_JniUtil
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_xyw_aaron_JniUtil
 * Method:    jiafa
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_xyw_aaron_JniUtil_jiafa
  (JNIEnv *, jclass, jint, jint);

/*
 * Class:     com_xyw_aaron_JniUtil
 * Method:    chengfa
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_xyw_aaron_JniUtil_chengfa
  (JNIEnv *, jclass, jint, jint,jstring);

#ifdef __cplusplus
}
#endif
#endif

5.編寫自己的C文件(aaron.c)
#include "jni.h"
#include "com_example_createsodemo_SoUtil.h"
#include "test.h"

JNIEXPORT jint JNICALL Java_com_example_createsodemo_SoUtil_jiafa(JNIEnv *env, jclass jz, jint a, jint b){
    return add(a,b);
}

JNIEXPORT jint JNICALL Java_com_example_createsodemo_SoUtil_chengfa(JNIEnv *env, jclass jz, jint a, jint b,jstring classname){
    return mul(a,b);
 }

這個文件其實就是實現com_example_createsodemo_SoUtil.h裏面的兩個方法jiafa()和jianfa(),注意第三行代碼,這裏引入了第三方的test.h文件,因爲我們的aaron.c會用到tesh.h裏面暴露的方法add(a,b)和mul(a,b)
記得把第三方的.so文件(libtest.so)複製到jni文件夾裏面。

注意:這裏的so文件必須是和你開發設備abi一致的,我設備是x86的

6.在jni目錄裏新建Android.mk和Application.mk文件
Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := test                        // 根據下面的.so文件來就行
LOCAL_SRC_FILES := libtest.so                 // jni下的第三方.so文件
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := aaron                        //    你要生成的so文件的名稱
LOCAL_SRC_FILES := aaron.c                    //    你的.c文件
LOCAL_LDLIBS += -L$(SYSROOT)/lib -llog
LOCAL_LDLIBS := -llog -ljnigraphics
LOCAL_CFLAGS := -g

LOCAL_SHARED_LIBRARIES := test                // 第一個test
include $(BUILD_SHARED_LIBRARY)

Application.mk

APP_ABI := x86
APP_PLATFORM := android-16

7.編譯生成新的.so庫
在終端,cd到Android.mk所在的目錄,執行ndk-build命令,如果配置沒有問題,那麼,你將會在main目錄下看到libs和obj兩個文件夾,我們要的東西就在libs裏面,見圖:


五、使用符合Java規範的.so庫:
打開你將要開發的項目,在main下面建一個文件夾,文件夾的名稱爲“com.xyw.aaron”,這個目錄必須和我們新生成的.so文件中的Java_com_xyw_aaron_JniUtil 匹配,這裏我在前面(1. 新建Android項目,用來生成我們要的.so庫)就已經提到了,這就是爲什麼我們在二次封裝的時候,文件夾名稱一定要和實際項目的相同的原因。如果相同,那麼你就不要再建這個文件夾了,好了不廢話了。
將(2.新建一個類JniUtil)提到的JniUtil類複製到該文件夾裏面(如果你要自己寫也未嘗不可,哈哈)。
ok,到這裏你就可以隨意的在項目中使用.so庫裏面的方法了(直接調JniUtil裏面的方法即可!)

大功告成,希望能幫到大家,願大家編寫順利,少遇坑!
有什麼問題大家一起探討!
留個郵箱:[email protected]

【轉】JNI開發學習之C反射調用java方法


————————————————
版權聲明:本文爲CSDN博主「Aaron_lxq」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/AaronYB/article/details/89413758

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章