Android So 库增加和生成
一:前言
日常开发咱们常常会应用到第三库,波及到底层的语音,视频等都须要增加 so 库。
而 so 库的体积一般来说十分的大,不搞清楚随便增加会导致 apk 体积暴增。
下面问题:
Android 提供 abifilters 为咱们提供了解决方案 abifilters 为咱们提供了抉择适配指定 CPU 架构的能力,只须要在 app 下的 build.gradle 增加如下配置:
android{
defaultConfig{
ndk {
// 抉择要增加的对应 cpu 类型的.so 库。abiFilters 'arm64-v8a','armeabi', 'armeabi-v7a', 'x86_64','x86'
}
}
}
为何大厂 APP 如微信、支付宝等只适配了 armeabi-v7a/armeabi?
https://mp.weixin.qq.com/s/jn…
Android 中的 so 文件是动态链接库,是二进制文件,即 ELF 文件。多用于 NDK 开发中
二:什么是 ABI
ABI 是英文 Application Binary Interface 的缩写,即利用二进制接口。
不同 Android 设施,应用的 CPU 架构可能不同,因而反对不同的指令集。
CPU 与指令集的每种组合都有其本人的利用二进制界面(或 ABI),ABI 十分准确地定义了应用程序的机器代码应如何在运行时与零碎交互。
您必须为要与您的应用程序一起应用的每种 CPU 架构指定一个 ABI(Application Binary Interface)
Android 目前反对 7 种 ABIs:arm64-v8a,armeabi, armeabi-v7a,X86, X86–64,mips, mips64
三:CPU 架构
总结:
(1)只适配 arm64-v8a 能够运行在 arm64-v8a 上
长处: 性能最佳
毛病:只能运行在 arm64-v8 上,要放弃局部老旧设施用户
(2)只适配 armeabi-v7a 能够运行在 armeabi-v7a 和 arm64-v8a
只是又筛掉了一部分老旧设施, 在性能和兼容二者中比拟均衡
(3)只适配 armeabi 的 APP 能够跑在 armeabi,x86,x86_64,armewabi-v7a,arm64-v8 上
长处: 基本上适配了全副 CPU 架构(除了淘汰的 mips 和 mips_64)
毛病:性能低,相当于在绝大多数手机上都是须要辅助 ABI 或动静转码来兼容
将来只须要适配一款 cpu 架构 arm64-v8a,这些缓缓曾经淘汰了,支流是 cpu 架构 arm64-v8a
四:ADB 查看手机的 CPU 架构
F:\soudaoProject\MyGitignore>adb shell
onc:/ $ cat /proc/cpuinfo
Processor : AArch64 Processor rev 4 (aarch64)// 这里能够看出手机是 CPU 架构是 ARM v8 64 位
processor : 0
BogoMIPS : 38.40
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x51
CPU architecture: 8
CPU variant : 0xa
CPU part : 0x801
CPU revision : 4
processor : 1
BogoMIPS : 38.40
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x51
CPU architecture: 8
CPU variant : 0xa
CPU part : 0x801
CPU revision : 4
processor : 2
BogoMIPS : 38.40
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x51
CPU architecture: 8
CPU variant : 0xa
CPU part : 0x801
CPU revision : 4
processor : 3
BogoMIPS : 38.40
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x51
CPU architecture: 8
CPU variant : 0xa
CPU part : 0x801
CPU revision : 4
processor : 4
BogoMIPS : 38.40
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x51
CPU architecture: 8
CPU variant : 0xa
CPU part : 0x800
CPU revision : 2
五:Android Studio 增加 So 库
办法一:在 src/main 中新建 jniLibs 文件夹,把.so 复制进去
我这是 ijkplayer 的 so 库
办法二:是在 app/ 中新建 libs 文件夹,把.so 复制进去
这须要在 app 下 build.gradle 中增加五行脚本即可(注:以下脚本意思是会把 libs 文件夹当成 jniLibs 文件夹,能够间接用 so 库了)
android{
sourceSets {
main {jniLibs.srcDirs = ['libs']
}
}
}
六.Android So 库生成
JNI 是 Java Native Interface 的缩写,它的次要作用是提供了若干 API 来实现 Java 和其余语言的通信(次要是 C 和 C ++)。
NDK 是一系列工具的汇合,它能够帮忙开发者疾速开发 C(或者 C ++)的动静库(也称 So 库),并 So 库和 Java 利用一起打包。
JNI 的应用就是须要将 C(或者 C ++)代码编译成动静库供 Java 办法调用
生成 SO 库(形式一)
第一步:下载 NDK,配置 NDK,下载 CMake,这个是写 C 语言的
File–>Settings
![上传中 …]()
下载完 NDK 后,去 local.properties 文件中查看是否定义了 ndk 的存储门路,
而后到 gradle.properties 文件中增加 android.useDeprecateNdk=true,示意咱们的利用须要应用 NDK
第二步:NDK 开发建设一个 C ++ 我的项目
早 android 构造下
查看 CMakeLists.txt 并批改
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
demo// 默认是 native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
demo.cpp // 默认是 native-lib.cpp)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
demo// 默认是 native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib} )
在这里你能够发现 app 下的 build.gradle 曾经编译生成了
android {
compileSdkVersion 28
buildToolsVersion "28.0.3"
defaultConfig {
applicationId "com.randao.myproject"
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
// 这里是创立 C ++ 我的项目默认生成的
externalNativeBuild {
cmake {cppFlags ""}
}
// 这个是我本人增加去匹配 cPU 架构
ndk{abiFilters 'arm64-v8a'}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
// 默认生成去构建 CMakeLists.txt
externalNativeBuild {
cmake {path "src/main/cpp/CMakeLists.txt"}
}
}
第三步:编写 Java 调用类
/*
* JNI 测试类 */
public class TestJNI {
static {System.loadLibrary("demo");
}
public native void set();// C 语言中实现,输入这就是一个 JNI 的调用}
Java 调用类的阐明:
1、动态代码块表明了该 Java 类须要加载哪一个 So 库,例子中的 demo 是 So 库的名称。(留神:实际上 NDK 生成的 So 库的名称为 libdemo.so,然而 So 库的名称就是 demo)
2、native 关键字申明了 set()办法,这个办法须要在 C(或者 C ++)中实现。
第四步:生成.h 头文件,编写 C(或者 C ++)代码
关上 demo.cpp 文件编写
#include <jni.h>
#include <string>
extern "C"
JNIEXPORT jstring JNICALL
Java_com_randao_myproject_TestJNI_set(JNIEnv *env, jobject thiz) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
//Java_com_randao_myproject_TestJNI_set(JNIEnv *env, jobject thiz)
//Java+ 我的项目名 + 类名 + 办法名后果是输入 Hello from C++
第五步:调用在 Activity
String aa=new TestJNI().set();// 调用办法输入
Toast.makeText(this,aa,Toast.LENGTH_SHORT).show();
第六步:查看生成的 so 库
1. 什么是 CMake?
定义:容许开发者编写一种平台无关的 CMakeList.txt 文件来定制整个编译流程,而后再依据指标用户的平台进一步生成所需的本地化 Makefile 和工程文件,如 Unix 的 Makefile 或 Windows 的 Visual Studio 工程。从而做到“Write once, run everywhere”。
2. 如果我想 JNI 中减少一个办法
/*
* JNI 测试类 */
public class TestJNI {
static {System.loadLibrary("demo");
}
public native void set();// C 语言中实现,输入这就是一个 JNI 的调用
public native void add(int x,int y);//demo.cpp 实现 add
对应的 demo.cpp 下办法
#include <jni.h>
#include <string>
extern "C"
JNIEXPORT jstring JNICALL
Java_com_randao_myproject_TestJNI_set(JNIEnv *env, jobject thiz) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_randao_myproject_TestJNI_add(JNIEnv *env, jobject thiz,jint x,jint y){// 具体操作 add}
END: 将来可期