Java 安装应用程序后,Android本机库将消失

Java 安装应用程序后,Android本机库将消失,java,android,c,android-studio,android-ndk,Java,Android,C,Android Studio,Android Ndk,切换到Android Studio后,我开始看到可怕的 java.lang.UnsatisfiedLinkError: dlopen failed: library '/data/app-lib/com.myapp.test-1/libmylib.so' not found 错误。当我解包apk时,我可以看到libmylib.so以及lib/armeabi文件夹下的所有其他本机库(libmyotherlib.so和libtest.so),所以打包应该不是问题。。。我决定在我的测试设备上设置根

切换到Android Studio后,我开始看到可怕的

java.lang.UnsatisfiedLinkError: dlopen failed: library
'/data/app-lib/com.myapp.test-1/libmylib.so' not found 
错误。当我解包apk时,我可以看到libmylib.so以及lib/armeabi文件夹下的所有其他本机库(libmyotherlib.so和libtest.so),所以打包应该不是问题。。。我决定在我的测试设备上设置根目录,并检查/data/app lib下我的应用程序文件夹的实际内容,安装后它的本机库应该在那里——我发现在设备上安装应用程序后,我的应用程序的一个本机库(libmylib.so)丢失了。libmylib.so和libmyotherlib.so是预构建的.so文件,放在src/main/jniLibs中,libtest.so是从src/main/jni中的test.c编译而来的

这是在我切换到Android Studio之后才开始的;我已经验证了在Eclipse ADT中使用相同代码构建的APK在安装后在/data/app lib/com.myapp.test-1下具有所有必需的库

Android Studio build的相关build.gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "21.1.2"

    defaultConfig {
        applicationId "com.myapp.test"
        minSdkVersion 17
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"

        ndk{

            moduleName "test"//testing ndk integration
        }

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
        }
    }

}

repositories {
    // You can also use jcenter if you prefer
    mavenCentral()
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'

    //android support libs etc.
    compile 'com.android.support:appcompat-v7:23.1.0'
    compile 'com.android.support:support-v13:23.1.0'

}
相关gradle.properties文件

android.useDeprecatedNdk=true
在src/main/jni下,我只有test.c

#include <jni.h>

int main(){

    return 0;
}
Eclipse ADT构建的相关Android.mk:

include $(CLEAR_VARS)
LOCAL_MODULE    := test
LOCAL_SRC_FILES += test.c
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := myotherlib
LOCAL_SRC_FILES :=  $(TARGET_ARCH_ABI)/libmyotherlib.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := mylib
LOCAL_SRC_FILES :=  $(TARGET_ARCH_ABI)/libmylib.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
安装Android Studio构建的应用程序后的相关/data/app lib内容:

root@SOLONE SL-K40:/ # ls /data/app-lib/com.myapp.test-1               
libmyotherlib.so
libtest.so
安装Eclipse ADT构建的应用程序后的相关/data/app lib内容:

root@SOLONE SL-K40:/ # ls /data/app-lib/com.myapp.test-1               
libmylib.so
libmyotherlib.so
libtest.so
我无意中发现,通过添加

sourceSets {
        main {
            jni.srcDirs = []
 }
}
对于build.gradle,我可以让libmylib.so在安装后再次显示,但这就排除了在我的项目中包含任何NDK源代码

第一个问题: 知道这里发生了什么吗?可能是mylib实际上是为armeabi以外的abi编译的,Android放弃了它,因为它的实际abi与apk中的文件夹不匹配(我没有mylib的源代码)?我的问题听起来与讨论的问题相似,但那个人似乎在最终安装的应用程序中只看到一个共享库;除了我的一个共享库之外,我看到了所有的库

第二个问题:
在Android Studio构建中包含预构建的.so文件的当前正确方式是什么?Android Studio版本(我使用的是Android Studio 1.5、Gradle版本2.4、Android插件版本1.3.0)之间的差异似乎很大,是否仍然需要将jniLibs.srcDir变量重定向到src/main/libs?

是的,最好的方法是定义jniLibs.srcDir,以便所有预构建的库都可以从那里复制

是的,ABI是问题的最可能来源。如果预构建库是为armeabi构建的,但该设备(今天绝大多数设备)支持armeabi-v7a,那么安装程序将很高兴地将未预构建库的…v7a版本复制到/data/app lib/com.myapp.test-1,加载程序稍后会抱怨libmylib.so丢失

您应该指示Android Studio只构建一个ABI。如果您在Eclipse构建中没有做一些特殊的事情,那么很可能是armeabi

指示AS的方式取决于gradle插件的版本

对于'com.android.tools.build:gradle:1.5.0'插件,我使用了

android {
    defaultConfig.ndk {
        …
        abiFilter 'armeabi'
    }

    splits {
        abi {
            enable true
            reset()
            include 'armeabi'
        }
    }
}
对于…gradle实验:0.2.0,我使用

model {
    android.ndk {
        …
        abiFilters += 'armeabi'
    }
}

我不需要在实验插件上启用拆分,因此我不会在语法更改方面误导您。

我猜这是一项累进的任务,它正在破坏构建首先,您不需要root访问/data/app lib/com.myapp.test-1/@AlexCohn true中的库,但是您确实需要root用户通过adb shell“ls-al/data/app lib”列出/data/app lib的内容,我不想在运行时从Context::getApplicationInfo()获取我的应用程序文件夹的名称。nativeLibraryDir@CCJ如果您正在运行调试应用程序,则不需要这样做:嗯,奇怪。我想知道libmyotherlib是如何/为什么通过安装过程的?最终的apk对所有ABI都有一个libtest,包括armeabi-v7a,但libmyotherlib仅存在于armeabi中……安装程序是否检测到设备的/system/lib目录中有一个名为libmylib的库?如果是这样的话,这就可以解释为什么libmyotherlib通过了安装,而libmylib被抛出了——我正在加载的实际库是在我的测试设备上的/system/lib下找到的一个库的修改版本,因此和/或您提到的abi最佳匹配过滤可以解释我看到的行为
model {
    android.ndk {
        …
        abiFilters += 'armeabi'
    }
}