Add .so (prebuilt) library from another directory to APK
Asked Answered
M

2

5

I am trying to include my .so library from another directory. Compiling my project works fine. But when I run it, it gives me

java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.company.gimikapp-2/base.apk"],nativeLibraryDirectories=[/data/app/com.company.gimikapp-2/lib/arm, /vendor/lib, /system/lib]]] couldn't find "libtheprebuiltlib.so"

Common solutions I see in SO is this:

sourceSets {
    main {
        jniLibs.srcDirs = ['src/main/jniLibs']
    }
}

Tried both

jniLibs.srcDirs = ['C:\\svn\\sys_libs']

and

jniLibs.srcDirs = ['C:/svn/sys_libs']

How do you actually point it to another directory outside your Android project?

This is my CMakeList.txt:

cmake_minimum_required(VERSION 3.4.1)
add_library( native-lib
            SHARED
            src/main/cpp/source/native-lib.cpp )
add_library(theprebuiltlib SHARED IMPORTED)
set_target_properties(theprebuiltlib PROPERTIES IMPORTED_LOCATION
            C:/svn/sys_libs/libtheprebuiltlib.so)
target_include_directories(
            native-lib PRIVATE
            src/main/cpp/source/
            C:/svn/sys_includes/)
find_library( log-lib
            log)
target_link_libraries( native-lib
            theprebuiltlib
            ${log-lib})

And here is my gradle setup for my JNI:

android {
    ...
    defaultConfig {
        ...
        externalNativeBuild {
            cmake {
                cppFlags "-frtti -fexceptions"
            }
            ndk {
                abiFilters 'armeabi'
            }
        }
        ...
    }
    ...
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
    sourceSets {
        main {
            jniLibs.srcDirs = ['C:/svn/sys_libs']
        }
    }
}
Malmo answered 6/6, 2018 at 6:51 Comment(10)
developer.android.com/studio/projects/…Kikelia
check this solution medium.com/mobiwise-blog/…Kikelia
the medium.com link discusses a solution when .so is inside the android project. mine is outside the project, specifically in C:/svn/sys_libs/Malmo
I think you have to copy the .so file in the jniLibs folder manually or just link statically if you have a static version.Uncrowned
First, to eliminate some situations that might cause the problem, check your APK file. If it has lib folder, what files do you find there? Android Studio has Analyze APK in the top menu.Grating
I used Analyze APK, lib folder is emptyMalmo
Let's try to remove the jniLibs setting from build.gradle, and check how the APK changes. BTW, maybe the part where you launch cmake is incorrect, please post it here, too.Grating
with or without jniLibs.srcDirs, it's the same. "launch cmake" - what do you mean? the cmake declaration in gradle?Malmo
There are usually two externalNativeBuild blocks in build.gradle. But just in case, show this file as it is, there are too many ways to get it wrong.Grating
added. hopefully it helps you help me. :)Malmo
G
3

Apparently, you have NDK r17 installed and Android plugin v.3.1.0 or higher (we don't see this in the published fragment of build.gradle).

But you set abiFilters to armeabi, which has been dropped. You should set it to armeabi-v7a, and make sure that libtheprebuiltlib.so is also built for this ABI, or you can download an older version of NDK and in build.gradle dependencies set

classpath 'com.android.tools.build:gradle:3.0.1'

You can force the latest plugin handle armeabi if you set it explicitly:

android {
    defaultConfig {
        ndk {
            abiFilters 'armeabi'
        }
    }
}

(in your script, it is under android.defaultConfig.externalNativeBuild.ndk, so has no effect).

One mistake in your build.gradle, it should read

android {
  sourceSets {
     main { 
       jniLibs.srcDir 'C:/svn/sys_libs' 
     }
   }
}

when you have the file C:\svn\sys_libs\armeabi\libtheprebuiltlib.so. But this does not explain why cmake does not work as expected.

Grating answered 10/6, 2018 at 12:47 Comment(6)
thanks for continued support. I am using NDK r16 but using the latest gradle. (giving you +1 though as this answer might be helpful to others.)Malmo
this doesnt seem to work. i tried gradle 3.0.1, ndk r16, and moved abiFilters to android.defaultConfig.ndk. i am sure my .so file is for armeabiMalmo
OK, let's step back then. Comment out the externalNativeBuild block(s), and see if the prebuilt lib gets packed (as pointed by jniLibs).Grating
removed all externalNativeBuild blocks. set android.sourceSets.main.jniLibs.srcDirs = ['C:/svn/sys_libs'], .so is still missing.Malmo
what about a relative path instead ?Pianette
@OlivierMATROT sure, you can use relative paths anywhere. In gradle, all paths should be relative to the gradle project directory, which is where build.gradle file resides.Grating
M
2

For NDK r16 and Gradle plugin v3.1.2, here is the step by step solution (thanks to @Alex Cohn).

  1. Set android.sourceSets.main.jniLibs.srcDir to point to the location of external .so

    android {
        sourceSets {
            main { 
                jniLibs.srcDir 'C:/svn/sys_libs' 
            }
       }
    }
    
  2. Make sure that your external .so is located in the above path (step1), appended by correct architecture. In my case, it is armeabi, thus my .so is in

    C:/svn/sys_libs/armeabi/libtheprebuiltlib.so
    
  3. Move ndk from android.defaultConfig.externalNativeBuild.ndk to android.defaultConfig.ndk like so

    android {
        defaultConfig {
            ndk {
                abiFilters 'armeabi'
            }
        }
    }
    
  4. Make sure that CMakeLists.txt points to the complete path with proper architecture.

    set_target_properties(theprebuiltlib PROPERTIES IMPORTED_LOCATION
            C:/svn/sys_libs/armeabi/libtheprebuiltlib.so)
    
Malmo answered 11/6, 2018 at 17:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.