Android的Unsatisfiedlinkerror OpenALPRtesting项目

几天后,我正在为Android构buildOpenALPR示例项目 。 它build立并启动,但在调用本地方法来识别它之后例外:

java.lang.RuntimeException: An error occured while executing doInBackground() at android.os.AsyncTask$3.done(AsyncTask.java:299) at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352) at java.util.concurrent.FutureTask.setException(FutureTask.java:219) at java.util.concurrent.FutureTask.run(FutureTask.java:239) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573) at java.lang.Thread.run(Thread.java:838) Caused by: java.lang.UnsatisfiedLinkError: Native method not found: org.openalpr.AlprJNIWrapper.recognizeWithCountryRegionNConfig:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String; at org.openalpr.AlprJNIWrapper.recognizeWithCountryRegionNConfig(Native Method) at org.openalpr.app.AlprFragment$AlprTask.doInBackground(AlprFragment.java:78) at org.openalpr.app.AlprFragment$AlprTask.doInBackground(AlprFragment.java:1) at android.os.AsyncTask$2.call(AsyncTask.java:287) at java.util.concurrent.FutureTask.run(FutureTask.java:234) ... 4 more 

我什么都做不了,它一直都是。

Application.mk

 APP_ABI := armeabi-v7a APP_CPPFLAGS := -frtti -fexceptions APP_STL := gnustl_static 

Android.mk经过我所有的尝试

 LOCAL_PATH := $(call my-dir) LIB_PATH := $(LOCAL_PATH)/../libs/armeabi-v7a include $(CLEAR_VARS) LOCAL_MODULE := leptonica LOCAL_SRC_FILES := 3rdparty/liblept.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := tesseract LOCAL_SRC_FILES := 3rdparty/libtess.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := simpleini LOCAL_SRC_FILES := 3rdparty/libsimpleini.a include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := support LOCAL_SRC_FILES := 3rdparty/libsupport.a include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := openalpr LOCAL_SRC_FILES := 3rdparty/libopenalpr-static.a include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) OPENCV_INSTALL_MODULES:=on OPENCV_CAMERA_MODULES:=off include d:\Other\robovisor_mobile\OpenCV-android-sdk\sdk\native\jni\OpenCV.mk LOCAL_MODULE := openalpr-native SOURCE_LIST := $(wildcard $(LOCAL_PATH)/*.cpp) HEADER_LIST := $(wildcard $(LOCAL_PATH)/*.h) LOCAL_SRC_FILES := AlprJNIWrapper.cpp LOCAL_SRC_FILES += $(HEADER_LIST:$(LOCAL_PATH)/%=%) LOCAL_SRC_FILES += $(SOURCE_LIST:$(LOCAL_PATH)/%=%) LOCAL_EXPORT_C_INCLUDES += /home/sujay/builds/src/openalpr/src/openalpr LOCAL_EXPORT_C_INCLUDES += /home/sujay/builds/src/OpenCV-2.4.9-android-sdk/sdk/native/include FILE_LIST := $(foreach dir, $(LOCAL_EXPORT_C_INCLUDES), $(wildcard $(dir)/*.cpp)) LOCAL_SRC_FILES := $(FILE_LIST:$(LOCAL_PATH)/%=%) LOCAL_C_INCLUDES += /home/sujay/builds/src/openalpr/src/openalpr LOCAL_C_INCLUDES += /home/sujay/builds/src/OpenCV-2.4.9-android-sdk/sdk/native/include LOCAL_C_INCLUDES += /home/sujay/tools/android-ndk-r10/platforms/android-19/arch-arm/usr/include LOCAL_SHARED_LIBRARIES += tesseract leptonica LOCAL_STATIC_LIBRARIES += openalpr support simpleini LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY) 

AlprJNIWrapper.cpp包含我所需的原生函数

 /** * Created by sujay on 13/11/14. */ #include <string> #include <sstream> #include <cstdio> #include <iostream> // openCV includes #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" // open alpr includes #include "support/filesystem.h" #include "support/timing.h" #include "alpr.h" #include "cjson.h" #include "AlprJNIWrapper.h" #include "AlprNative.h" using namespace alpr; JNIEXPORT jstring JNICALL Java_org_openalpr_AlprJNIWrapper_recognize(JNIEnv *env, jobject object, jstring jimgFilePath, jint jtopN) { jstring defaultCountry = env->NewStringUTF("us"); jstring defaultRegion = env->NewStringUTF(""); jstring defaultConfigFilePath = env->NewStringUTF(CONFIG_FILE); return _recognize(env, object, defaultCountry, defaultRegion, jimgFilePath, defaultConfigFilePath, jtopN); } JNIEXPORT jstring JNICALL Java_org_openalpr_AlprJNIWrapper_recognizeWithCountryNRegion( JNIEnv *env, jobject object, jstring jcountry, jstring jregion, jstring jimgFilePath, jint jtopN) { jstring defaultConfigFilePath = env->NewStringUTF(CONFIG_FILE); return _recognize(env, object, jcountry, jregion, jimgFilePath, defaultConfigFilePath, jtopN); } JNIEXPORT jstring JNICALL Java_org_openalpr_AlprJNIWrapper_recognizeWithCountryRegionNConfig (JNIEnv *env, jobject object, jstring jcountry, jstring jregion, jstring jimgFilePath, jstring jconfigFilePath, jint jtopN) { return _recognize(env, object, jcountry, jregion, jimgFilePath, jconfigFilePath, jtopN); } jstring _recognize(JNIEnv *env, jobject object, jstring jcountry, jstring jregion, jstring jimgFilePath, jstring jconfigFilePath, jint jtopN) { const char* countryChars = env->GetStringUTFChars(jcountry, NULL); std::string country(countryChars); env->ReleaseStringUTFChars(jcountry, countryChars); if(country.empty()) { country = "us"; } const char* configFilePathChars = env->GetStringUTFChars(jconfigFilePath, NULL); std::string configFilePath(configFilePathChars); env->ReleaseStringUTFChars(jconfigFilePath, configFilePathChars); if(configFilePath.empty()) { configFilePath = "/etc/openalpr/openalpr.conf"; } const char* imgFilePath = env->GetStringUTFChars(jimgFilePath, NULL); int topN = jtopN; std::string response = ""; cv::Mat frame; Alpr alpr(country, configFilePath); const char* regionChars = env->GetStringUTFChars(jregion, NULL); std::string region(regionChars); env->ReleaseStringUTFChars(jregion, regionChars); if(region.empty()) { alpr.setDetectRegion(true); alpr.setDefaultRegion(region); } alpr.setTopN(topN); if (alpr.isLoaded() == false) { env->ReleaseStringUTFChars(jimgFilePath, imgFilePath); response = errorJsonString("Error initializing Open Alpr"); return env->NewStringUTF(response.c_str()); } if(fileExists(imgFilePath)) { frame = cv::imread(imgFilePath); response = detectandshow(&alpr, frame, ""); } else { response = errorJsonString("Image file not found"); } env->ReleaseStringUTFChars(jimgFilePath, imgFilePath); return env->NewStringUTF(response.c_str()); } JNIEXPORT jstring JNICALL Java_org_openalpr_AlprJNIWrapper_version (JNIEnv *env, jobject object) { return env->NewStringUTF(Alpr::getVersion().c_str()); } std::string detectandshow(Alpr* alpr, cv::Mat frame, std::string region) { std::vector < uchar > buffer; std::string resultJson = ""; cv::imencode(".bmp", frame, buffer); std::vector < char > buffer1; for(std::vector < uchar >::iterator i = buffer.begin(); i < buffer.end(); i++) { buffer1.push_back(*i); } timespec startTime; getTimeMonotonic(&startTime); //std::vector < AlprResults > results = alpr->recognize(buffer); AlprResults results = alpr->recognize(buffer1); timespec endTime; getTimeMonotonic(&endTime); double totalProcessingTime = diffclock(startTime, endTime); //if (results.size() > 0) { resultJson = alpr->toJson(results/*, totalProcessingTime*/); } return resultJson; } std::string errorJsonString(std::string msg) { cJSON *root; root = cJSON_CreateObject(); cJSON_AddTrueToObject(root, "error"); cJSON_AddStringToObject(root, "msg", msg.c_str()); char *out; out = cJSON_PrintUnformatted(root); cJSON_Delete(root); std::string response(out); free(out); return response; } 

AlprJNIWrapper.java调用本地方法

 /** * */ package org.openalpr; /** * @author sujay * */ public class AlprJNIWrapper implements Alpr { static { System.loadLibrary("lept"); System.loadLibrary("tess"); System.loadLibrary("opencv_java"); System.loadLibrary("openalpr-native"); } /* (non-Javadoc) * @see org.openalpr.Alpr#recognize(java.lang.String, int) */ @Override public native String recognize(String imgFilePath, int topN); /* (non-Javadoc) * @see org.openalpr.Alpr#recognizeWithCountryNRegion(java.lang.String, java.lang.String, java.lang.String, int) */ @Override public native String recognizeWithCountryNRegion(String country, String region, String imgFilePath, int topN); /* (non-Javadoc) * @see org.openalpr.Alpr#recognizeWithCountryRegionNConfig(java.lang.String, java.lang.String, java.lang.String, java.lang.String, int) */ @Override public native String recognizeWithCountryRegionNConfig(String country, String region, String imgFilePath, String configFilePath, int topN); /* * (non-Javadoc) * @see org.openalpr.Alpr#version() */ @Override public native String version(); } 

编辑

有关于我的手机上的处理器的信息。

 Processor : ARMv7 Processor rev 3 (v7l) processor : 0 BogoMIPS : 1993.93 Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpv4 idiva idivt CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xc07 CPU revision : 3 

再次编辑

我试图得到结果.so文件中的函数的信息,有我得到:

 Symbol table '.dynsym' contains 6 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 FUNC GLOBAL DEFAULT UND __cxa_finalize 2: 00000000 0 FUNC GLOBAL DEFAULT UND __cxa_atexit 3: 00002004 0 NOTYPE GLOBAL DEFAULT ABS _edata 4: 00002004 0 NOTYPE GLOBAL DEFAULT ABS __bss_start 5: 00002004 0 NOTYPE GLOBAL DEFAULT ABS _end 

我从它得到:

 <ndk_path>\toolchains\arm-linux-androideabi-4.8\prebuilt\windows\bin>arm-linux-androideabi-readelf.exe -Ws <projects_path>\libs\armeabi-v7a\libopenalpr-native.so 

难道我做错了什么? 或者.so文件中真的没有我的function?

可能有几个问题。
首先,你在不受支持的设备上运行示例,就像为armeabi-v7构build的lib(以及由于在make文件中设置APP_ABI := armeabi-v7a确定),而你的设备是Intel x86或者低于7 armeabi版本等。
可能是因为样本已经过时,而lib项目已经更新,所以一些方法的名称已经改变或方法已被淘汰,等等。
另外编译NDK库是包敏感的,所以如果你把JNI类放到不同的包中,它也不会工作。
另外,原生库.so文件必须放置在您的项目的正确位置,而不是放置jar-libs的libs文件夹。 它有点不同的文件夹像android studio:

… \ src \ main \ jniLibs \ aremabi-v7a \ libYourLib.so(对于aremabi-v7a版本)
… \ src \ main \ jniLibs \ x86 \ libYourLib.so(适用于x86版本等)

更新:
不要忘记尊重最低的API级别是19.应用程序不会在API级别较低的设备上工作,我的意思是您可以更改项目中的最小API级别 – 不要这样做。
这里的问题是, libopenalpr-native.so有一个破折号在它的名字。 Dash是AOS资源命名的受限字符。 所以我用“_”replace它, 现在应用程序可以工作了,并在此处replace它:

 System.loadLibrary("openalpr_native"); 

而我没有使用你的.so版本,但只有项目之一。
UPDATE
看看: http ://prntscr.com/6w6qfx你的lib比原来的1.7Mb只有5kb肯定是有问题的。 并在评论中解释你的问题:

为什么System.loadLibrary(“openalpr-native”)没有错误? 我只是无法理解这种情况 – 创buildlibopenalpr-native.so文件,它加载到编程,没有方法。

你可以使用包含在示例项目中的原始库吗? 只是为了testing。

没有正确的方法在你的库中发现是由于名称不匹配,你应该包装你的JNI函数代码与extern "C"在C + +代码。