说明:
android的NDK本来就提供了zlib库,但是由于zlib相对简单,所以我第一次编译的就是zlib,只是为了了解一下大概如何编译的思路。
这里使用的zlib的版本是zlib-1.2.3。
(1)使用ndk-build的方式
解压zlib包后,将其放入JNI文件夹下,目录树结构如下:
NDK#tree -L 3
.
├── prj_zlib
│ └── jni
│ └── zlib-1.2.3
└── zlib-1.2.3.tar
在jni目录下,新建Android.mk(注意大写)文件,其内容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := mytest.c
LOCAL_C_INCLUDES := \
$(LOCAL_PATH) \
$(LOCAL_PATH)/..
LOCAL_STATIC_LIBRARIES := libzlib
LOCAL_MODULE := libmyzlibtest
include $(BUILD_SHARED_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))
其中,mytest.c为使用JNI封装zlib函数的测试例子,内容如下(根据需要去调用):
#include <jni.h>
#include "zlib.h"
#include <string.h>
jstring chartojstring( JNIEnv* env, const char* pat)
{
/*jclass strClass = (*env)->FindClass(env,"java/lang/String;");
jmethodID ctorID = (*env)->GetMethodID(env,strClass, "<init>", "([BLjava/lang/String;)V");
jbyteArray bytes = (*env)->NewByteArray(env, strlen(pat));
(*env)->SetByteArrayRegion(env,bytes, 0, strlen(pat), (jbyte*)pat);
jstring encoding = (*env)->NewStringUTF(env,"utf-8");
return (jstring)(*env)->NewObject(env,strClass, ctorID, bytes, encoding);
*/
/*
jstring stoJstring(JNIEnv* env, const char* pat)
{
jclass strClass = env->FindClass("Ljava/lang/String;");
jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
jbyteArray bytes = env->NewByteArray(strlen(pat));
env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
jstring encoding = env->NewStringUTF("utf-8");
return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
}
*/
return (*env) -> NewStringUTF(env, pat);
}
char* jstringTostring(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = (*env)->FindClass(env, "java/lang/String");
jstring strencode = (*env)->NewStringUTF(env, "utf-8");
jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode);
jsize alen = (*env)->GetArrayLength(env, barr);
jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
(*env)->ReleaseByteArrayElements(env, barr, ba, 0);
return rtn;
}
jbyteArray Java_com_hello_zlib_ZlibActivity_compressStr(JNIEnv* env, jobject thiz, jstring str)
{
char* strSrc = jstringTostring(env, str);
Byte buff[1024]={0};
unsigned long bufLen = sizeof(buff)/sizeof(buff[0]);
int ret = compress(buff, &bufLen, strSrc, strlen(strSrc) + 1);
if (Z_OK != ret)
{
memcpy(buff, "error", strlen("error")+1 );
}
jbyteArray retArray = (*env)->NewByteArray(env, bufLen);
(*env)->SetByteArrayRegion(env, retArray, 0, bufLen, buff);
return retArray;
}
jstring Java_com_hello_zlib_ZlibActivity_uncompressStr(JNIEnv* env, jobject thiz, jbyteArray bArray)
{
jsize length = (*env)->GetArrayLength(env, bArray);
jbyte* pArrayByte = (*env)->GetByteArrayElements(env, bArray, 0);
unsigned char buff[1024]={0};
unsigned long bufLen = sizeof(buff)/sizeof(buff[0]);
int ret = uncompress(buff, &bufLen, pArrayByte, length);
/* if (Z_OK != ret)
{
memcpy(buff, "error", strlen("error")+1);
}
*/
if (Z_DATA_ERROR == ret)
{
memcpy(buff, "data_error", strlen("data_error")+1);
}
if (Z_BUF_ERROR == ret)
{
memcpy(buff, "buf_error", strlen("buf_error")+1);
}
if (Z_MEM_ERROR == ret)
{
memcpy(buff, "mem_error", strlen("mem_error")+1);
}
return chartojstring(env, buff);
}
jstring Java_com_hello_zlib_ZlibActivity_getVersion(JNIEnv* env, jobject thiz)
{
const char* version= zlibVersion();
return chartojstring(env, version);
}
在jni下的zlib-1.2.3文件夹下新建Android.mk,内容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := adler32.c compress.c crc32.c deflate.c gzio.c infback.c inffast.c inflate.c inftrees.c minigzip.c trees.c uncompr.c zutil.c
LOCAL_MODULE:= libzlib
include $(BUILD_STATIC_LIBRARY)
最后,整个”工程“目录树如下(说明,只有在上面的Android.mk中列举的相关的c文件和对应的h文件对编译有用,所以下面显示的目录树将原本zlib源码中的其它无关文件和文件夹删除了):
$tree
.
├── prj_zlib
│ └── jni
│ ├── Android.mk
│ ├── mytest.c
│ └── zlib-1.2.3
│ ├── adler32.c
│ ├── Android.mk
│ ├── compress.c
│ ├── crc32.c
│ ├── crc32.h
│ ├── deflate.c
│ ├── deflate.h
│ ├── example.c
│ ├── gzio.c
│ ├── infback.c
│ ├── inffast.c
│ ├── inffast.h
│ ├── inffixed.h
│ ├── inflate.c
│ ├── inflate.h
│ ├── inftrees.c
│ ├── inftrees.h
│ ├── minigzip.c
│ ├── trees.c
│ ├── trees.h
│ ├── uncompr.c
│ ├── zconf.h
│ ├── zconf.in.h
│ ├── zlib.3
│ ├── zlib.h
│ ├── zutil.c
│ └── zutil.h
└── zlib-1.2.3.tar
3 directories, 30 files
然后,就可以进行编译了,如下:
$ls
prj_zlib zlib-1.2.3.tar
$cd prj_zlib/
$ls
jni
$NDK/ndk-build
Compile thumb : myzlibtest <= mytest.c
Compile thumb : zlib <= adler32.c
Compile thumb : zlib <= compress.c
Compile thumb : zlib <= crc32.c
Compile thumb : zlib <= deflate.c
Compile thumb : zlib <= gzio.c
Compile thumb : zlib <= infback.c
Compile thumb : zlib <= inffast.c
Compile thumb : zlib <= inflate.c
Compile thumb : zlib <= inftrees.c
Compile thumb : zlib <= minigzip.c
Compile thumb : zlib <= trees.c
Compile thumb : zlib <= uncompr.c
Compile thumb : zlib <= zutil.c
StaticLibrary : libzlib.a
SharedLibrary : libmyzlibtest.so
Install : libmyzlibtest.so => libs/armeabi/libmyzlibtest.so
$
下面是在android中调用上面的.so中函数的代码:
package com.hello.zlib;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class ZlibActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String version = getVersion();
String comSrc = "中文测试 EnglishTesting 1234567890\n" +
"中文测试 EnglishTesting 1234567890\n" +
"中文测试 EnglishTesting 1234567890\n" +
"中文测试 EnglishTesting 1234567890\n" +
"中文测试 EnglishTesting 1234567890";
byte[] comByte = compressStr(comSrc);
String uncomStr = uncompressStr(comByte);
String str = "Ther version of zlib is: " + version + "\n\n";
str = str + "SrcStr: \n" + comSrc + "\nLen: " + comSrc.length() + "\n\n";
str = str + "Com byte: \n" + comByte + "\nLen: " + comByte.length + "\n\n";
str = str + "Un-com Str: \n" + uncomStr + "\nLen: " + uncomStr.length() + "\n\n";
TextView tx = (TextView) findViewById(R.id.txt);
tx.setText(str);
}
public native String getVersion();
public native byte[] compressStr(String str);
public native String uncompressStr(byte b[]);
static {
System.loadLibrary("myzlibtest");
}
}
这样,就在jni下的libs中生成了libmyzlibtest.so了,编译完成。
(2)使用GCC
略。