cURL / Mailing Lists / curl-library / Single Mail

curl-library

Porting curl to Android - A success story with NDK 1.6

From: Mark Scheel <tantdyalf_at_gmail.com>
Date: Tue, 8 Dec 2009 14:08:14 -0700

This is how I got curl to work in an Android application.

Using Android Platform 1.5 and NDK 1.6 on Ubuntu 9.10, assuming NDKROOT is
where you installed the NDK, and naming my app curljni ...

Create NDKROOT/apps/curljni/project/jni folder structure.

Create Application.mk in NDKROOT/apps/curljni:

#Application.mk
APP_PROJECT_PATH := $(call my-dir)/project
APP_MODULES := curljni libcurl

Create two files in NDKROOT/apps/curljni/project/jni

(1) Android.mk

##########################

LOCAL_PATH:= $(call my-dir)

common_CFLAGS := -Wpointer-arith -Wwrite-strings -Wunused -Winline
-Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long
-Wfloat-equal -Wno-multichar -Wsign-compare -Wno-format-nonliteral
-Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement
-Wno-system-headers -DHAVE_CONFIG_H

include $(CLEAR_VARS)

#include $(LOCAL_PATH)/src/Makefile.inc

MY_SRCS := file.c timeval.c base64.c hostip.c progress.c formdata.c \
  cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \
  ldap.c ssluse.c version.c getenv.c escape.c mprintf.c telnet.c \
  netrc.c getinfo.c transfer.c strequal.c easy.c security.c krb4.c \
  krb5.c memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c \
  multi.c content_encoding.c share.c http_digest.c md5.c curl_rand.c \
  http_negotiate.c http_ntlm.c inet_pton.c strtoofft.c strerror.c \
  hostares.c hostasyn.c hostip4.c hostip6.c hostsyn.c hostthre.c \
  inet_ntop.c parsedate.c select.c gtls.c sslgen.c tftp.c splay.c \
  strdup.c socks.c ssh.c nss.c qssl.c rawstr.c curl_addrinfo.c \
  socks_gssapi.c socks_sspi.c curl_sspi.c slist.c nonblock.c \
  curl_memrchr.c
MY_CURL_HEADERS := \
    curlbuild.h \
    curl.h \
    curlrules.h \
    curlver.h \
    easy.h \
    mprintf.h \
    multi.h \
    stdcheaders.h \
    typecheck-gcc.h \
    types.h

LOCAL_SRC_FILES := $(addprefix curl/lib/,$(MY_SRCS))
LOCAL_CFLAGS += $(common_CFLAGS)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/curl/include/

LOCAL_COPY_HEADERS_TO := libcurl
LOCAL_COPY_HEADERS := $(addprefix curl/include/curl/,$(MY_CURL_HEADERS))

LOCAL_MODULE:= libcurl

include $(BUILD_STATIC_LIBRARY)

#curljni
########

include $(CLEAR_VARS)

LOCAL_MODULE := curljni
LOCAL_SRC_FILES := curljni.c
LOCAL_STATIC_LIBRARIES := libcurl
LOCAL_C_INCLUDES += $(LOCAL_PATH)/curl/include
include $(BUILD_SHARED_LIBRARY)

##########################

(2) curljni.c#include <string.h>

##########################

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include "curl/curl.h"

jstring
Java_com_banandroid_curljni_curljni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{

  CURL *curl;
  CURLcode res;
        char buffer[10];

  curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "yahoo.com");
    res = curl_easy_perform(curl);
        /* always cleanup */
    curl_easy_cleanup(curl);
   if(res == 0)
                return (*env)->NewStringUTF(env, "0 response");
   else
        sprintf(buffer,"code: %i",res);
                return (*env)->NewStringUTF(env, buffer);

  } else {

return (*env)->NewStringUTF(env, "no curl");

  }
}

##########################

Next create a Android project in Eclipse. Specify the location of the
project by unchecking "Use default location" - it should be:
NDKROOT/apps/curljni/project

The application name - curljni
The package name - curljni
The activity - curljni
I set min sdk to 3

Click finish

This will create a file src/curljni.java, edit it so that it is:

package com.banandroid.curljni;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class curljni extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView tv = new TextView(this);
        tv.setText( stringFromJNI() );
        setContentView(tv);
    }
    public native String stringFromJNI();
    static {
        System.loadLibrary("curljni");
    }
}

Next move curl source into the right spot. You should have these
directories:

NDKROOT/apps/curljni/project/jni/curl/include
NDKROOT/apps/curljni/project/jni/curl/lib
NDKROOT/apps/curljni/project/jni/curl/src

Now you have to invoke the NDK build system from NDKROOT:

$ make APP=curljni

You may see warnings, but eventually you will see:

StaticLibrary : libcurl.a
SharedLibrary : libcurljni.so
Install : libcurljni.so => apps/curljni/project/libs/armeabi

Almost done!

Last step is to ask Eclipse to install everything onto your emulator. Do
this with the Run menu / Run command.

It should run and show a curl response code of 6, which indicates a
connection problem. This is because Android is preventing the application
from using the internet. To fix this you can give your application
permission to use the internet.

Using Eclipse modify AndroidManifest.xml, the last three lines should be:

    <uses-sdk android:minSdkVersion="3" />
    <uses-permission android:name="android.permission.INTERNET"/>
</manifest>

Where the second line is the one you add.

A response code of 0 indicates success. You can use a sniffer to see that
the web page is pulled, or modify the c code to pass back some of the
retrieved HTML and display it.

Thank you to Daniel and others who provided breadcrumbs towards this
solution, and thanks to the NDK team, they work extremely hard and I am
deeply thankful.

I hope this helps someone else.

Before going to all this trouble be sure you need curl on Android, I needed
it as a dependency for a large body of legacy c and c++ code.

Happy porting!

-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
Received on 2009-12-08