简体   繁体   中英

Link static library to JNI shared library in Android

I'm new to Android, so forgive me if this seems a little amature. I have two pre-built static libraries, feta ( ../../feta/build/libfeta.a ) and mish ( ../../mish/build/libmish.a ), and I have the shared JNI library. Using the JNI library works perfectly fine, but I'm trying to access both feta and mish via the JNI library. These two libraries are constantly changed and updated along with the Android project so copying them every time they're built isn't really an option (if that'd even fix the linking problem), and I'd much not prefer simply copying the source files into the Android project.

I've tried searching, but most of the answers use the old version of the system and want me to modify Android.mk , which I don't have. I'm using the most recent version of Android Studio, it uses the Gradle plugin.

I've attempted to use all the configuration from over a dozen tutorials and Stackoverflow answers in various setups, but with no luck.

If you answer, please provide a full and working build.gradle so I don't run into the same problems I've been getting from the other answers (thanks!).

I've asked this question after just following this tutorial, so all the files will reflect that.

Here's the build error I'm getting:

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.

Here's my build.gradle file inside the app module:

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

And here's the root ( mish-android ) directory one:

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

And here's my 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} )

Here's my directory structure if it helps at all.

在此输入图像描述

As it turns out, I needed to upgrade my Gradle plugin. I was able to delete CMakeLists.txt . I also needed to upgrade my Gradle wrapper version to 3.2 to support the new experimental plugin.

Here's my root 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
}

Here's my app 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'
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM