打包so库及jar包,发到仓库供他人使用

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

打包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++支持。

新建完后的工程结构如图

avatar

2、为库模块添加C++支持

2.1准备CMakeLists文件

如果你会自己写的话最好,不会的话,可以新建一个支持c++的工程,在我现在的AndroidStudio4.0版本上,在Chose Project这一步时,选择Native C++就会有了 ,然后复制这个工程的CMakeListsnative-lib.cpp文件过来就好了。

avatar

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文件里这个位置是自己定的。文件结构如下:

avatar

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,就可以看到了。

avatar

编写一个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会有相应提示:

avatar

avatar

标红的不要管它,因为现在我还没有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文件。

avatar

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 文件,一举两得。

avatar

如果要对自己的依赖库进行升级 ,重新去JitPack获取即可!

GitHub下载地址

参考资料:

AndroidNDK开发

Android 安卓创建自己的依赖库(保姆级教程)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值