文章目录
打包so库及jar包,发到仓库供他人使用
Android的NDK开发相信各位已经精通各种姿势了。不过基本上都是那种native代码和java代码都在同一个工程中,因为应用从头到脚都是我们自己的,也不需要分离。但有时候可能需要我们自己把某些库打包起来供别人使用,或者使用别人提供给我们的库。本篇文章及下篇文章就讲讲so库如何打包。
介绍
这篇文章会讲第一种方式来打包so库,这种方式是基于jni层的,需要我们同时提供接口的jar包来配合使用,适用于对方从java层调用我们的库。因为jni中的函数名是有特殊要求的,它会指定jni的java接口的路径,如果不提供jar包,那么使用者就要按照我们在jni头文件中声明的函数名来建立java文件,这将是非常痛苦的。
废话不多说,直接嘎斯。
1、新建库module
File > New > New module > Android Library
填好相关信息等就可以finish了。目前我在用的是AndroidStudio4.0,在新建工程的时候已经找不到添加c++ support的选项了,因此一会儿也免不了要自己去改build.gradle文件来添加c++支持。
新建完后的工程结构如图

2、为库模块添加C++支持
2.1准备CMakeLists文件
如果你会自己写的话最好,不会的话,可以新建一个支持c++的工程,在我现在的AndroidStudio4.0版本上,在Chose Project这一步时,选择Native C++就会有了 ,然后复制这个工程的CMakeLists和native-lib.cpp文件过来就好了。

cmake_minimum_required(VERSION 3.4.1)
# 这一句用来导出编译生成的so库
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/jniLibs/${ANDROID_ABI})
include_directories(src/main/cpp)
file(GLOB CPP_FILES "src/main/cpp/*.cpp")
add_library(
native-lib
SHARED
${CPP_FILES}
)
通常操作,我就不解释CMakeLists里都是啥意思了。注意我注释的那条语句,它会负责把编译出的so库导出到我们指定的位置。这里的位置就是sdk/jniLibs/{ANDROID_ABI}。 然后将这个文件放在库模块的根目录下(虽然我这库模块的名字是sdk,但是并不是AndroidSDK,切勿搞混,需要AndroidSDK的时候我会特别指明的)。放在别的地方也行,因为在gradle文件里这个位置是自己定的。文件结构如下:

2.2修改sdk的gradle脚本
此处修改的是sdk的build.gradle文件(不是AndroidSDK!!!)。在defaultConfig节点下指定要编译的cpu架构,在android节点下指定CMakeLists的位置。最后文件如下:
defaultConfig {
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
//这里指定cpu架构
/**
* armeabi-v7a: 曾经的主流架构平台
* arm64-v8a:目前主流架构平台 (占有率90%)
* arm84-v8a可以兼容armeabi-v7a
*/
ndk {
abiFilters "armeabi-v7a"
// 使用模拟器
// abiFilters "x86"
}
}
//这里指定CMakeLists的位置,默认根目录是从sdk目录开始的。
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
2.3 编写c++及java代码
我们从库里返回一个字符串"Hello from C++ Cc"。 注意看我们的CMakeLists文件中指定的src位置,是src/main/cpp,那么去检查一下有无这个文件。没有的话就新建一个,也可以从C++项目Copy过来。然后在里面新建一个cpp文件(如果你是c的话,注意修改一下CMakeLists里相关的地方,因为这个目前仅包含了cpp文件)。点击Build > Make module "sdk",等模块编译完成后,我们就可以看到项目中出现了cpp文件夹和里面的源代码,并且被AndroidStudio认定为源代码文件夹。如果看不到,再点击一下Build > Refresh linked C++ project,就可以看到了。

编写一个jni函数。假设我在我的包里要建立一个MyStringUtil.java文件,那么这个文件的完整路径就是com.zu.sdk.MyStringUtil。 那么在这个c++文件中,我们这样写:
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_sdk_MyStringUtil_getStringNDK(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++ Cc";
return env->NewStringUTF(hello.c_str());
}
extern "C"是个比较迷惑的点,因为我们现在使用的是cpp文件,使用c++编译器编译后,函数名会改变,但是c的不会,因此我们要在作为jni接口的函数上加上这句。否则jni会找不到接口。 然后按照我们之前说的,在包下建立名为MyStringUtil.java的文件 。
在java文件中加载ndk库,然后声明函数,要和c++文件中的对应起来。
package com.example.sdk;
public class MyStringUtil {
public static String ndkString() {
return getStringNDK();
}
private static native String getStringNDK();
static {
System.loadLibrary("native-lib");
}
}
注意如果你的java的函数和jni中的函数能对应起来的话,AndroidStudio会有相应提示:


标红的不要管它,因为现在我还没有build。
2.4 测试库
在app的MainActivity里就可以调用sdk里MyStringUtils里的ndkString方法获取字符串。
package com.example.sdk_app_client;
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
//现在可以导入sdk里的内容了
import static com.example.sdk.MyStringUtil.ndkString;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tvApp = findViewById(R.id.tv_app);
tvApp.setText(ndkString());
}
}
然后运行。 字符串没有错误,说明就成功了
3、打包so库
so库其实不用打包,因为我们已经在CMakeLists文件中指定了so库的输出路径。点击Build > Make module "sdk",然后去文件管理器里看一下,sdk目录下会生成一个jniLibs文件夹,里面包含了指定cpu架构的so文件。

4、打包jar包
通过上一步我们已经打包出了so,但是只有so是很难使用的,因为jni接口是指定包名的,使用者的包名基本不可能和我们的一样,因此提供一个jar包来调用so库。 打包jar包实际上是一个不怎么常见的操作,这里我们要在sdk的build.gradle中添加一个task,通过这个task来打包。 为sdk的build.gradle文件添加如下节点
//该task用来打包jar包
task makeJar(type: Copy) {
delete 'libs/sdk.jar' //删除已经存在的jar包
// 这个目录里面是classes.jar 之前也是一直卡在这里
from('build/intermediates/compile_library_classes_jar/debug/')//从该目录下加载要打包的文件,注意这个目录,不同版本的AndroidStudio是不一样的,比如在3.0版本是build/intermediates/bundles/release/,要自己去查一下。
into('libs/')//jar包的保存目录
include('classes.jar')//设置过滤,只打包classes文件
rename('classes.jar', 'sdk.jar')//重命名,mylibrary.jar 根据自己的需求设置
}
makeJar.dependsOn(build)
添加完之后,sync gradle一下。然后,打开Android Studio的Terminal,输入gradlew makeJar,然后你就会看到一堆输出。
最后看到build success,然后去sdk/libs目录下查看是否生成了名为sdk.jar的文件。如果没有,应该就是你的classes.jar路径写错了。
到这里就已经拿到了Jar包 和So 库,项目就和平时我们正常使用一样了。 但是还像跟进一步,可以直接发到远程仓库上面去
5、发布远程仓库
这里的仓库,选择性有很多。 有Jcenter、Maven、还有jitpack。 相比jitpack可以直接使用Github 或者是Gitee,所以就直接使用jitpack了。 将这个sdk库直接上传到GitHub上去,关联jitpack。 https://jitpack.io/
就可以在使用项目上通过一键依赖的方式去调用So库 ,并且还隐藏了So 文件,一举两得。

如果要对自己的依赖库进行升级 ,重新去JitPack获取即可!
本文详细介绍了如何打包Android的so库和jar包,以便供他人使用。首先创建库module,添加C++支持,编写C++和Java代码,测试库的功能。接着,利用CMakeLists文件打包so库,自动导出到指定位置。同时,通过Gradle任务打包jar包。最后,将库发布到Jitpack远程仓库,实现便捷的依赖引入。
6160

被折叠的 条评论
为什么被折叠?



