本文是继前文
AndroidStudio2.2.3 JNI与NDK开发之一:生成可调用.so库的跟进文章
主要用于解决生成的.so库中,jni的方法名有包名的限制,导致其他项目工程引用时,包名不一致,出现jni层接口调用无效的问题。即,A项目的a.so,在B项目使用时,报uncaughtException的错误,导致程序崩溃。
uncaughtException Ljava/lang/ThreadGroup;
12-30 23:07:09.936 4604-4604/com.example.jnitest E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.jnitest, PID: 4604
java.lang.UnsatisfiedLinkError: getJniString
at com.example.jnitest.JniUtil.getJniString(Native Method)
at com.example.jnitest.MainActivity.onCreate(MainActivity.java:15)
at android.app.Activity.performCreate(Activity.java:5451)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
引起这个崩溃的原因是,jni的getJniString接口对应的包名为com.example.jnidemo,而本项目中包名为com.example.jnitest.
一般来说,编译的.so库就是为了使用方便,通用性好,不管本项目工程或者是其他的项目工程,于是要编译出一个适用性强的.so提供使用,需要将jni层的.so对应Java层的类接口打包成一个.jar,给其他项目工程使用,其他工程使用时,只需要添加.jar包和.so文件即可。本文主要介绍新建一个Library,生成.so和jar提供给其他工程使用。
1、新建项目为JniTest
(1)、为JniTest新建Module,选择Android Library命名为jnilibrary
然后再java的com.example.jnilibrary下新建JniUtil.java,如图:
JniUtil的内容依然为测试内容
public class JniUtil {
static {
System.loadLibrary("JniUtil");
}
public static native String getJniString();
public static native int getJniAdd(int a, int b);
}
接下来就是进行jni操作,编译.so库的步骤,也是在src\main文件下新建jni文件夹,如图:
配置build.gradle和Project Structure中ndk-build路径,具体步骤参考前一篇文章。
(2)、配置并生成jar文件
主要是对JniUtil.java生成.jar文件。
在jnilibrary这个module下的build.gradle中配置如下信息
def SDK_NAME = "JniUtil"; def SDK_VERSION = "_V1.0"; def sdkDestinationPath = "build"; def zipFile = file('build/intermediates/bundles/release/classes.jar') task deleteBuild(type: Delete) { delete sdkDestinationPath + SDK_NAME + SDK_VERSION + ".jar" } task makeJar(type: Jar) { from zipTree(zipFile) from fileTree(dir: 'src/main',includes: ['assets/**']) baseName = SDK_NAME + SDK_VERSION destinationDir = file(sdkDestinationPath) } makeJar.dependsOn(deleteBuild, build)声明jar的文件名,版本,路径,以及编译依赖的编译文件等。完整的build.gradle文件如下:
apply plugin: 'com.android.library'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main {
jni.srcDirs = ['src/main/jni', 'src/main/jni/']
}
}
externalNativeBuild {
ndkBuild {
path file("src\\main\\jni\\Android.mk")
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.1.0'
testCompile 'junit:junit:4.12'
}
def SDK_NAME = "JniUtil";
def SDK_VERSION = "_V1.0";
def sdkDestinationPath = "build";
def zipFile = file('build/intermediates/bundles/release/classes.jar')
task deleteBuild(type: Delete) {
delete sdkDestinationPath + SDK_NAME + SDK_VERSION + ".jar"
}
task makeJar(type: Jar) {
from zipTree(zipFile)
from fileTree(dir: 'src/main',includes: ['assets/**'])
baseName = SDK_NAME + SDK_VERSION
destinationDir = file(sdkDestinationPath)
}
makeJar.dependsOn(deleteBuild, build)
接下来下Android Srudio的Gradle窗口,找到makejar(没有时,Gradle窗口左上角的刷新按钮进行刷新),双击。如图:
等待编译一会在如下目录下生成想要的.jar文件:
3、新建一个Test项目工程验证,目录结构如下图
在真机上运行如下结果