Android NDK用にzlibをビルドして利用する

test106_01.png
今回はデータ圧縮/解凍用のzlibをAndroidのネイティブ環境から利用してみる。基本的な流れは前回のSQLiteを利用したときと同じだ。

http://www.zlib.net/からzlibのソースコードをダウンロードする。今回はzlib 1.2.5を利用した。

test106_02.png
次にEasyProjectGenerator for Android Ver 1.00を利用してAndroid NDKプロジェクトを生成して、jniフォルダ直下に「zlb」というフォルダを作る。そして、そこへダウンロードしたzlibのソースファイルのうち、上位のフォルダに入っている*.cと*.hファイルをすべて解凍する。

test106_03.png
さらにjniフォルダ直下のソースファイルとmakefileも新しく「Test106」というフォルダを作り、そこへ移動しておく。

test106_04.png
ここまでの操作でできたプロジェクトフォルダをEclipseにAndroidプロジェクトとして取り込んだ。

test106_05.png
次にビルド用のAndroid.mkファイルを順次作成する。まずはjniフォルダの直下に作る。

test106_06.png jniフォルダの直下のAndroid.mkファイルはその下のサブフォルダをビルド対象にさせる。
include $(call all-subdir-makefiles)

test106_07.png 次にzlibのビルド用Android.mkをzlibフォルダ内に作成する。 解凍したソースファイルのうち、minigzip.cとexample.cはmain関数を含んだテスト用なのでビルド対象からは除外する。
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := libzip
LOCAL_LDLIBS := -lz
LOCAL_SRC_FILES := adler32.c compress.c crc32.c deflate.c  gzclose.c gzlib.c gzread.c gzwrite.c infback.c inffast.c inflate.c inftrees.c trees.c uncompr.c zutil.c

include $(BUILD_STATIC_LIBRARY)

test106_08.png 次にJNI用のメインとなるソースファイルを編集する。
#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <zlib.h>



int CompressTest(int bCompress,const char* pszDstFile,const char* pszSrcFile)
{
	int		ret;
	int		nFd;
	char*	pszMapped;
	long	nFileSize;

	//処理対象ファイルを開く
	nFd = open(pszSrcFile,O_RDONLY);
	if(nFd < 0)
		return	0;

	//処理対象ファイルのサイズ取得
	{
		struct stat	sFileStat;

		ret = fstat(nFd,&sFileStat);
		if(ret < 0)
		{
			close(nFd);
			return	0;
		}
		nFileSize = sFileStat.st_size;
	}

	//処理対象ファイルをメモリマップドファイルにする
	pszMapped = (char*)mmap(NULL,nFileSize,PROT_READ,MAP_SHARED,nFd,0);
	if(pszMapped == MAP_FAILED)
	{
		close(nFd);
		return	0;
	}

	//メイン処理
	{
		Bytef*	pcbCompData;
		long	nCompLen;

		if(bCompress)
		{
			//圧縮処理

			nCompLen = nFileSize * 1.1 + 13;
			pcbCompData = (Bytef*)malloc(nCompLen);

			compress(pcbCompData,&nCompLen,pszMapped,nFileSize);
		}
		else
		{
			//解凍処理

			//元サイズ取得&バッファ確保
			nCompLen = *(long*)pszMapped;
			pcbCompData = (Bytef*)malloc(nCompLen);

			char*	pTmp;

			//サイズが保存されていた分だけポインタを進めて解凍処理
			pTmp = pszMapped;
			pTmp += sizeof(nFileSize);

			uncompress(pcbCompData,&nCompLen,pTmp,nFileSize - sizeof(nFileSize));
		}

		{
			FILE	*fp;
			fp = fopen(pszDstFile,"w");
			if(fp)
			{
				if(bCompress)
				{
					//圧縮時は圧縮前のサイズを保存
					fwrite(&nFileSize,sizeof(nFileSize),1,fp);
				}

				fwrite(pcbCompData,1,nCompLen,fp);
				fclose(fp);
			}
		}

		free(pcbCompData);
	}

	//メモリマップドファイル開放
	munmap(pszMapped,nFileSize);

	close(nFd);

	return	1;
}

jstring
Java_com_Test106_Test106Act_stringFromJNI(JNIEnv* env,jobject thiz)
{
	//テスト用ファイル作成
	FILE	*fp;
	fp = fopen("/sdcard/test.txt","w");
	if(fp)
	{
		fputs("--------------------------------------------------",fp);
		fputs("----------this is compress data-------------------",fp);
		fputs("--------------------------------------------------",fp);
		fputs("Test line.Test line.Test line.Test line.Test line.",fp);
		fputs("Test line.Test line.Test line.Test line.Test line.",fp);
		fputs("Test line.Test line.Test line.Test line.Test line.",fp);
		fputs("--------------------------------------------------",fp);
		fclose(fp);
	}

	//圧縮
	CompressTest(1,"/sdcard/test.cmp","/sdcard/test.txt");

	//解凍
	CompressTest(0,"/sdcard/decomp.txt","/sdcard/test.cmp");

	return (*env)->NewStringUTF(env, "Test106text");
}

test106_09.png さらにAndroid.mk内でzlibが利用されるようにする。
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := Test106jni
LOCAL_SRC_FILES := Test106jni.c

LOCAL_STATIC_LIBRARIES := libzip

LOCAL_C_INCLUDES += $(call my-dir)/../zlib

include $(BUILD_SHARED_LIBRARY)


test106_10.png
以上の操作でプロジェクトの設定が終わった。ndk-buildによりネイティブコードをビルドする。

test106_11.png
そしてAndroidプロジェクトを実行する。

test106_12.png
これでAndroidエミュレーター内で実行された。

test106_13.png
EclipseのDDMSから仮想SDカード内を見ると、圧縮前のtest.txt、圧縮したtest.cmp、解凍したdecomp.txtの3ファイルを確認できた。



プロジェクトファイルをダウンロード


カテゴリー「android」 のエントリー