如何在 Android Studio 中包含 *.so 库?
Posted
技术标签:
【中文标题】如何在 Android Studio 中包含 *.so 库?【英文标题】:How to include *.so library in Android Studio? 【发布时间】:2014-08-13 00:10:12 【问题描述】:我阅读了很多关于如何将 *.so 库添加到 android Studio 的帖子,但它们都不起作用,尤其是在涉及到文本时:这不适用于较新的 xxx(Android Studio、gradle、. ..)
我们可以重新开始吗?我得到了:
Android Studio 0.6.0
从我看到的项目结构:
SDK 位置:
/usr/share/android-studio/data/sdk
/usr/lib/jvm/default-java
项目:
Gradle version 1.10
Android Plugin Version 0.11.+
模块/应用程序: 属性:
编译 SDK 版本 19 构建工具版本 19.1.0
依赖关系:
dir=libs, include=[*.jar] Compile
dir=libs, include=[*.so] Provided
m com.android.support: appcompat -v7:19.+ Compile
我得到了预编译的 *.so 文件,并且在他们正在运行的演示应用程序中。我必须更改应用程序的源代码,因此我需要使用相同的 *.so 文件进行重建。
【问题讨论】:
从android项目外的目录中添加一个.so文件:***.com/questions/50713933/… 在这里查看答案:***.com/a/54977264/8034839 【参考方案1】:在 Android Studio 1.0.2 中添加 .so 库
-
在“src/main/”中创建文件夹“jniLibs”
将所有 .so 库放入“src/main/jniLibs”文件夹中
文件夹结构看起来像,
|--应用:
|--|--src:
|--|--|--主要
|--|--|--|--jniLibs
|--|--|--|--|--armeabi
|--|--|--|--|--|--.so 文件
|--|--|--|--|--x86
|--|--|--|--|--|--.so 文件
无需额外的代码,只需同步您的项目并运行您的应用程序。
参考
https://github.com/commonsguy/sqlcipher-gradle/tree/master/src/main
【讨论】:
这不适用于 2015 年 6 月 16 日的 Studio 测试版 这是正确的答案,在 Android Studio 1.2.2 中工作。检查和验证。 使用 Android Studio 1.3.1。 为我工作过。在 android studio 2.1.2 上 :) 适用于 Android Studio 3.2.1,太棒了!仍然没有记录在任何地方!???【参考方案2】:当前解决方案
创建文件夹project/app/src/main/jniLibs
,然后将您的*.so
文件放在该位置的abi 文件夹中。例如,
project/
├──libs/
| └── *.jar <-- if your library has jar files, they go here
├──src/
└── main/
├── AndroidManifest.xml
├── java/
└── jniLibs/
├── arm64-v8a/ <-- ARM 64bit
│ └── yourlib.so
├── armeabi-v7a/ <-- ARM 32bit
│ └── yourlib.so
└── x86/ <-- Intel 32bit
└── yourlib.so
已弃用的解决方案
在您的模块 gradle.build 文件中添加两个代码 sn-ps 作为依赖项:
compile fileTree(dir: "$buildDir/native-libs", include: 'native-libs.jar')
如何创建这个自定义 jar:
task nativeLibsToJar(type: Jar, description: 'create a jar archive of the native libs')
destinationDir file("$buildDir/native-libs")
baseName 'native-libs'
from fileTree(dir: 'libs', include: '**/*.so')
into 'lib/'
tasks.withType(JavaCompile)
compileTask -> compileTask.dependsOn(nativeLibsToJar)
同样的答案也可以在相关问题中找到:Include .so library in apk in android studio
【讨论】:
Compile
任务已被弃用。改用JavaCompile
(来自相关答案)
我应该把任务放在哪里?
请先尝试jniLibs文件夹解决方案。此任务应放入您的应用程序/库 gradle.build 文件中。
jniLibs
目录路径参考Gradle Plugin User Guide - Project Structure
另见此处(列出不同的架构子文件夹):cumulations.com/blogs/9/…【参考方案3】:
解决方案 1:创建 JniLibs 文件夹
在您的应用程序中创建一个名为“jniLibs”的文件夹,并在其中包含您的 *.so 文件夹。 “jniLibs”文件夹需要创建在与“Java”或“Assets”文件夹相同的文件夹中。
解决方案 2:修改 build.gradle 文件
如果您不想创建新文件夹并将 *.so 文件保存到 libs 文件夹中,这是可能的!
在这种情况下,只需将您的 *.so 文件添加到 libs 文件夹中(请尊重与解决方案 1 相同的架构:例如 libs/armeabi/.so)并修改应用的 build.gradle 文件以添加jniLibs的源码目录。
sourceSets
main
jniLibs.srcDirs = ["libs"]
你会有更多的解释,这里有帮助你的截图(第6步):
http://blog.guillaumeagis.eu/setup-andengine-with-android-studio/
EDIT 必须是 jniLibs.srcDirs,而不是 jni.srcDirs - 编辑了代码。该目录可以是指向项目目录之外的 [相对] 路径。
【讨论】:
解决方案 2 对我不起作用。我收到一个构建错误:“在源集 'main' 上找不到属性 'jni'。” 秘密是“需要在与“Java”或“Assets”文件夹相同的文件夹中创建“jniLibs”文件夹。谢谢! 方法 1 让我能够正确编译,第二个在 AS 中创建了一个“cpp”文件夹并给了我关于缺少 C++ 编译器的错误 解决方案 2 必须使用 jniLibs.srcDirs,而不是 jni.srcDirs 以允许指定本机库的位置(路径可以是相对的或绝对的,甚至可以指向项目目录之外)。 对于解决方案 2,您需要将source Sets
代码放在 android
部分下【参考方案4】:
Android Studio 中的*.so 库
您必须在 android Studio 项目的 main 中生成 jniLibs 文件夹,并将所有 .so 文件放入其中。也可以在 build.gradle 中集成这一行
编译 fileTree(dir: 'libs', include: ['.jar','.so'])
效果很好
|--应用程序:
|--|--src:
|--|--|--main
|--|--|--|--jniLibs
|--|--|--|--|--armeabi
|--|--|--|--|--|--.so 文件
这是项目结构。
【讨论】:
在compile fileTree(dir: 'libs', include: ['.jar','.so'])中添加.so 解决了我的prb。谢谢 如果还是按照下面的解决方法,试试android ndk r10e【参考方案5】:这是我的 build.gradle 文件,请注意这一行
jniLibs.srcDirs = ['libs']
这将包括 libs 的 *.so 文件到 apk。
sourceSets
main
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['libs']
// Move the tests to tests/java, tests/res, etc...
instrumentTest.setRoot('tests')
// Move the build types to build-types/<type>
// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
// This moves them out of them default location under src/<type>/... which would
// conflict with src/ being used by the main source set.
// Adding new build types or product flavors should be accompanied
// by a similar customization.
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
【讨论】:
【参考方案6】:Android NDK 官方hello-libs
CMake 示例
https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs
刚刚在 Ubuntu 17.10 主机、Android Studio 3、Android SDK 26 上为我工作过,所以我强烈建议您将项目基于它。
共享库名为libgperf
,关键代码部分为:
hello-libs/app/src/main/cpp/CMakeLists.txt:
// -L
add_library(lib_gperf SHARED IMPORTED)
set_target_properties(lib_gperf PROPERTIES IMPORTED_LOCATION
$distribution_DIR/gperf/lib/$ANDROID_ABI/libgperf.so)
// -I
target_include_directories(hello-libs PRIVATE
$distribution_DIR/gperf/include)
// -lgperf
target_link_libraries(hello-libs
lib_gperf)
app/build.gradle:
android
sourceSets
main
// let gradle pack the shared library into apk
jniLibs.srcDirs = ['../distribution/gperf/lib']
然后,如果您在设备上查看/data/app
,libgperf.so
也会在那里。
在 C++ 代码上,使用:#include <gperf.h>
标头位置:hello-libs/distribution/gperf/include/gperf.h
库位置:distribution/gperf/lib/arm64-v8a/libgperf.so
如果您只支持某些架构,请参阅:Gradle Build NDK target only ARM
示例 git 跟踪预构建的共享库,但它也包含构建系统以实际构建它们:https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs/gen-libs
【讨论】:
【参考方案7】:我已经使用打包在 jar 文件中的外部本机 lib 依赖项解决了类似的问题。有时这些架构依赖库一起打包在一个 jar 中,有时它们被拆分为几个 jar 文件。所以我写了一些构建脚本来扫描原生库的 jar 依赖项并将它们分类到正确的 android lib 文件夹中。此外,这还提供了一种下载在 maven repos 中找不到的依赖项的方法,这对于让 JNA 在 android 上运行很有用,因为并非所有本机 jar 都发布在公共 maven repos 中。
android
compileSdkVersion 23
buildToolsVersion '24.0.0'
lintOptions
abortOnError false
defaultConfig
applicationId "myappid"
minSdkVersion 17
targetSdkVersion 23
versionCode 1
versionName "1.0.0"
buildTypes
release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
sourceSets
main
jniLibs.srcDirs = ["src/main/jniLibs", "$buildDir/native-libs"]
def urlFile = url, name ->
File file = new File("$buildDir/download/$name.jar")
file.parentFile.mkdirs()
if (!file.exists())
new URL(url).withInputStream downloadStream ->
file.withOutputStream fileOut ->
fileOut << downloadStream
files(file.absolutePath)
dependencies
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.android.support:design:23.3.0'
compile 'net.java.dev.jna:jna:4.2.0'
compile urlFile('https://github.com/java-native-access/jna/blob/4.2.2/lib/native/android-arm.jar?raw=true', 'jna-android-arm')
compile urlFile('https://github.com/java-native-access/jna/blob/4.2.2/lib/native/android-armv7.jar?raw=true', 'jna-android-armv7')
compile urlFile('https://github.com/java-native-access/jna/blob/4.2.2/lib/native/android-aarch64.jar?raw=true', 'jna-android-aarch64')
compile urlFile('https://github.com/java-native-access/jna/blob/4.2.2/lib/native/android-x86.jar?raw=true', 'jna-android-x86')
compile urlFile('https://github.com/java-native-access/jna/blob/4.2.2/lib/native/android-x86-64.jar?raw=true', 'jna-android-x86_64')
compile urlFile('https://github.com/java-native-access/jna/blob/4.2.2/lib/native/android-mips.jar?raw=true', 'jna-android-mips')
compile urlFile('https://github.com/java-native-access/jna/blob/4.2.2/lib/native/android-mips64.jar?raw=true', 'jna-android-mips64')
def safeCopy = src, dst ->
File fdst = new File(dst)
fdst.parentFile.mkdirs()
fdst.bytes = new File(src).bytes
def archFromName = name ->
switch (name)
case ~/.*android-(x86-64|x86_64|amd64).*/:
return "x86_64"
case ~/.*android-(i386|i686|x86).*/:
return "x86"
case ~/.*android-(arm64|aarch64).*/:
return "arm64-v8a"
case ~/.*android-(armhf|armv7|arm-v7|armeabi-v7).*/:
return "armeabi-v7a"
case ~/.*android-(arm).*/:
return "armeabi"
case ~/.*android-(mips).*/:
return "mips"
case ~/.*android-(mips64).*/:
return "mips64"
default:
return null
task extractNatives <<
project.configurations.compile.each dep ->
println "Scanning $dep.name for native libs"
if (!dep.name.endsWith(".jar"))
return
zipTree(dep).visit zDetail ->
if (!zDetail.name.endsWith(".so"))
return
print "\tFound $zDetail.name"
String arch = archFromName(zDetail.toString())
if(arch != null)
println " -> $arch"
safeCopy(zDetail.file.absolutePath,
"$buildDir/native-libs/$arch/$zDetail.file.name")
else
println " -> No valid arch"
preBuild.dependsOn(['extractNatives'])
【讨论】:
【参考方案8】:我有 android studio 4.1.2,当我尝试在 File -> Project Structure -> Sdk Location 中设置 ndk 路径时,即使它已经安装,它也会要求我下载 ndk,我设置了 NDK_HOME、ANDROID_NDK_HOME和 PATH 环境变量,什么都没有。唯一对我有用的是在 local.properties 中手动设置 ndk 版本,使用 ABI 及其各自的 .so 文件创建一个 jniLibs(是的,具有此确切名称)文件夹,并在构建中指定 abi 过滤器和 ndk 版本.gradle。希望这可以使其他人免于头痛。
local.properties
ndk.dir=C\:\\Users\\<user>\\AppData\\Local\\Android\\Sdk\\ndk\\22.0.7026061
build.gradle
plugins
id 'com.android.application'
android
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig
applicationId "com.example.myapplication"
minSdkVersion 22
targetSdkVersion 30
versionCode 1
versionName "1.0"
ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
sourceSets
main
jniLibs.srcDir 'jniLibs'
buildTypes
release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
compileOptions
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
ndkVersion '22.0.7026061'
...\app\src\main\
在 jniLibs 文件夹内
【讨论】:
【参考方案9】:使用本机库(so 文件) 您需要在“build.gradle”文件中添加一些代码。
此代码用于在“清理项目”时清理“armeabi”目录并将“so”文件复制到“armeabi”中。
task copyJniLibs(type: Copy)
from 'libs/armeabi'
into 'src/main/jniLibs/armeabi'
tasks.withType(JavaCompile)
compileTask -> compileTask.dependsOn(copyJniLibs)
clean.dependsOn 'cleanCopyJniLibs'
我是从下面提到的。 https://gist.github.com/pocmo/6461138
【讨论】:
以上是关于如何在 Android Studio 中包含 *.so 库?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 android studio 中包含应用内图标选择器?
[在Android Studio中,构建一个Android Wear项目,如何在两个模块中包含相同的文件
当JSON对象URL字段在android studio中包含多个URL时,如何存储来自JSON对象请求的URL?