Android JNI编译SO库完整demo实现高斯模糊效果

作者为防止手生,用高斯模糊算法类练手,将其C代码编译成SO库。重点介绍了SO库从编译到使用的过程,包括新建依赖库、配置编译环境、申明函数、生成头文件、编写逻辑文件和mk文件、编译库文件、拷贝文件及配置依赖等步骤,还提及了生成头文件的错误处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很久没用玩jni ndk编译so库了,为了防止手生就用最近需要实现的一个高斯模糊算法类练手。当然这个算法不是我实现的,我只是把这个算法C代码编译成了一个so库,因为C执行效率比java更高,作为这个吃CPU的算法很适合做成SO文件。

这里不再介绍JNI和NDK了,我要说的重点是一个SO库从编译到使用的这个过程。

上面图片可以清除看到这个SO库的生成和java层代码通过KJNI环境调用C/C++代码的过程。

我是用android studio编译的,因为SO都是一个库并且需要对应的java层加载库文件和申明方法接口所以我们可以直接在工程里面新建一个依赖库模块,下面开始讲解完成步骤:

 

(1)新建一个依赖库根据需要填写包名

(2)配置编译环境

在依赖库项目中找到local.properties文件添加ndk工具位置。
ndk.dir=/home/zhuxingchong/Android/Sdk/ndk-bundle

ndk位置file->project setting可以在下面找到

为了兼容低版本ndk在依赖库gradle.properties文件中添加
android.useDepreCateNdk=true

依赖库build.gradle文件中添加ndk编译模块和so文件编译mk文件

apply plugin: 'com.android.library'
 
android {
    compileSdkVersion 28
 
    defaultConfig {
        minSdkVersion 23
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
 
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        ndk{
            moduleName "jni_blur"//生成so文件名
        }
    }
 
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild{
        ndkBuild{
            path "src/main/java/jni/Android.mk"//mk文件路径
        }
    }
}


(3)java文件中申明函数

(4)生成.h头文件

终端进入mylibrary/src/main/java目录下执行javah -d jni com.data.mylibrary.StackNative命令生成.h文件

命令执行完成后会在java目录下生成jni目录并且在目录下生成

具体.h文件代码如下

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_data_mylibrary_StackNative */
 
#ifndef _Included_com_data_mylibrary_StackNative
#define _Included_com_data_mylibrary_StackNative
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_data_mylibrary_StackNative
 * Method:    blurPixels
 * Signature: ([IIII)V
 */
JNIEXPORT void JNICALL Java_com_data_mylibrary_StackNative_blurPixels
  (JNIEnv *, jclass, jintArray, jint, jint, jint);
 
/*
 * Class:     com_data_mylibrary_StackNative
 * Method:    blurBitmap
 * Signature: (Ljava/lang/Object;I)V
 */
JNIEXPORT void JNICALL Java_com_data_mylibrary_StackNative_blurBitmap
  (JNIEnv *, jclass, jobject, jint);
 
#ifdef __cplusplus
}
#endif
#endif


(5)编写具体逻辑.c或cpp文件,文件命名可以和.h文件一样后缀改为.c或cpp即可,因为是对图片做高斯模糊处理代码比较多。

 

#include <android/log.h>
#include <android/bitmap.h>
#include "stackblur.h"
 
#define TAG "com_data_mylibrary_StackNative"
#define LOG_D(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__)
 
JNIEXPORT void JNICALL
Java_com_data_mylibrary_StackNative_blurPixels
        (JNIEnv
         *env,
         jclass obj, jintArray
         arrIn,
         jint w, jint
         h,
         jint r
        ) {
    jint *pixels;
    // cpp:
    // pix = (env)->GetIntArrayElements(arrIn, 0);
    pixels = (*env)->GetIntArrayElements(env, arrIn, 0);
    if (pixels == NULL) {
        LOG_D("Input pixels isn't null.");
        return;
    }
 
    // Start
    pixels = blur_ARGB_8888(pixels, w, h, r);
    // End
    (*env)->ReleaseIntArrayElements(env, arrIn, pixels, 0);
}
 
JNIEXPORT void JNICALL
Java_com_data_mylibrary_StackNative_blurBitmap
        (JNIEnv
         *env,
         jclass obj, jobject
         bitmapIn,
         jint r
        ) {
    AndroidBitmapInfo infoIn;
    void *pixels;
 
    // Get image info
    if (AndroidBitmap_getInfo(env, bitmapIn, &infoIn) != ANDROID_BITMAP_RESULT_SUCCESS) {
        LOG_D("AndroidBitmap_getInfo failed!");
        return;
    }
 
    // Check image
    if (infoIn.format != ANDROID_BITMAP_FORMAT_RGBA_8888 &&
        infoIn.format != ANDROID_BITMAP_FORMAT_RGB_565) {
        LOG_D("Only support ANDROID_BITMAP_FORMAT_RGBA_8888 and ANDROID_BITMAP_FORMAT_RGB_565");
        return;
    }
 
    // Lock all images
    if (AndroidBitmap_lockPixels(env, bitmapIn, &pixels) != ANDROID_BITMAP_RESULT_SUCCESS) {
        LOG_D("AndroidBitmap_lockPixels failed!");
        return;
    }
    // height width
    int h = infoIn.height;
    int w = infoIn.width;
 
    // Start
    if (infoIn.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
        pixels = blur_ARGB_8888((int *) pixels, w, h, r);
    } else if (infoIn.format == ANDROID_BITMAP_FORMAT_RGB_565) {
        pixels = blur_RGB_565((short *) pixels, w, h, r);
    }
    // End
    // Unlocks everything
    AndroidBitmap_unlockPixels(env, bitmapIn);
}


(6)编写mk文件

Android.mk

LOCAL_PATH		:= $(call my-dir)
 
include $(CLEAR_VARS)
 
LOCAL_MODULE    := jni_blur //生成so文件名
LOCAL_SRC_FILES := stackblur.c com_data_mylibrary_StackNative.c load.c //所有需要编译的c/cpp文件
LOCAL_LDLIBS    := -lm -llog -ljnigraphics
 
include $(BUILD_SHARED_LIBRARY)

Aplication.mk

APP_ABI		:= all
APP_PLATFORM:= android-23
APP_OPTIM	:= release


(7)编译so文件和aar包文件

点击android studio右侧gradle->mylibrary->build->build

生成相应库文件位置

(8)将响应so文件和aar文件拷贝到你的项目libs项目

(9)最后在build.gradle里面配置相关依赖即可使用了

注意:

生成头文件的时候执行javah -d jni com.data.mylibrary.StackNative出错

错误: 无法确定Bitmap的签名

public static native void blurBitmap(Bitmap bitmap, int r);改为
public static native void blurBitmap(Object bitmap, int r);

源码地址:链接

原文博客:https://blog.youkuaiyun.com/zhuxingchong/article/details/89217985

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值