4

Android用の静的libcurlをコンパイルしましたが、CurlResコード6、つまりCURLE_COULDNT_RESOLVE_HOSTを継続的に受信しています。

Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := Curl

LOCAL_SRC_FILES := prebuild/libcurl.a

include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE    := ccSharedLib

LOCAL_SRC_FILES := main-jni.cpp

LOCAL_STATIC_LIBRARIES := Curl 

include $(BUILD_SHARED_LIBRARY)

main-jni.cpp

extern "C" {
    size_t write_data(void *ptr, size_t size, size_t count, FILE *stream)
        {
            size_t written;
            written = fwrite(ptr, size, count, stream);
            printf("data sent, size = %lu",written);
            return written;
        }

    jint
        Java_com_example_testlibcurl_MainActivity_test1( JNIEnv*  env,
                                        jobject  thiz, jstring downloadDirectoryPath)
        {
            CURLcode res;
            res = curl_global_init(CURL_GLOBAL_ALL);

            jint temp = 3;

            printf("Method called");
            const char *nativeDownloadDirPath = env->GetStringUTFChars(downloadDirectoryPath,0);
            // Test code for calling methods of libCURL
            CURL *curl;
            FILE *fp;
            std::string s = "http://travel.paintedstork.com/blog/wp-content/uploads/2012/10/2013-calendar-images-1.jpg";
            curl = curl_easy_init();
            if(curl)
            {
                fp = fopen(nativeDownloadDirPath, "wb");
            res = curl_easy_setopt(curl, CURLOPT_URL, s.c_str());
                res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
                res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
                res = curl_easy_perform(curl);
                curl_easy_cleanup(curl);
                if(fp)
                    fclose(fp);
            }
            return res;
        }
}

このコードはWebソースから画像をダウンロードしていますが、「curl_easy_perform」メソッドが呼び出されるたびにエラーコード6が表示されます。別のURLでこれを確認しましたが、まだ失敗しています:(.. ..

「android.permission.INTERNET」および「android.permission.WRITE_EXTERNAL_STORAGE」権限は、マニフェストファイルですでに付与されています。

これを解決するためのポインタは、大きな助けになります。

4

2 に答える 2

1

有効なファイル名書き込み可能なディレクトリパスをfopenに渡すようにしてください。

私は得ていた

0x00000010(コード= 1)での致命的な信号11(SIGSEGV)..。

fopenがファイルではなくディレクトリを開こうとしたためです。

EclipseからLogCatのログを確認するか、adblogcatを使用して他の考えられるエラーを確認してください。

次の変更を加えてコードをテストしましたが、機能します。

MainActivity.java

public class MainActivity
{
    private static final String TAG = MainActivity.class.getName();

    static
    {
        try
        {
            System.loadLibrary("mynativelib");
        }
        catch (UnsatisfiedLinkError ex)
        {
            Log.e(TAG, "WARNING: Could not load native library: " + ex.getMessage());
        }
    }

    public static native int DownloadFile(String downloadDirectoryPath);

   @Override
   protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        int res = DownloadFile(Environment.getExternalStorageDirectory().getAbsolutePath()
                + File.separator + Environment.DIRECTORY_DOWNLOADS + File.separator 
                + "test.jpg");
        Log.d(TAG, "Result Code: " + res);
    }
}

main-jni.cpp

#include <jni.h>
#include <android/log.h>
#include <string>
#include <curl/curl.h>

#define LOG_TAG "native"

#define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOG_ERROR(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOG_WARN(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOG_DEBUG(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

#ifdef __cplusplus
extern "C"
{
#endif

    // [FIX for Android 4.2.x]
    // "WARNING: Could not load native library:
    // Cannot load library: soinfo_relocate(linker.cpp:975): cannot locate symbol "__exidx_end" referenced by"
    // http://stackoverflow.com/a/14501998/313113
    void __exidx_start()
    {
    }
    void __exidx_end()
    {
    }

    size_t write_data(void *ptr, size_t size, size_t count, FILE *stream)
    {
        size_t written;
        written = fwrite(ptr, size, count, stream);
        LOG_DEBUG("Writing data to file stream %u", written);
        return written;
    }

    jint Java_com_company_awesomeapp_MainActivity_DownloadFile(JNIEnv* env, jobject thiz,
            jstring downloadDirectoryPath)
    {
        CURLcode res;
        res = curl_global_init(CURL_GLOBAL_ALL);

        jint temp = 3;

        LOG_DEBUG("Downloading file");
        const char *nativeDownloadDirPath = env->GetStringUTFChars(downloadDirectoryPath, 0);

        LOG_DEBUG(nativeDownloadDirPath);

        CURL *curl;
        FILE *fp;
        std::string url = "http://travel.paintedstork.com/blog/wp-content/uploads/2012/10/2013-calendar-images-1.jpg";

        curl = curl_easy_init();
        if (curl)
        {
            fp = fopen(nativeDownloadDirPath, "wb");
            res = curl_easy_setopt(curl, CURLOPT_URL, url.c_str());

            LOG_DEBUG("Before write function");
            res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
            LOG_DEBUG("After write function");

            LOG_DEBUG("Before write data");
            res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
            LOG_DEBUG("After write data");

            res = curl_easy_perform(curl);
            curl_easy_cleanup(curl);

            if (fp) fclose(fp);
        }

        env->ReleaseStringUTFChars(downloadDirectoryPath, nativeDownloadDirPath);

        return res;
    }

/**
     * The VM calls JNI_OnLoad when the native library is loaded (for example, through System.loadLibrary).
     * JNI_OnLoad must return the JNI version needed by the native library.
     *
     * @see http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html#JNI_OnLoad
     */JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
    {
        JNIEnv* env;
        if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
        {
            return -1;
        }

        // [*] Get jclass with env->FindClass.
        // [*] Register methods with env->RegisterNatives.
        //jniRegisterNativeMethods(env, "dev/android/sample/AndroidNDKSampleActivity", sMethods, NELEM(sMethods));

        return JNI_VERSION_1_6;
    }

/**
     * The VM calls JNI_OnUnload when the class loader containing the native library is garbage collected.
     * This function can be used to perform cleanup operations.
     *
     * Because this function is called in an unknown context (such as from a finalizer),
     * the programmer should be conservative on using Java VM services, and refrain from arbitrary
     * Java call-backs.
     * @see http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html#JNI_OnUnload
     */JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *reserved)
    {

    }


#ifdef __cplusplus
}
#endif

ファイルは次の場所に保存されます:/storage/emulated/0/Download/test.jpg

于 2013-03-07T14:09:10.460 に答える
1

これは、23未満のAndroid APIレベルをターゲットにしているときlibcurlに、スレッドリゾルバー(CMa​​keオプション)なしでコンパイルした場合にも発生する可能性があります。ENABLE_THREADED_RESOLVER

問題は、の実装に次のCMake/CurlTests.c行が含まれているためです。

#ifndef gethostbyaddr_r
  (void)gethostbyaddr_r;
#endif

ただし、netdb.hAndroid NDKでヘッダーを確認すると、次のように表示されます。

#if __ANDROID_API__ >= 23
int gethostbyaddr_r(const void* __addr, socklen_t __length, int __type, struct hostent* __ret, char* __buf, size_t __buf_size, struct hostent** __result, int* __h_errno_ptr) __INTRODUCED_IN(23);
#endif /* __ANDROID_API__ >= 23 */

これは、マシュマロより古いAndroidをターゲットにしている場合、この機能は使用できないことを意味します。これは問題があります。テストはHAVE_GETHOSTBYNAME_R成功しますが、テストはHAVE_GETHOSTBYNAME_R_6失敗します(ただし、成功するはずです)。次のエラーが発生します(で確認できますCMakeError.log)。

/path/to/curl/CMake/CurlTests.c:128:9: error: use of undeclared identifier 'gethostbyaddr_r'
  (void)gethostbyaddr_r;
        ^
1 error generated.

Curl_ipv4_resolve_rこれにより、ファイル内の関数で操作なしの動作が発生しますhostip4.c。これは、afterが定義されていることを想定しているため、、、またはのHAVE_GETHOSTBYNAME_R少なくとも1つです。したがって、curlはホストを解決しようとさえしません。HAVE_GETHOSTBYNAME_R_5HAVE_GETHOSTBYNAME_R_6HAVE_GETHOSTBYNAME_R_3

この問題を修正するには、これらの問題のある行をから削除するだけCMake/CurlTest.cです。

公式ドキュメントconfigureのようにスクリプトを使用してcurlを構築しようとはしませんでしたが、作成したとしても、OpenSSLを介してSSLをサポートする場合は、Android M以上をターゲットにする必要があると明確に述べられていますが、単純なHTTPサポートのAFAIKは機能するはずです。 。

スレッド化されたリゾルバーを使用する場合、DNS解決を実行するために異なるシステムAPIを使用するため(getaddrinfoの機能Curl_getaddrinfo_excurl_addrinfo.c)、問題はなくなりました。getaddrinfo最新のAPIですが、組み込みシステムなど、スレッドのサポートが不足している可能性があるすべてのプラットフォームカールターゲットで使用できるとは限りません。したがって、curlは、スレッドが無効になっている場合、DNS解決で従来のアプローチを使用します。

PS 7年以上後にこの質問を復活させて申し訳ありませんが、あなたとまったく同じ問題に直面した後、このStackOverflowの質問は唯一の同様のGoogle検索結果でした

于 2020-09-22T13:45:25.723 に答える