将so库打包进apk

遇到过同样的问题,大佬文章分析的很到位,特此转载记录:

文章链接:https://blog.csdn.net/sevenjoin/article/details/104768293

概述

本章主要介绍如何将自己开发的so库文件或者第三方提供的库文件一并打包到APK中的正确姿势。

在之前也参考了很多资料就是无法将so正确打包,走了很多坑,一度想放弃。现在总结一下 避免其他新同学继续入坑!

至于为什么需要将so打包到apk呢? 是因为在开发app时引用到了so文件,但是so文件没有被apk一起打包,在安装apk的时候提示,so库文件找不到:

  • 问题一

java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file “/data/app/com.hx.template-2/base.apk”],nativeLibraryDirectories=[/data/app/com.hx.template-2/lib/arm, /vendor/lib, /system/lib]]] couldn’t find “libled_jni.so”

既然找不到so库文件,那么手动将so push到设备中部就可以了吗?

adb push libled_jni.so /system/lib

再次,执行apk,又出现如下错误提示:

  • 问题二

E AndroidRuntime: java.lang.UnsatisfiedLinkError: dlopen failed: library “/system/lib/libled_jni.so” needed or dlopened by “/system/lib/libnativeloader.so” is not accessible for the namespace “classloader-namespace”

查资料,给的解释说Android N之后加载so库做了限制, 会对加载者权限进行检查,否合条件的才会被加载。
那么,应该如何解决呢?

  • 1,首先对于问题一, 这个很明显是缺少so文件, 我们只要把so文件放到设备中即可。
  • 2,其次对于问题二, 它是基于问题一引出的问题, 也就是说不单单是把so放到设备中就行了, 如果姿势不正确,将会引发问题二的出现。
  • 3,最后,我们还是要聚焦问题一上, 应该以什么样的姿势才算正确呢?
    有两种做法:

1, 直接修改白名单文件,将so库增加进去,该文件为/system/etc/public.libraries.txt
但这种方法总感觉不妥, 个人不提倡
2,将so文件和apk一起打包,在安装apk的时候将so一同安装到设备。它也分两种方式实现:
方式一, 通过IDE方式打包so到apk。 - 这种方式打包还是会有其他问题
方式二, 通过Android.mk的方式打包so到apk。 - 验证可行 跳转链接

本章将以方式一的方式讲如何通过IDE AS打包so文件到apk中。在打包的过程中遇到很多坑,网上的方式基本都是千篇一律,经过不断尝试终于可以将so成功打包。 虽然这种方式仍然没有解决问题一的错误,但还是做一个记录,引导ide 打包so的正确姿势。

前期测试准备

  • 1, 测试环境IDE - 我使用的是Android Studio3.5版本
  • 2, c/c++测试库文件 - libled_jni.so - 你们也可以替换成你们自己的so文件

创建测试工程

首先需要先新建工程,如果已经有了工程,可以直接移步到下一小节中增加so库打包信息
这样我们简单创建一个helloworld工程。一路Next下去。
在这里插入图片描述
创建好了之后最好先编译一下。 接下来我们就开始增加so文件。

增加so库打包信息

这一步,也是入坑的关键一步。
网上有很多资料说,在工程目录下(即app目录下)的build.gradle文件中增加如下语句,即可:

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

这样的做法是正确的,但总是不成功。关键的问题在于这个中括号[]里的路径设置出了问题,[‘libs’]这个路径要和实际工程中so所在的路径要保持一致,这样编译打包的时候才会找到so文件。
通常我们会把so文件放置到,和java同级目录下的libs目录中:
在这里插入图片描述

如果是这样放置的,那么在build.gradle文件中就应该修改为:

android {
    signingConfigs {
        debug {
            storeFile file('D:\\work\\Android\\platform.keystore')
            storePassword 'android'
            keyPassword 'android'
            keyAlias = 'androiddebugkey'
        }
    }
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.example.ledsventest"
        minSdkVersion 23
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    sourceSets {
        main {
        // ['libs'] change to ['src/main/libs']
            jniLibs.srcDirs = ['src/main/libs']
        }
    }
}

编译工程并查看结果

上述修改完成后,我们可以编译然后run->run app,在模拟器或设备中进行查看:
一般应用会被安装到/data/app/com.xxxx.xxxx/lib/arm/libled_jni.so
在这里插入图片描述

你可能感兴趣的:(Andriod,android,安卓)