> 文章列表 > JNI小记1 -- VS生成so给AS调用

JNI小记1 -- VS生成so给AS调用

JNI小记1 -- VS生成so给AS调用

万年不变的环境配置

NDK 下载 | Android NDK | Android Developers (google.cn)
需要提的是,直到本文撰写的时间,我在这个页面下的NDK是只有x86-64平台的。而我测试时确实只有x64编译成功。
在visual studio里新建一个安卓共享库工程:
JNI小记1 -- VS生成so给AS调用

刚开始的界面应该是这样的:
JNI小记1 -- VS生成so给AS调用

而后在: 工具->选项->跨平台 选上我们的ndk目录(这里和交叉编译工具链一样,把此前的ndk压缩包解压到你期望的目录):
JNI小记1 -- VS生成so给AS调用

JNI小记1 -- VS生成so给AS调用

再选择项目的重定解决方案:
JNI小记1 -- VS生成so给AS调用

重定好后可以再项目配置(项目->属性)里修改如下(这里clang最好改成5.0):
JNI小记1 -- VS生成so给AS调用

接下来配置include和lib目录。
快速定位这两个目录可以这样,在ndk目录搜索"log.h"(这个也是项目默认所需要引用的)
JNI小记1 -- VS生成so给AS调用

我们要用的是toolchains->llvm的。跳转过去找lib和include文件夹即可
接着将对应目录填进来(包含和引用),添加正确只后可以看到:
JNI小记1 -- VS生成so给AS调用
JNI小记1 -- VS生成so给AS调用

JNI小记1 -- VS生成so给AS调用

环境配置基本完成。

在VS-Android-So默认模板的基础上写JNI

工程一开始如下:
JNI小记1 -- VS生成so给AS调用

需要注意的是,我们的项目在默认情况下是编译不过的。因为定义LOGI、LOGW处的关键字"ANDROID_LOG_INFO"是NDK的头文件"log.h"里才被定义的内容,这里还没被引用。
开头引用:#include<android/log.h>
如果之前的配置步骤一致,编译正常是通过的。
而之后我们再添加JNI调用函数如下:

Java_com_example_myapplication_MainActivity_HelloWorld(JNIEnv * env, jclass jcls) {LOGI("init", "012");return env->NewStringUTF("Hello World!");}

这里用我目前浅薄的认识稍微解释一下,JNI调用函数是很有讲究的。C层的函数接口,其命名需要和安卓工程的名匹配。(当然也有不一致的写法,但我还没学到)最后一截是函数名,前面那一串都是包名。
完整demo代码如下:

#include "SharedObject2.h"
#include <android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "SharedObject2", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "SharedObject2", __VA_ARGS__))extern "C" {/*此简单函数返回平台 ABI,此动态本地库为此平台 ABI 进行编译。*/const char * SharedObject2::getPlatformABI(){#if defined(__arm__)#if defined(__ARM_ARCH_7A__)#if defined(__ARM_NEON__)#define ABI "armeabi-v7a/NEON"#else#define ABI "armeabi-v7a"#endif#else#define ABI "armeabi"#endif#elif defined(__i386__)#define ABI "x86"#else#define ABI "unknown"#endifLOGI("This dynamic shared library is compiled with ABI: %s", ABI);return "This native library is compiled with ABI: %s" ABI ".";}extern "C" jstring Java_com_example_myapplication_MainActivity_HelloWorld(JNIEnv * env, jclass jcls) {LOGI("init", "012");return env->NewStringUTF("Hello World!");}void SharedObject2(){}SharedObject2::SharedObject2(){}SharedObject2::~SharedObject2(){}
}

生成完毕后AS新建工程、、、
而后开始配置build.gradle:
JNI小记1 -- VS生成so给AS调用

这里也是参考网上的一个配置脚本,把ndk和sourcesSet配置一下:

plugins {  id 'com.android.application'  
}  android {  namespace 'com.example.myapplication'  compileSdk 32  defaultConfig {  applicationId "com.example.myapplication"  minSdk 26  targetSdk 32  versionCode 1  versionName "1.0"  testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"  ndk {  //针对自己项目的架构对应添加相应的so目录  //目前的手机架构基本上都是arm架构,x86的基本上没有,基本上是平板  abiFilters "armeabi-v7a",//arm架构的32位  "armeabi",//十年前的手机CPU架构,基本上已经不存在了  "arm64-v8a",//arm架构的64位  "x86",//x86架构的 32位  "x86_64"//x86架构的64位  }  }  buildTypes {  release {  minifyEnabled false  proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'  }  }    compileOptions {  sourceCompatibility JavaVersion.VERSION_1_8  targetCompatibility JavaVersion.VERSION_1_8  }  buildFeatures {  viewBinding true  }  sourceSets {  main {  //这里的libs需要替换成你放置so库的目录,比如jniLibs  jniLibs.srcDirs = ['libs']  }  }}  dependencies {  implementation 'androidx.appcompat:appcompat:1.4.1'  implementation 'com.google.android.material:material:1.5.0'  implementation 'androidx.constraintlayout:constraintlayout:2.1.3'  implementation 'androidx.navigation:navigation-fragment:2.4.1'  implementation 'androidx.navigation:navigation-ui:2.4.1'  testImplementation 'junit:junit:4.13.2'  androidTestImplementation 'androidx.test.ext:junit:1.1.3'  androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'  
}

接着放上我们的lib:
JNI小记1 -- VS生成so给AS调用

static:
JNI小记1 -- VS生成so给AS调用

引用:
JNI小记1 -- VS生成so给AS调用
跑起来:
JNI小记1 -- VS生成so给AS调用