android - 将静态库链接到 Android 中的 JNI 共享库

标签 android gradle android-ndk java-native-interface

我是 Android 的新手,如果这看起来有点成熟,请原谅我。我有两个预构建的静态库,feta (../../feta/build/libfeta.a) 和 mish (../../mish/build/libmish.a),我有共享的 JNI 库。使用 JNI 库工作得很好,但我试图通过 JNI 库访问 fetamish。这两个库与 Android 项目一起不断更改和更新,因此每次构建它们时都复制它们并不是一个真正的选择(如果这样甚至可以解决链接问题),我不喜欢简单地复制将源文件导入到 Android 项目中。

我试过搜索,但大多数答案都使用旧版本的系统,要我修改Android.mk,我没有。我使用的是最新版本的 Android Studio,它使用了 Gradle 插件。

我尝试在各种设置中使用来自十几个教程和 Stackoverflow 答案的所有配置,但没有成功。

如果您回答,请提供完整且有效的 build.gradle,这样我就不会遇到与其他答案相同的问题(谢谢!)。

我在关注 this 之后问了这个问题教程,因此所有文件都会反射(reflect)这一点。

这是我遇到的构建错误:

Error:A problem occurred configuring project ':app'.
> The following model rules could not be applied due to unbound inputs and/or subjects:
    android.sources { ... } @ app/build.gradle line 58, column 5
      subject:
        - android.sources Object [*]
    repositories { ... } @ app/build.gradle line 39, column 5
      subject:
        - repositories Object [*]
  [*] - indicates that a model item could not be found for the path or type.

这是我在 app 模块中的 build.gradle 文件:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "com.neonorb.mish_android"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags "-std=c++14 -Wno-implicit-exception-spec-mismatch"
            }
        }
        ndk {
            // ${targetPlatform.getName()}
            // ${buildType.getName()}
            stl "c++_static"
            abiFilters "x86_64"
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

model {
    repositories {
        libs(PrebuiltLibraries) {
            feta {
                headers.srcDir "../../feta/include/"
                binaries.withType(StaticLibraryBinary) {
                    staticLibraryFile = file("../../feta/build/libfeta.a")
                }
            }
        }
        libs(PrebuiltLibraries) {
            mish {
                headers.srcDir "../../mish/include/"
                binaries.withType(StaticLibraryBinary) {
                    staticLibraryFile = file("../../mish/build/libmish.a")
                }
            }
        }
    }

    android.sources {
        main {
            jni {
                dependencies {
                    library "feta" linkage "static"
                    library "mish" linkage "static"
                }
            }
        }
    }
}

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'
    compile 'com.google.android.gms:play-services-ads:10.0.1'
    compile 'com.android.support:design:25.1.0'
    testCompile 'junit:junit:4.12'
}

这是根 (mish-android) 目录之一:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

这是我的 CMakeLists.txt:

# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
             mish-android

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             # Associated headers in the same location as their source
             # file are automatically included.
             src/main/cpp/mish.cpp )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because system libraries are included in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
                       mish-android

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

如果有帮助的话,这是我的目录结构。

enter image description here

最佳答案

事实证明,我需要升级我的 Gradle 插件。我能够删除 CMakeLists.txt。我还需要将我的 Gradle 包装器版本升级到 3.2 以支持新的实验性插件。

这是我的根 build.gradle:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        //classpath 'com.android.tools.build:gradle:2.2.3'
        classpath 'com.android.tools.build:gradle-experimental:0.9.0-beta1'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

这是我的应用 build.gradle:

apply plugin: 'com.android.model.application'

model {
    android {
        compileSdkVersion 25
        buildToolsVersion "25.0.2"
        defaultConfig {
            applicationId "com.neonorb.mish_android"
            minSdkVersion.apiLevel 15
            targetSdkVersion.apiLevel 25
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
        ndk {
            moduleName "mish-android"
            ldLibs.add("log")
            cppFlags.add("-std=c++14")
            cppFlags.add("-Wno-implicit-exception-spec-mismatch")
            // ${targetPlatform.getName()}
            // ${buildType.getName()}
            stl "c++_static"
            abiFilters.addAll(["x86_64"])
            // only build for x86_64 because that's all Feta and Mish support atm
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles.add(file("proguard-rules.pro"))
            }
        }
        sources {
            main {
                jni {
                    source {
                        srcDir "src"
                    }
                    dependencies {
                        library "feta" linkage "static"
                        library "mish" linkage "static"
                    }
                }
            }
        }
    }
    repositories {
        libs(PrebuiltLibraries) {
            feta {
                headers.srcDir "../../feta/include/"
                binaries.withType(StaticLibraryBinary) {
                    staticLibraryFile = file("../../feta/build/libfeta.a")
                }
            }
        }
        libs(PrebuiltLibraries) {
            mish {
                headers.srcDir "../../mish/include/"
                binaries.withType(StaticLibraryBinary) {
                    staticLibraryFile = file("../../mish/build/libmish.a")
                }
            }
        }
    }
}

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'
}

关于android - 将静态库链接到 Android 中的 JNI 共享库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41446393/

相关文章:

java - 将自定义属性添加到现有 View

java - 通过 XML 与服务器和 Android 客户端通信

Maven - 发布多个子模块/Artifact

android - 如何在android中获取时间提前值?

android - Unwind_Backtrace 中的堆栈跟踪与映射文件地址不匹配

android - 实现从服务到 Activity 的回调

android - RecyclerView notifyDataSetChanged 滚动到顶部位置

android-studio - Android Studio错误

gradle - 使用 build.gradle.kts 发布到 mavenLocal

android - 无法找到 android NDK 堆栈跟踪