linux系统下jni封装curl,android java使用curl

libcurl主要功能就是用不同的协议连接和沟通不同的服务器~也就是相当封装了的sockPHP 支持libcurl(允许你用不同的协议连接和沟通不同的服务器)。, libcurl当前支持http, https, ftp, gopher, telnet, dict, file, 和ldap 协议。libcurl同样支持HTTPS证书授权,HTTP POST, HTTP PUT, FTP 上传(当然你也可以使用PHP的ftp扩展), HTTP基本表单上传,代理,cookies,以及用户认证。

PHP具备curl扩展,但是java却不具备curl功能。此文章介绍如何在linux系统下,通过jni封装curl,供java进行调用

在Ubuntu下面,首先安装libcurl库

sudo aptitude install libcurl4-openssl-dev

如果需要使用最新的libcurl库,那么就需要自行下载源码来编译安装了,为了简单,采用apt方式安装也没什么。

libcurl的API就不多做介绍了,初始化以及清理curl都是通过native来进行调用的,因此要进行一个封装

public Curl() {
        if (!INIT) {
            curlGlobalInit(CurlConstant.CURL_GLOBAL_DEFAULT);
        }
    }
 
    public static void curlGlobalInit(int flags) {
        if (INIT) {
            return;
        }
 
        CurlCode code = CurlCode.fromValue(curlGlobalInitNative(flags));
        if (code != CurlCode.CURLE_OK) {
            throw new IllegalStateException("curlGlobalInit fail: " + code);
        }
        INIT = true;
    }
 
    private native static int curlGlobalInitNative(int flags);
 
    private native static void curlGlobalCleanupNative();
 
    public void curlEasyInit() throws CurlException {
        // Log.v(TAG, "curlEastInit");
        handle = curlEasyInitNative();
        if (handle == 0) {
            throw new CurlException("curl init native fail");
        }
    }
 
    private native long curlEasyInitNative();
 
    public void curlEasyCleanup() {
        // Log.v(TAG, "curlEastCleanup: " + handle);
        if (handle != 0) {
            curlEasyCleanupNative(handle);
        }
        handle = 0;
    }
 
    private native void curlEasyCleanupNative(long handle);

然后需要对opt进行封装:
/**
     * 
     * @param opt
     *            {@link OptLong}
     * @param value
     * @return
     */
    public CurlCode curlEasySetopt(OptLong opt, long value) {
        // Log.v(TAG, "curlEastSetopt: " + opt + "=" + value);
        return CurlCode.fromValue(curlEasySetoptLongNative(handle,
                opt.getValue(), value));
    }
 
    private native int curlEasySetoptLongNative(long handle, int opt, long value);
 
    public CurlCode curlEasySetopt(OptFunctionPoint opt, WriteCallback callback) {
        // Log.v(TAG, "curlEastSetopt: " + opt + "=" + callback);
        return CurlCode.fromValue(curlEasySetoptFunctionNative(handle,
                opt.getValue(), callback));
    }
 
    private native int curlEasySetoptFunctionNative(long handle, int opt,
            Callback callback);
 
    public CurlCode curlEasySetopt(OptObjectPoint opt, String value) {
        // Log.v(TAG, "curlEastSetopt: " + opt + "=" + value);
        return CurlCode.fromValue(curlEasySetoptObjectPointNative(handle,
                opt.getValue(), value));
    }
 
    private native int curlEasySetoptObjectPointNative(long handle, int opt,
            String value);
 
    public CurlCode curlEasySetopt(OptObjectPoint opt, byte[] value) {
        // Log.v(TAG, "curlEastSetopt: " + opt + "=" + value);
        return CurlCode.fromValue(curlEasySetoptObjectPointBytesNative(handle,
                opt.getValue(), value));
    }
 
    private native int curlEasySetoptObjectPointBytesNative(long handle,
            int opt, byte[] value);
 
    public CurlCode curlEasySetopt(OptObjectPoint opt, String[] values) {
        // Log.v(TAG, "curlEastSetopt: " + opt + "=" + values);
        return CurlCode.fromValue(curlEasySetoptObjectPointArrayNative(handle,
                opt.getValue(), values));
    }
 
    private native int curlEasySetoptObjectPointArrayNative(long handle,
            int opt, String[] value);

对FormData以及Perform进行封装
/**
     * 
     * @param multiParts
     * @return
     */
    public CurlFormadd setFormdata(List<MultiPart> multiParts) {
        if (multiParts != null && multiParts.size() > 0) {
            return CurlFormadd.fromValue(setFormdataNative(handle,
                    multiParts.toArray(new MultiPart[multiParts.size()])));
        } else {
            return CurlFormadd.CURL_FORMADD_NULL;
        }
    }
 
    private native int setFormdataNative(long handle, MultiPart[] multiArray);
 
    public CurlCode curlEasyPerform() {
        return CurlCode.fromValue(curlEasyPerformNavite(handle));
    }
 
    private native int curlEasyPerformNavite(long handle);

所有的封装全部写到一个类里面,剩下要做的事情,就是通过javah生成头文件了
进入到bin/class目录

使用如下命令生成头文件

javah -o curldroid.h com.netbirdtech.libcurl.Curl

生成头文件之后,需要在使用C++来实现Curl.java中的native方法:

JNIEXPORT jint JNICALL Java_com_netbirdtech_libcurl_Curl_curlGlobalInitNative
  (JNIEnv * env, jclass cls, jint flag) {
    curl_global_init((int) flag);
}
 
JNIEXPORT void JNICALL Java_com_netbirdtech_libcurl_Curl_curlGlobalCleanupNative
  (JNIEnv * env, jclass cls) {
    curl_global_cleanup();
}
 
JNIEXPORT jlong JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasyInitNative
  (JNIEnv * env, jobject obj) {
    CURL* curl = curl_easy_init();
    if (curl != 0) {
        Holder* holder = new Holder(curl);
        return (long) holder;
    }
    return 0;
}
 
JNIEXPORT void JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasyCleanupNative
  (JNIEnv * env, jobject obj, jlong handle) {
    if (handle != 0) {
        Holder* holder = (Holder*) handle;
        curl_easy_cleanup(holder->getCurl());
        delete holder;
        holder = 0;
    }
}
 
JNIEXPORT jint JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasySetoptLongNative
  (JNIEnv *env, jobject obj, jlong handle, jint opt, jlong value) {
    Holder* holder = (Holder*) handle;
    return (int) curl_easy_setopt(holder->getCurl(), (CURLoption) opt, (long) value);
}
JNIEXPORT int JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasySetoptFunctionNative
  (JNIEnv * env, jobject obj, jlong handle, jint opt, jobject cb) {
    Holder* holder = (Holder*) handle;
    CURL * curl = holder->getCurl();
    jobject cb_ref = 0;
    switch (opt) {
    case CURLOPT_HEADERFUNCTION:
        //LOGV("setopt CURLOPT_HEADERFUNCTION");
        curl_easy_setopt(curl, (CURLoption) opt, &write_callback);
        cb_ref = env->NewGlobalRef(cb);
        holder->addGlobalRefs(cb_ref);
        curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *)cb_ref);
        break;
    case CURLOPT_WRITEFUNCTION:
        // see http://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html
        curl_easy_setopt(curl, (CURLoption) opt, &write_callback);
        cb_ref = env->NewGlobalRef(cb);
        holder->addGlobalRefs(cb_ref);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)cb_ref);
        break;
    case CURLOPT_READFUNCTION:
        curl_easy_setopt(curl, (CURLoption) opt, &read_callback);
        cb_ref = env->NewGlobalRef(cb);
        holder->addGlobalRefs(cb_ref);
        curl_easy_setopt(curl, CURLOPT_READDATA, (void *)cb_ref);
        break;
    default:
        // no-op
        ;
    }
    return (int) CURLE_OK;
}
 
JNIEXPORT jint JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasySetoptObjectPointNative
  (JNIEnv * env, jobject obj, jlong handle, jint opt, jstring value) {
    const char *str;
    int result;
    Holder* holder = (Holder*) handle;
    CURL * curl = holder->getCurl();
    jstring value_ref;
    str = env->GetStringUTFChars(value, 0);
    if (str == 0) {
       return 0;
    }
 
    result = (int) curl_easy_setopt(curl, (CURLoption) opt, str);
    switch(opt) {
    case CURLOPT_POSTFIELDS:
        // this field not copy data
        // see http://curl.haxx.se/libcurl/c/CURLOPT_POSTFIELDS.html
        value_ref = (jstring) env->NewGlobalRef(value);
        holder->addStringGlobalRefs(value_ref, str);
        break;
    default:
        // free
        env->ReleaseStringUTFChars(value, str);
    }
 
    return result;
}
 
JNIEXPORT jint JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasySetoptObjectPointBytesNative
  (JNIEnv * env, jobject obj, jlong handle, jint opt, jbyteArray bytes) {
    int result;
    Holder* holder = (Holder*) handle;
    CURL * curl = holder->getCurl();
 
    jbyte* str = env->GetByteArrayElements(bytes, JNI_FALSE);
    int content_length = env->GetArrayLength(bytes);
 
    if (str == NULL) {
       return 0;
    }
 
    result = (int) curl_easy_setopt(curl, (CURLoption) opt, str);
    switch(opt) {
    case CURLOPT_POSTFIELDS:
        // this field not copy data
        // see http://curl.haxx.se/libcurl/c/CURLOPT_POSTFIELDS.html
        // release after perform
        holder->addByteArrayGlobalRefs(env->NewGlobalRef(bytes), (const char*)str);
        break;
    default:
        // free
        env->ReleaseByteArrayElements(bytes, str, 0);
    }
 
    return result;
}
 
JNIEXPORT jint JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasySetoptObjectPointArrayNative
  (JNIEnv *env, jobject obj, jlong handle, jint opt, jobjectArray values) {
    Holder* holder = (Holder*) handle;
    CURL * curl = holder->getCurl();
 
    const char *str;
    struct curl_slist *slist = 0;
    int nargs = env->GetArrayLength(values);
    for (int i = 0; i < nargs; i++) {
        jstring value = (jstring) env->GetObjectArrayElement(values, i);
        str = env->GetStringUTFChars(value, 0);
        if (str == 0) {
            return 0;
        }
        //LOGV("append slist");
        slist = curl_slist_append(slist, str);
        env->ReleaseStringUTFChars(value, str);
    }
    holder->addCurlSlist(slist);
    //LOGD("set slist option=%d, size=%d", opt, nargs);
    return curl_easy_setopt(curl, (CURLoption) opt, slist);
}
 
JNIEXPORT jint JNICALL Java_com_netbirdtech_libcurl_Curl_setFormdataNative
  (JNIEnv* env, jobject obj, jlong handle, jobjectArray multi_array) {
    Holder* holder = (Holder*) handle;
    if (holder == NULL) {
        return 0;
    }
    CURL* curl = holder->getCurl();
 
    struct curl_httppost* post = holder->getPost();;
    struct curl_httppost* last = NULL;
    // clear all
    if (post != NULL) {
        //LOGD("clear previous form.");
        curl_formfree(post);
        post = NULL;
    }
 
    if (multi_array != NULL) {
        CURLFORMcode code;
        int len = env->GetArrayLength(multi_array);
        //LOGD("set name/parts size=%d", len);
        for (int i = 0; i < len; i++) {
            //LOGV(".");
            jobject part = env->GetObjectArrayElement(multi_array, i);
            jstring name = (jstring) env->CallObjectMethod(part, MID_MultiPart_get_name);
            jstring filename = (jstring) env->CallObjectMethod(part, MID_MultiPart_get_filename);
            jstring content_type = (jstring) env->CallObjectMethod(part, MID_MultiPart_get_content_type);
            jbyteArray content = (jbyteArray) env->CallObjectMethod(part, MID_MultiPart_get_content);
            jbyte* bytes = env->GetByteArrayElements(content, 0);
            int content_length = env->GetArrayLength(content);
 
            holder->addByteArrayGlobalRefs(env->NewGlobalRef(content), (const char*)bytes); // release after perform
 
            const char* name_str = env->GetStringUTFChars(name, 0);
 
            // content_type and filename may be null
            if (content_type == NULL && filename == NULL) {
                code = curl_formadd(&post, &last,
                                    CURLFORM_COPYNAME, name_str,
                                    CURLFORM_BUFFER, "file.dat",
                                    CURLFORM_BUFFERPTR, bytes,
                                    CURLFORM_BUFFERLENGTH, content_length,
                                    CURLFORM_END);
            } else if (content_type == NULL) {
                const char* filename_str = env->GetStringUTFChars(filename, 0);
                code = curl_formadd(&post, &last,
                                    CURLFORM_COPYNAME, name_str,
                                    CURLFORM_BUFFER, filename_str,
                                    CURLFORM_BUFFERPTR, bytes,
                                    CURLFORM_BUFFERLENGTH, content_length,
                                    CURLFORM_END);
                env->ReleaseStringUTFChars(filename, filename_str);
            } else if (filename == NULL) {
                const char* content_type_str = env->GetStringUTFChars(content_type, 0);
                code = curl_formadd(&post, &last,
                                    CURLFORM_COPYNAME, name_str,
                                    CURLFORM_BUFFER, "file.dat",
                                    CURLFORM_CONTENTTYPE, content_type_str,
                                    CURLFORM_BUFFERPTR, bytes,
                                    CURLFORM_BUFFERLENGTH, content_length,
                                    CURLFORM_END);
                env->ReleaseStringUTFChars(content_type, content_type_str);
            } else {
                const char* filename_str = env->GetStringUTFChars(filename, 0);
                const char* content_type_str = env->GetStringUTFChars(content_type, 0);
                code = curl_formadd(&post, &last,
                                    CURLFORM_COPYNAME, name_str,
                                    CURLFORM_BUFFER, filename_str,
                                    CURLFORM_CONTENTTYPE, content_type_str,
                                    CURLFORM_BUFFERPTR, bytes,
                                    CURLFORM_BUFFERLENGTH, content_length,
                                    CURLFORM_END);
                env->ReleaseStringUTFChars(filename, filename_str);
                env->ReleaseStringUTFChars(content_type, content_type_str);
            }
 
            env->ReleaseStringUTFChars(name, name_str);
        }
 
        if (code != CURL_FORMADD_OK) {
            LOGW("curl_formadd error %d", code);
            curl_formfree(post);
            // TODO return fromadd error or setopt error?
            return (int) code;
        }
    }
 
    if (post != NULL) {
        //LOGV("set_opt CURLOPT_HTTPPOST");
        holder->setPost(post);
        return curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
    }
    return 0;
}
 
 
JNIEXPORT jint JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasyPerformNavite
  (JNIEnv *env, jobject obj, jlong handle) {
    Holder* holder = (Holder*) handle;
    CURL * curl = holder->getCurl();
    return (int) curl_easy_perform(curl);
}


这个基本上得认真看看libcurl的API了

代码写好之后,就是进行编译了

为了方便,写了一个Makefile文件

jni:
    @echo "编译之前,请务必指定jni.h以及jni_md.h的实际运行目录"
    g++ curldroid.cpp -I /usr/lib/jdk/include -I /usr/lib/jdk/include/linux -lcurl  -fPIC -shared -o libcurl4java.so
install:
    @echo "执行install(安装so文件)操作之前,请务必指定java.library.path目录,通过System.getProperty(\"java.library.path\")可以获取"
    cp -f libcurl4java.so /usr/lib/libcurl4java.so
uninstall:
    @echo "执行uninstall(卸载so文件)操作之前,请务必指定java.library.path目录,通过System.getProperty(\"java.library.path\")可以获取"
    rm -f  /usr/lib/libcurl4java.so
clean:
    @echo "删除所有的链接文件以及所有的目标文件,可能需要root权限"
    rm -f *.o
    rm -f *.so
    rm -f /usr/lib/ibcurldroid.so

在linux系统下面,安装jdk的时候,务必要记下jdk的安装地址,需要指定jni.h的头文件路径

否则会编译失败。

执行make就可以生成so文件

执行make install之前修改install这个target的路径

cp -f libcurl4java.so /usr/lib/libcurl4java.so

如何获取已经说明了。

通过如下代码可以简单的测试功能:

    CurlResult result = CurlHttp.newInstance().addParam("ip", "202.108.67.57")
                .getUrl("http://ip.taobao.com/service/getIpInfo.php").perform();
 
        int status = result.getStatus();
        String statusLine = result.getStatusLine();
        String body = result.getBodyAsString();
        byte[] binaryData = result.getBody();
        String binaryStr = new String(binaryData, "UTF-8");
        // byte[] binaryDecodedDate = result.getDecodedBody(); // if gzipped
        String header = result.getHeader("ContentType"); // ignore header
 
        Map<String, String> headers = result.getHeaders();
        System.out.println("status=" + status);
        System.out.println("statusLine=" + statusLine);
        System.out.println("body=" + body);
        System.out.println("binaryStr=" + binaryStr);
        System.out.println("header=" + header);
        for(int i=0;i<headers.size();i++)
        {
            System.out.println(headers.values());
        }
在android平台下,正确的编译了libcurl,同样能够在android上运行。


代码有空再上传,睡觉去咯


--------------------- 
作者:yanglinjingshu 
来源:CSDN 
原文:https://blog.csdn.net/yanglinjingshu/article/details/45605381 
版权声明:本文为博主原创文章,转载请附上博文链接!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值