Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Работа с cURL на android

Anna | 25.06.2014 | нет комментариев

Мы хотим общение с API сервером написать на C , а дальше применять написанную библиотеку во всех наших приложения под разными платформами. Безусловно мы хотим, Дабы работало под android.

Libcurl — это библиотека интерфейса API для передачи, которую разработчики могут встроить в свои программы; cURL действует как самостоятельная обёртка для библиотеки libcurl. libcurl применяется, Дабы обеспечить вероятность передачи файлов (адресуемых с поддержкой URL) многочисленным приложениям (как открытым, так и торговым). (wikipedia)

Для iOS дозволено скачать готовый пример подключения и применения cURL с сайта разработчика. И с iOS всё легко.

Под android мне на просторах google не удалось обнаружить ни одного исходника, где бы производилось удачное обращение к этой кросс-платформенной библиотеке. (Может я нехорошо искал).

И вообще говоря под android принудить трудиться cURL оказалось немножко труднее чем хотелось бы.

Что нам потребуется:
  • Установленный и настроенный для работы с android Eclipse;
  • ndk и знание работы с ним;
  • Скомпиленная под android библиотека cURL.

Приобретение библиотеки cURL для android

Если пойти на сайт cURL и зайти в загрузки, то там дозволено обнаружить скомпиленный бинарник (Android 7.31.0 binary SSL) тот, что видимо дозволено запускать как консольную утилиту из под девайса. Но он абсолютно непотребен, если мы хотим трудиться с библиотекой из своего приложения.
Отлично погуглив дозволено обнаружить туториал, как собрать надобную для ndk *.a библиотеку, с которой дозволено теснее трудиться из приложения.

Есть про портирование cURL под android и на прогре. В итоге мы получим желаемый *.a файл библиотеки. Сам я его не собирал. Я его Добросовестно скачал.

Дальше

Дальше полученную библиотеку дозволено отважно вставлять план и применяя всю мощь ndk обращаться к ней.

Java часть часть

Сотворим MainActivity с одной кнопкой и полем для ввода адреса сайта, с которого будем получать информацию.

activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
	    <EditText
	       android:id="@ id/server_url"
	       android:text="@string/default_url"
	       android:hint="@string/server_url_hint"
	       android:layout_width="match_parent"
	        android:layout_height="wrap_content"
	       android:singleLine="true"/>      
	   	<Button android:id="@ id/button_curl_call"
	   	    android:layout_below="@ id/server_url"
	       		android:layout_width="wrap_content"
	        	android:layout_height="wrap_content"
	           android:layout_alignParentRight="true"
	           android:text="@string/button_curl"
	           android:layout_gravity="right"
	           />    
	    <TextView
	        android:id="@ id/text"
	        android:layout_below="@ id/button_curl_call"
	        android:layout_weight="1"
	        android:layout_width="fill_parent"
	        android:layout_height="fill_parent"
	    />
</RelativeLayout>

MainActivity.java

package com.ifree.ndkNative;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {
	private static final String INTENT_HTML_DATA = ".html_data";
	public static final int HANDLE_CALLBACK = 0;
	final private Handler handler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case HANDLE_CALLBACK:
                	String html = msg.getData().getString(INTENT_HTML_DATA);
                	SetHtmlText(html);
                    break;
            }
        }
    };    

    private void SetHtmlText(String html){
    	TextView tv = (TextView) findViewById(R.id.text);
    	tv.setText(html);
    }

	/** Called when the activity is first created. */
	    @Override
	    public void onCreate(Bundle savedInstanceState) {
	        super.onCreate(savedInstanceState);
	        setContentView(R.layout.activity_main);

	        final EditText serverUrl = (EditText) findViewById(R.id.server_url);

	        Button btnCurl = (Button) findViewById(R.id.button_curl_call);
	        btnCurl.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					Native curl = new Native();
			        curl.addCurlCallbackListener(new ICurlCallbackListener() {
						@Override
						public void curlCallBack(String callback) {
							//для того, Дабы синхронизировать с потоком gui и отобразить полученный текст в TextView, используем handler
							Bundle bundle = new Bundle();
							bundle.putString(INTENT_HTML_DATA, callback);
							Message message = handler.obtainMessage();
							message.setData(bundle);
							handler.sendMessage(message);
						}
					});
			        String response = curl.get_text_from_cpp(String.valueOf(serverUrl.getText()));//Собственно само обращение к С   части
				}
			});   
	    }
}

Напишем класс Native.java, в котором будет производиться обращение к С коду.

package com.ifree.ndkNative;

import java.util.HashSet;

public class Native {
	private HashSet<ICurlCallbackListener> callBackListeners = new HashSet<ICurlCallbackListener>();

	public void addCurlCallbackListener(ICurlCallbackListener listener){
		callBackListeners.add(listener);
	}

	public void removeCurlCallbackListener(ICurlCallbackListener listener){
		callBackListeners.remove(listener);
	}

	static {
	       System.loadLibrary("ndkNative");
	    } 
	//(ключевое слово native говорит, что реализация будет на C  ):
	public native String get_text_from_cpp(String data);
	private void callback(String data) {		
		for(ICurlCallbackListener listener:callBackListeners){
			listener.curlCallBack(data);
		}
	}
}

Необходимо не позабыть добавить в AndroidManifest разрешение на интернет

<uses-permission android:name="android.permission.INTERNET"/>
С часть

Сделанный при помощи утилиты javah файл com_ifree_ndkNative_Native.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_ifree_ndkNative_Native */

#ifndef _Included_com_ifree_ndkNative_Native
#define _Included_com_ifree_ndkNative_Native
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_ifree_ndkNative_Native
 * Method:    get_text_from_cpp
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_ifree_ndkNative_Native_get_1text_1from_1cpp
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

Определим функцию приобретения данных с сервера (JNICALL Java_com_ifree_ndkNative_Native_get_1text_1from_1cpp) в ndkNative.cpp

#include <string.h>
#include <stdio.h>
#include "stddef.h"
#include <jni.h>
#include "com_ifree_ndkNative_Native.h"
#include "curl/curl.h"
#include "curl/easy.h"

JNIEnv * gEnv;
jobject gObj;

void function_callback(jstring str){
	  jclass cls = gEnv->GetObjectClass(gObj);
	  jmethodID mid = gEnv->GetMethodID(cls, "callback", "(Ljava/lang/String;)V");//вызов способа из java Native.callback(String data)
	  gEnv->CallVoidMethod(gObj, mid, str);
}

size_t function_pt(void *ptr, size_t size, size_t nmemb, void *stream){
	function_callback(gEnv->NewStringUTF((char *) ptr));
	size_t written = fwrite(ptr, size, nmemb, (FILE*)stream);
	  if(written <= 0)
	  return written * size;
}

JNIEXPORT jstring JNICALL Java_com_ifree_ndkNative_Native_get_1text_1from_1cpp
  (JNIEnv * env, jobject obj, jstring str)
{
	gEnv = env;
	gObj = obj;

	CURL *curl;
	CURLcode res;
	curl = curl_easy_init();
	if(curl) {
	    curl_easy_setopt(curl, CURLOPT_URL, env->GetStringUTFChars(str, 0));
	    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, function_pt);
	    res = curl_easy_perform(curl);
	    curl_easy_cleanup(curl);
        /* Check for errors */
		if(res != CURLE_OK)
			function_callback(gEnv->NewStringUTF(curl_easy_strerror(res)));
	  }else{
		  function_callback(gEnv->NewStringUTF("error"));
	  }
	  return env->NewStringUTF( "ok" );
}

Android.mf

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

include $(CLEAR_VARS)
LOCAL_MODULE:= libcurl
LOCAL_SRC_FILES := libcurl.a
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE    := ndkNative
LOCAL_SRC_FILES := ndkNative.cpp
LOCAL_STATIC_LIBRARIES := libcurl
include $(BUILD_SHARED_LIBRARY)

Исходник

P.s.: Нужно крепко видоизменить план для применения его в реальных приложения, в частности всю работу сcURL необходимо перенести в обособленный С класс-обвертку.

P.s.s.: code convention в плане немножко хромает.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB