Android 使用so库的遇到的坑

本文详细介绍了在Android开发中遇到的SO库问题及其解决方案,包括SO库版本选择、正确引入和配置方法,以及如何处理常见错误。

使用so库采坑记录

做Android开发会遇到各种各样的问题,遇到问题不可怕,解决了并且知道为什么,下次遇到能马上解决就好了,今天要说的就是这个so库的使用采坑了。

通常在使用一些第三方的SDK时会有一些so库需要你放入到项目中,这里分为两步,其实,第一步放入,第二步使用。两步都有坑,幸运的是我都踩到了,所以记录一下:

常规的so库是使用C或者C++写的,Android中只要调用就好了,而这些依赖库通常的有好几个版本文件,比如我们来看看百度的文字识别SDK,如下图所示。
在这里插入图片描述
上面有四个文件夹arm64-v8aarmeabiarmeabi-v7ax86,这四个文件表示不同的so库的版本,基本可以满足现在的Android智能机,但是不一定支持虚拟设备,所以当你涉及到使用第三方SDK时,首先就是要使用真机,别用虚拟机,做人不要太头铁了,出问题难受的是你自己。

下面的jar包,就是常规的Java架包,里面封装了一些方法,当你的项目加载这个架包之后,你就可以调用它里面的方法。如何判断这个jar有没有加载到你的项目呢?

就看这个架包能不能展开,如下图所示:
在这里插入图片描述

当然也有人是jar包能展开了,但是项目中还是调用不了方法,这个时候,你关掉Android Studio 泡杯茶,然后看看窗外的风景,再打开Android Studio,它就好了。
在这里插入图片描述
再说的通俗一点就是你去网吧打游戏,然后打的开心的时候电脑卡死了,此时你关机重启就好了,是一样的,你目前先这么理解就好了,刨根问题是没有好下场滴?反派死于话多!只有打酱油的能活到大结局。

你可以看到我的jar放在libs下,什么?你说的你的项目中没找到libs文件夹?
在这里插入图片描述

那你把你的工程切换到Project就可以了,你就能找到,找不到就投诉Google,欺骗消费者,虽然你没有花过钱,都是白嫖。

然后把那包含so库的四个文件夹和jar包都放到这个libs下。

一般来说Android默认是读取jniLibs下的文件的,但是这个文件在项目创建时是没有的,需要开发者手动创建。但是你同样可以省略这一步,就放在libs。这样做你就需要在app下的build.gradle中的android{}闭包下,添加这样一段代码:

	//改变.so的路径到libs下
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

注释都给你写好了,既然你默认读取jniLibs文件,那么我就改了你的默认读取文件夹到libs下,那就可以了,改完之后记得右上角点一下Sync Now。意思是同步配置资源。

配置完这一步,运行项目,然后调用so库中的代码时。

在这里插入图片描述
看到这样的报错,就问你慌不慌?不慌的话你就看不到我这篇文章了,兄嘚!其实上面一堆报错了,最要的就只有一句话:

couldn’t find “libleveldb.so”

你先别管这个libleveldb是什么,你只要知道它现在是一个so库就可以了。刚才我们明明指向了libs文件夹,怎么会找不到这个so库呢?这不是扯呢吗?

其实也很好解决了,so库是属于ndk开发,不同的so库就有不同的配置,因此当你的常规配置解决不了问题的时候,就要尝试新的玩法。

在app模块下的build.gradle中的defaultConfig{}闭包中添加如下代码:

	ndk {
            abiFilters "armeabi-v7a", "x86"
        }

这就是一个ndk的过滤器,然后你再运行,如果还是说找不到,那就再改动一下。

	ndk {
            abiFilters  "armeabi","x86","armeabi-v7a","arm64-v8a"
        }

记得改动后要Sync 或者Sync Now 。否则你的改动无效。

以上操作基本上就可以解决我的第一个找不到so库的问题。

然后我就要调用里面的方法了,再运行一手。
在这里插入图片描述
重点同样也是一句话:

No implementation found for boolean com.abc.LevelDB.open(java.lang.String) (tried Java_com_abc_LevelDB_open and Java_com_abc_LevelDB_open__Ljava_lang_String_2

这句话是什么意思呢?就是说无法实现你的这个类型的方法,在这个包下的类中。这个错误是比较奇葩的,一般的第三方是不会因为你的包名有变化就出问题的,但是巧妙就巧妙在这里了,如果你的这个so库是个人编写的,那么就有这种可能,那么你就不能去随意的改变它的类的包名,比如说。
在这里插入图片描述
上面这个图有一个包名,两个实现类,实现类里面调用了so库里面的代码。这是原本的样子,而我觉得这个包名太长了没有什么意义,因此我改成下面这样。
在这里插入图片描述
然后就报错了,这就说明了这个so库在写的时候就规定要在什么包名下,不能改变包名,改了就找不到这个下面的类了,里面的方法也就是用不了,然后程序就崩溃了。就好比钥匙和锁的关系,钥匙还是那个钥匙,锁换了,钥匙就打不开了。

这么一说你就理解了,所以说当你出现 No implementation found for 这种开头,后面是下划线分割的包名类名,又涉及到so库,那么你可以通过这样的方式来试着解决的,我写的是我真实解决问题的过程。但是每个人的项目环境都有不同,因此很多事情你需要尝试一下才知道行不行,对吧。

如果你有不同的解决方法不妨告诉我,我也会添加到文章中,上高水长,后会有期~

<think>好的,用户想要了解Android JNI的使用教程,我需要先回忆一下相关知识点,确保信息准确。首先,JNI是Java Native Interface,用于让Java和C/C++代码交互。在Android开发中,当需要高性能计算或使用现有C/C++时,就会用到JNI。 接下来,我应该分步骤讲解。首先,用户需要配置NDK环境,这是基础。然后,创建本地方法声明,生成头文件,编写C/C++代码,编译生成so,最后在Java中加载并调用。这些步骤需要详细说明,但也要避免过于冗长。 用户可能的疑问点包括如何生成头文件,javah命令可能已经被javac -h替代,这点需要指出,避免用户使用过时的方法。另外,CMake和ndk-build两种构建方式,现在推荐使用CMake,但可能需要简单对比说明。 要注意示例代码的正确性,比如类名、方法名的一致性,包名的处理,避免用户复制粘贴时出错。比如,Java中的native方法声明,包名com.example需要替换,用户可能忽略这一点,导致不到方法。 另外,异常处理部分需要强调,比如JNI中的异常和Java异常的不同处理方式,避免崩溃。性能方面,频繁的JNI调用可能影响效率,提醒用户注意上下文切换开销。 常见问题部分要考虑用户在实际操作中可能遇到的,比如方法签名错误、加载失败、内存管理问题。比如,方法签名中的分号、包名是否正确,名称是否正确对应,这些容易出错的地方需要重点提示。 需要检查是否有遗漏的步骤,比如Android Studio的NDK配置是否最新,CMakeLists.txt的编写是否正确,是否有权限问题等。同时,推荐用户查阅官方文档,确保信息的权威性。 最后,保持语言口语化,避免使用专业术语过多,必要时进行解释。比如解释.so文件是什么,JNIEnv的作用等,但不要过于深入,保持教程的实用性。</think>以下是 Android JNI 的使用教程(分步骤说明): 1. **环境配置** - 安装 Android Studio - SDK Manager 中安装 NDK(Native Development Kit) - 配置 `local.properties` 添加: ```gradle ndk.dir=你的NDK路径 ``` 2. **创建本地方法声明** ```java public class NativeLib { static { System.loadLibrary("native-lib"); } // native方法声明 public native String stringFromJNI(); } ``` 3. **生成C/C++头文件** - 进入 `app/src/main/java` 目录 - 执行命令(注意包名替换): ```bash javac -h . com/example/app/NativeLib.java ``` 4. **编写C/C++代码** 创建 `app/src/main/cpp/native-lib.cpp`: ```cpp #include <jni.h> extern "C" JNIEXPORT jstring JNICALL Java_com_example_app_NativeLib_stringFromJNI(JNIEnv* env, jobject /* this */) { return env->NewStringUTF("Hello from C++"); } ``` 5. **配置CMakeLists.txt** ```cmake cmake_minimum_required(VERSION 3.10.2) add_library(native-lib SHARED native-lib.cpp) find_library(log-lib log) target_link_libraries(native-lib ${log-lib}) ``` 6. **修改build.gradle** ```gradle android { defaultConfig { externalNativeBuild { cmake { cppFlags "" } } } externalNativeBuild { cmake { path "src/main/cpp/CMakeLists.txt" } } } ``` 7. **调用JNI方法** ```java NativeLib lib = new NativeLib(); String result = lib.stringFromJNI(); // 输出 "Hello from C++" ``` **关键注意事项:** 1. 方法命名必须严格遵循格式: `Java_包名_类名_方法名` 2. JNIEnv 是线程相关的,不可跨线程使用 3. 数据类型转换: - Java `String` ↔ C++ `jstring` - Java `int[]` ↔ C++ `jintArray` **常见问题排查:** - **不到so**:检查 System.loadLibrary() 名称是否与 CMake 配置一致 - **UnsatisfiedLinkError**:确认方法签名是否正确,可用 `javap -s` 验证 - **内存泄漏**:及时调用 DeleteLocalRef() 释放局部引用 建议通过 Android Studio 的 `External Build Files` 功能查看实时编译日志,使用 `ndk-stack` 工具分析崩溃日志。
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

初学者-Study

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值