4.5 Android上使用libcurl
下载和编译
libcurl想要在Android上开发,显然不能只能用C++的so文件。
所以我们需要将curl的源代码通过Android.mk重新编译一次,但是显然很是麻烦。
这里我用就用别人写好的东西。
https://github.com/gcesarmza/curl-android-ios
这个是一个已经写好的移动端使用libcurl的源代码。
下载curl_android_ios
git clone https://github.com/gcesarmza/curl-android-ios.git
由于这个库依赖于 curl库和 openssl,所以需要再次关联下载
git submodule init && git submodule update
编译android版本
/curl-android-ios-master/curl-compile-scripts/
./bulid_android.sh
(1) 问题1
如果提示需要NDK_ROOT
环境变量,需要在~/.bashrc加入NDK安装的路径.
vim ~/.bashrc
export NDK_ROOT=/home/itcast/BC-Project/Android-SDK/ndk-bundle
source ~/.bashrc
(2) 问题2
./build_Android.sh: 行 34: ./Configure: 没有那个文件或目录
Error running the ssl configure program
可能是没有下载依赖库openssl 和curl导致。
这个编译可能会话费很长时间,因为他要编译很多种平台的Android。如x86,mips,arm等等。
最后,我们会得到以下静态库文件。
[arm64-v8a] StaticLibrary : libcurl.a
[x86_64] StaticLibrary : libcurl.a
[mips64] StaticLibrary : libcurl.a
[armeabi] StaticLibrary : libcurl.a
[armeabi-v7a] StaticLibrary : libcurl.a
[x86] StaticLibrary : libcurl.a
[mips] StaticLibrary : libcurl.a
对应我们Android的设备的平台型号,选择一款就好了,一般我们都是用的[armeabi]
配置和部署
将生成的libcurl.a 和所对应的头文件拷贝到Android项目中的jni/路径下。
cd ./curl-android-ios-master/prebuilt-with-ssl/android/
cp armeabi/libcurl.a ~/AndroidStudioProjects/testApp/jni/
cp include/curl/ ~/AndroidStudioProjects/testApp/jni/ -R
以上如果您使用的开发环境是Linux。
如果是Windows,需要将armeabi下的libcurl.a通过远程传输,拷贝到当前windows项目中的jni路径下.
测试libcurl
目前我们jni/路径下已经有 libcurl.a 和curl/头文件了。
现在我们可以实现一个login的jni接口,让java调用,来完成客户端和服务端的网络通信。
(1)首先在java类中,定义一个native接口。
//登陆服务器login接口
public native void testLibcurl();
(2) 给该native通过javah生成头文件.
cd testApp/app/src/main/java/
javah -jni com.cpp.itcast.testapp.HelloJni
(3)测试libcurl代码
在jni.cpp中 实现jni接口。 就是访问一个网页,然后将网页的信息打印到debug上。
size_t print_html( void *ptr, size_t size, size_t nmemb, void *stream)
{
int len = size*nmemb;
char *buf = new char[len+1];
memcpy(buf, ptr, len);
buf[len] = '\0';
__android_log_print(ANDROID_LOG_ERROR, "jnitag", "%s\n", buf);
delete [] buf;
return len;
}
JNIEXPORT void JNICALL Java_com_cpp_itcast_testapp_HelloJni_testLibcurl
(JNIEnv *, jobject)
{
CURL *curl = NULL;
CURLcode ret;
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "www.baidu.com");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, print_html);
ret = curl_easy_perform(curl);
if (ret != CURLE_OK) {
__android_log_print(ANDROID_LOG_ERROR, "jnitag", "curl_easy_perform error");
return ;
}
curl_easy_cleanup(curl);
return ;
}
(4)修改Android.mk文件
LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
# libcurl.a
LOCAL_MODULE := libcurl
LOCAL_SRC_FILES := libcurl.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
#libmyJni.so
LOCAL_MODULE := myJni
LOCAL_SRC_FILES := test.cpp jni.cpp
LOCAL_LDLIBS := -llog -lz
LOCAL_STATIC_LIBRARIES := libcurl
include $(BUILD_SHARED_LIBRARY)
(5) 编译生成libmyJni.so
进入到jni/路径 执行。
ndk-build APP_ABI="armeabi"
(6)测试 该Jni接口
此过程需要两个必要条件:
1.Android移动设备必须可以上网。
2.给该APP应用开辟上网权限
开辟上网权限如下:
打开testApp/app/src/main/AndroidManifest.xml:
在
<uses-permission android:name="android.permission.INTERNET"/>
3.在app源根文件夹下build.gradle文件的配置
这里面加注释的是额外需要关注的地方。
compileSdkVersion 24
buildToolsVersion "24.0.3"
defaultConfig {
applicationId "com.example.ace.obo"
minSdkVersion 10
targetSdkVersion 24
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
// 不声明ndk标签,项目默认会创建一个libapp.so的文件
ndk {
// 声明创建so库的文件名,会自动添加lib前缀, 添加了前缀,不会自动添加
moduleName "OBOjni"
//声明启用Android日志, 在c/c++的源文件中使用的#include <android/log.h> 日志将得到输出
//这里我们关联了两个库 一个是liblog 和 libz
ldLibs "log","z"
// 声明创建指定cpu架构的so库, 不声明的话, 默认(gradle 1.5.0)会生成7中架构,如果你的libcurl没有提供别的平台,那么就会链接失败,
//所以此条配置很重要,这里我们只生成一个平台
abiFilters "armeabi"
}
}
4.另外最好加上如下配置
项目根文件夹下的gradle.properties文件中添加如下配置(解决AS中NDK插件过时不能编译的问题)
android.useDeprecatedNdk=true
5.最后执行测试代码,在真机上运行,观察结果.
HelloJni.getInstance().testLibcurl();
注意事项:
如果在生成连接到时候 出现
error: linker command failed with exit code 1 (use -v to see invocation)
错误
需要过滤生成的ABI平台