android studio 添加JNI模块与.a文件的方法与经验分享

一、添加Native Module

选中已有的工程,在菜单选择 file->New->New Module。在弹出的界面选择:

Android Native Library

 自行客制化模块名与包名。还有blenativelib.cpp BleNativeLib.java等。包名是用来给APP代码import用的。模块名是生成aar的名字,也是生成模块的文件夹名字。本例是blenativelib

二、编译通过自动生成的Module

编译的时候可能会遇到不少问题,有以下几个方面要检查:

1,检查CMAKE

native模块blenativelib的build.gradle ->  android {} -> externalNativeBuild {} 需要包含:path "src/main/cpp/CMakeLists.txt"。否则c++文件gradle编译不到。这里注意区分android{} -> defaultConfig{} 也有个 externalNativeBuild {}

android {
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }
}

 编译version要注意与 src/main/cpp/CMakeLists.txt里面的 cmake_minimum_required(VERSION 3.10.2) 对应。不能小于它,最好一致。版本要与本地下载的cmake版本一致。如果不一致,可尝试卸载不对应版本。

方法:file->settings->Appearance & Behavior->Android SDK->SDK Tools 删除或者添加

 2,筛选架构

如果不需要编译某些arch,则可以在native模块的build.gradle添加abiFilters:

    buildTypes {
        release {
            ndk {
                abiFilters "arm64-v8a", "armeabi-v7a"
            }
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        debug {
            ndk {
                abiFilters "arm64-v8a", "armeabi-v7a"
            }
        }
    }

3,app代码导入native模块blenativelib依赖

APP的build.gradle里面,增加刚才添加模块的依赖。如刚才我们新建的Module Name是blenativelib,则添加如下代码:

dependencies {
    implementation project(path: ':blenativelib')

}

三、添加接口

1,native模块blenativelib添加JAVA接口函数

在blenativelib\src\main\java\com\fiill\blenativelib\BleNativeLib.java增加接口

package com.fiill.blenativelib;

public class BleNativeLib {

    // Used to load the 'blenativelib' library on application startup.
    static {
        System.loadLibrary("blenativelib");
    }

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

    //add your interface, press ctrl + mouse-left to
    //create function in CPP
    public native String bleProcessData(byte[] raw);
}

2,在CPP文件添加函数实现

按住ctrl,鼠标左键点击JAVA文件中新加的函数,在CPP会自动创建对应的接口。

blenativelib\src\main\cpp\blenativelib.cpp

extern "C"
JNIEXPORT jstring JNICALL
        Java_com_fiill_blenativelib_BleNativeLib_bleProcessData(JNIEnv * env, jobject,
        jbyteArray raw) {
// your codes
}

 3,在APP中使用该接口

APP模块的JAVA函数使用方法:

import com.fiill.blenativelib.BleNativeLib;

public class MainActivity extends AppCompatActivity implements
        View.OnClickListener {
    ...
    static BleNativeLib lib = new BleNativeLib();

    relatedFunction () {
        byte[] raw = new byte[50];
        String out;
        out = lib.bleProcessData(raw);
    }
    ....

}

四、添加预编译库

1,CMAKE添加库

添加一个静态库为例,在blenativelib\src\main\cpp\CMakeLists.txt 里面添加静态库。其中文件夹proc_data是新建的,静态库是lib_proc_data.a

${CMAKE_CURRENT_SOURCE_DIR} 即当前CMakeLists.txt所在目录。

add_library(
        lib_proc_data
        STATIC
        IMPORTED)

set_target_properties(
        lib_proc_data
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_CURRENT_SOURCE_DIR}/proc_data/lib_proc_data.a )

include_directories( imported-lib/include/ )

 2,CPP代码使用接口

在CPP代码中#include 上面 include_directories声明过的头文件,直接使用函数即可。注意如果库是C编译的,要关注extern "C" 声明。

extern "C"{
#include <lib_proc_data.h>
}

extern "C"
JNIEXPORT jstring JNICALL
        Java_com_fiill_blenativelib_BleNativeLib_bleProcessData(JNIEnv * env, jobject,
        jbyteArray raw) {
    std::string str = "1111";
    unsigned char data[64];
    process_data(data, 64);
    return env->NewStringUTF(str.c_str());
}

3. 动态库添加与上述类似,不再描述

五、客制化编译

1,CMAKE区分arch

添加的库,会有arch差别。所以针对不同arch要用开关区分。

${ANDROID_ABI} 可以用来区分当前编译时候的arch。可以用来控制编译的库位置,或者编译属性。例如

if(${ANDROID_ABI} MATCHES "arm64-v8a")
    target_link_libraries( blenativelib lib_proc_data ${log-lib} )
 elseif(${ANDROID_ABI} MATCHES "armeabi-v7a")
    target_link_libraries( blenativelib ${log-lib} )
else()
    target_link_libraries(  blenativelib   ${log-lib} )
endif()

 2,代码中区分arch

通过宏判断。参考代码:

extern "C"
JNIEXPORT jstring JNICALL
        Java_com_fiill_blenativelib_BleNativeLib_bleProcessData(JNIEnv * env, jobject,
        jbyteArray raw) {
    std::string str = "1111";
    unsigned char data[64];
#if defined(__aarch64__)
    //process_data(data, 64);
#elif defined (__arm__)
    //process_data(data, 64);
#endif
    return env->NewStringUTF(str.c_str());
}

六、转换为Android.mk

参考一个其他项目的Android.mk。其他关键字或者so依赖具体根据具体问题来写。

LOCAL_PATH:= $(call my-dir)

PACKAGE_MODULE_NAME := NercCmdClient

NERCCMD_NATIVE_LIBRARY_NAME := libnerccmdclientnativelib

################################## libnerccmdclientnativelib.so ################################

include $(CLEAR_VARS)

LOCAL_MODULE:= $(NERCCMD_NATIVE_LIBRARY_NAME)
LOCAL_CFLAGS += -fstack-protector-strong -fno-common -pipe -Wno-inconsistent-missing-override
LOCAL_SRC_FILES:=           \
        NercCmdClientNativeLib/src/main/cpp/nerccmdclientnativelib.cpp

LOCAL_MODULE_TAGS := optional

LOCAL_SHARED_LIBRARIES :=   \
        libutils            \
        libcutils           \
        liblog              \


LOCAL_C_INCLUDES :=                \
        $(JNI_H_INCLUDE)            \
        $(LOCAL_PATH)/..            \
        $(SDK_DIR)/source/linux/include \
        $(SDK_DIR)/source/linux/api/include \
        $(SDK_DIR)/source/linux/drv/include \
        $(SDK_DIR)/source/linux/api/msp/include \

#LOCAL_PROPRIETARY_MODULE := true
include $(BUILD_SHARED_LIBRARY)

#################################### NercCmdClientNativeLib.jar ###############################
include $(CLEAR_VARS)

LOCAL_MODULE := NercCmdClientNativeLib
LOCAL_MULTILIB := both
LOCAL_MODULE_TAGS := optional
LOCAL_PRIVATE_PLATFORM_APIS := true
#LOCAL_JAVA_LIBRARIES += 
#LOCAL_STATIC_JAVA_LIBRARIES := 
LOCAL_JNI_SHARED_LIBRARIES := libnerccmdclientnativelib

LOCAL_PACKAGE_NAME := NercCmdClientNativeLib

LOCAL_MANIFEST_FILE := NercCmdClientNativeLib/src/main/AndroidManifest.xml

source_dir := NercCmdClientNativeLib/src/main

LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/NercCmdClientNativeLib/$(source_dir)/res
LOCAL_SRC_FILES += $(call all-java-files-under, $(source_dir))

#LOCAL_PROPRIETARY_MODULE := true
include $(BUILD_STATIC_JAVA_LIBRARY)

############################## NercCmdClient.apk ##############################################

include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PRIVATE_PLATFORM_APIS := true
#LOCAL_JAVA_LIBRARIES += 
LOCAL_STATIC_JAVA_LIBRARIES := NercCmdClientNativeLib
#LOCAL_JNI_SHARED_LIBRARIES := 
LOCAL_PACKAGE_NAME := $(PACKAGE_MODULE_NAME)

LOCAL_CERTIFICATE := platform
#LOCAL_CERTIFICATE := testkey platform
LOCAL_PRIVATE_PLATFORM_APIS := true

LOCAL_MANIFEST_FILE := app/src/main/AndroidManifest.xml

source_dir := app/src/main

LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/$(source_dir)/res
LOCAL_SRC_FILES += $(call all-java-files-under, $(source_dir))
LOCAL_SRC_FILES += $(source_dir)/aidl/org/nercdtv/INerccmd.aidl


LOCAL_STATIC_ANDROID_LIBRARIES := \
    androidx.recyclerview_recyclerview \
    androidx.preference_preference \
    androidx.appcompat_appcompat \
    androidx.annotation_annotation \
    androidx.legacy_legacy-preference-v14 \
    androidx.leanback_leanback-preference \
    androidx.leanback_leanback \
    androidx-constraintlayout_constraintlayout \

#LOCAL_PROPRIETARY_MODULE := true
include $(BUILD_PACKAGE)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android JNI 中引用 .a 静态文件的步骤如下: 1. 在 Android.mk 文件中指定静态库的路径和名称。例如: LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := native-lib LOCAL_SRC_FILES := native-lib.cpp LOCAL_LDLIBS := -llog LOCAL_STATIC_LIBRARIES := my-static-lib include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := my-static-lib LOCAL_SRC_FILES := libmy-static-lib.a include $(PREBUILT_STATIC_LIBRARY) 2. 将静态库文件放置在 jni 目录下,并在 Android.mk 文件中指定静态库的路径和名称。 3. 在 C++ 代码中使用 #include 指令引用静态库的头文件。 4. 在 C++ 代码中使用 extern "C" 指令声明静态库中的函数。 5. 在 C++ 代码中使用 System.loadLibrary() 函数加载动态库,并调用静态库中的函数。 下面是一个示例代码: #include <jni.h> #include <string.h> #include <android/log.h> #include "my-static-lib.h" extern "C" JNIEXPORT jstring JNICALL Java_com_example_native_1lib_MainActivity_stringFromJNI(JNIEnv *env, jobject /* this */) { const char* message = my_static_lib_function(); return env->NewStringUTF(message); } 注意:在 Android Studio 中使用 CMake 构建系统时,可以在 CMakeLists.txt 文件中使用 target_link_libraries() 函数引用 .a 静态文件。例如: add_library(my-static-lib STATIC IMPORTED) set_target_properties(my-static-lib PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/my-static-lib.a) target_link_libraries(native-lib my-static-lib)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值