前の10件 6  7  8  9  10  11  12  13  14  15  16

記事一覧

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

test108_01.png
今回はlibpngを利用してAndroidネイティブ環境からPNG画像の表示を行う。
まずhttps://www.libpng.org /pub/png /libpng.htmlからlibpngのソースコードをダウンロードする。今回利用したのはlibpng 1.4.5だ。

test108_02.png
次にEasyProjectGenerator for AndroidでNativeViewプロジェクトを作成する。

test108_03.png
そして自動生成されたプロジェクトにあるjniフォルダ内に「libpng」フォルダを作成。先ほどダウンロードしたlibpngのソースコードのうち、ルートにある*.cと*.hファイルを作成したlibpngフォルダ内へ解凍する。

test108_04.png
libpng 1.4.5はその処理にzlibを利用している。そのためさらにzlibをプロジェクトに加える。
ゼロからzlibを用意するのは面倒だ。そのため前に作成した「Android NDK用にzlibをビルドして利用する」エントリーでのプロジェクトファイルを流用する。「Test106.zip」をダウンロードする。

test108_05.png
そしてダウンロードしたプロジェクトのjniフォルダにあるzlibフォルダとAndroid.mkを今回のプロジェクトに取り込む。その前にjniフォルダ直下にあったTest108jni.cとAndroid.mkをtest108というフォルダを作成、その中へ移動しておいた。

test108_06.png
これまでの作業で作れたプロジェクトをEclipseにAndroidプロジェクトとして取り込む。これで図のようなフォルダ構造になった。

test108_07.png さらに必要なファイルを順次作成する。まずはlibpngフォルダ内にAndroid.mkを作る。 libpngのソースコードのうちexample.cとpngtest.cはmain()を含んだテスト用なのでビルドの必要はない。
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := libpng
LOCAL_LDLIBS := -lz
LOCAL_SRC_FILES := png.c pngerror.c pngget.c pngmem.c pngpread.c pngread.c pngrio.c pngrtran.c pngrutil.c pngset.c pngtrans.c pngwio.c pngwrite.c pngwtran.c pngwutil.c

include $(BUILD_STATIC_LIBRARY)

test108_08.png 次にtest108フォルダ内のAndroid.mkを修正する。
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := Test108jni
LOCAL_SRC_FILES := Test108jni.c
LOCAL_LDLIBS    := -lz -llog -ljnigraphics

LOCAL_C_INCLUDES += $(LOCAL_PATH)/../zlib
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libpng
LOCAL_STATIC_LIBRARIES := libzip libpng

include $(BUILD_SHARED_LIBRARY)

test108_09.png そして最後に実際の描画処理を実装する。今回は画像ファイル「/sdcard/test.png」を読み込んで表示する。
#include <jni.h>
#include <android/bitmap.h>
#include <stdlib.h>
#include <png.h>


/* this function is from Android NDK bitmap-plasma */
static uint16_t  make565(int red, int green, int blue)
{
	return (uint16_t)( ((red   << 8) & 0xf800) |
					   ((green << 2) & 0x03e0) |
					   ((blue  >> 3) & 0x001f) );
}



static int DrawBitmap(AndroidBitmapInfo* pBitmapInfo, void* pPixels, const char* pszImageFile)
{
	FILE	*fp;

	//画像ファイルの読み込み
	fp = fopen(pszImageFile,"r");
	if(fp == NULL)
		return	0;

	int		bSucceeded = 0;

	png_bytepp	ppRowImage = NULL;
	png_structp	pPng = NULL;
	png_infop	pInfo = NULL;

	while(1)
	{
		pPng = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
		if(pPng == NULL)
			break;

		pInfo = png_create_info_struct(pPng);
		if(pInfo == NULL)
			break;

		//ファイルポインタの設定
		png_init_io(pPng,fp);

		png_uint_32	nWidth;
		png_uint_32	nHeight;
		int		nBitDepth;
		int		nColorType;
		int		nIntMethod;
		int		nCompMethod;
		int		nFilterMethod;
		png_uint_32	nImageBytes;
		png_uint_32	nRowBytes;

		//画像情報取得
		png_read_info(pPng,pInfo);
		png_get_IHDR(pPng,pInfo,&nWidth,&nHeight,&nBitDepth,&nColorType,&nIntMethod,&nCompMethod,&nFilterMethod);
		nRowBytes	= png_get_rowbytes(pPng,pInfo);
		nImageBytes	= nHeight * nRowBytes;

		//画像データ用バッファーの確保
		ppRowImage = (png_bytepp)malloc(sizeof(png_bytep) * nHeight + nImageBytes);
		if(ppRowImage == NULL)
			break;

		int		yy;

		//画像データ用バッファーの初期化
		{
			png_bytep	pRowImage;

			pRowImage = (png_bytep)&(ppRowImage[nHeight]);
			for(yy = 0; yy < nHeight; yy++)
			{
				ppRowImage[yy] = pRowImage;
				pRowImage += nRowBytes;
			}
		}


		//画像ファイル読み込み
		png_read_image(pPng,ppRowImage);


		//描画
		for(yy = 0; yy < pBitmapInfo->height && yy < nHeight; yy++)
		{
			int		xx;
			uint16_t*	pLine;
			char*		pImagePixel;

			pLine = (uint16_t*)pPixels;					//ビットマップの行データ
			pImagePixel = (char*)(ppRowImage[yy]);		//画像ファイルの行データ

			for(xx = 0; xx < pBitmapInfo->width && xx < nWidth; xx++)
			{
				//■■注意■■1ピクセル3バイト前提で処理している。しかも画像ファイルが1ピクセル3バイトかどうかはチェックしていない!
				pLine[xx] = make565(pImagePixel[0],pImagePixel[1],pImagePixel[2]);
				pImagePixel += 3;
			}

			pPixels = (char*)pPixels + pBitmapInfo->stride;
		}

		bSucceeded = 1;
		break;				//必須忘れないこと!
	}


	if(ppRowImage)
	{
		free(ppRowImage);
		ppRowImage = NULL;
	}

	if(pPng)
	{
		if(pInfo)
			png_destroy_read_struct(&pPng,&pInfo,NULL);
		else
			png_destroy_read_struct(&pPng,NULL,NULL);

		pPng = NULL;
		pInfo = NULL;
	}

	fclose(fp);

	return	bSucceeded;
}



JNIEXPORT void JNICALL Java_com_Test108_NativeView_RenderBitmap(JNIEnv * env, jobject  obj, jobject bitmap)
{
	AndroidBitmapInfo  info;
	void*			  pixels;
	int				ret;

	if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0)
		return;

	if (info.format != ANDROID_BITMAP_FORMAT_RGB_565)
		return;

	if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0)
		return;

	DrawBitmap(&info,pixels,"/sdcard/test.png");

	AndroidBitmap_unlockPixels(env, bitmap);
}


test108_10.png
ソースコードの準備ができたので、ndk-buildによりビルドする。

test108_11.png
そして実行。まだ画像ファイルを用意していいないので何も表示されない。

test108_12.png
表示用のpng画像ファイルを用意する。

test108_13.png
Eclipseの「DDMS」画面で、「/mnt/sdcard/」を選択、「push a file on to device」ボタンからpngファイルを仮想SDカードへ転送する。もしもこの画面での転送に失敗する場合はadb pushコマンドによりコマンドラインから転送する。

test108_14.png
これで表示用のpng画像を用意できた。

test108_15.png
実行すると画像が表示された。。。が、表示色がだいぶ変わっている。

test108_16.png
原因を調べたところ、Android NDKのサンプルプロジェクト「bitmap-plasma」からコピペしていたmake565()関数内のバグでした。ここを修正する。

※EasyProjectGenerator for Android Ver1.02で修正します。
/* this function is from Android NDK bitmap-plasma , and modify for green color bug */
static uint16_t  make565(int red, int green, int blue)
{
	return (uint16_t)( ((red   << 8) & 0xf800) |
					   ((green << 3) & 0x07e0) |
					   ((blue  >> 3) & 0x001f) );
}

test108_17.png
これで減色による色変化が若干あるものの、PNG画像を表示できた。



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

EasyProjectGenerator for Android

「EasyProjectGenerator for Android」はAndroid用のプロジェクトを自動生成するフリーウエアです。

プロジェクト種類とプロジェクト名を指定するだけで簡単にAndroidアプリ(含ネイティブアプリ)用のプロジェクトを自動生成できます。

具体的な利用方法はこちらのエントリーを参照してください。


EasyProjectGenerator for Android Ver 1.04
EasyProjectGenerator for Android Ver 1.03
EasyProjectGenerator for Android Ver 1.02
EasyProjectGenerator for Android Ver 1.01
EasyProjectGenerator for Android Ver 1.00


epg11.png
「HelloJNI」タイプの自動生成されたプロジェクト実行画面。

EasyProjectGenerator for Android Ver 1.00から対応。

test107_06.png
「NativeView」タイプの自動生成されたプロジェクト実行画面。

EasyProjectGenerator for Android Ver 1.01から対応。

simplewidget.png
「SimpleWidget」タイプの自動生成されたプロジェクトをウィジットとして配置した画面。
アイコンとテキストがウィジットとして表示される。

EasyProjectGenerator for Android Ver 1.04から対応。

Androidネイティブによる描画処理をする

test107_01.png
前回はAndroid NDKに含まれるネイティブ描画のサンプルプロジェクト「bitmap-plasma」を見た。今回はそのプロジェクトを参考にネイティブ描画処理部分のみを抜き出した雛形プロジェクトを作る。

EasyProjectGenerator for Android Ver 1.00を利用してAndroid NDKプロジェクトを生成してEclipseに取り込む。

test107_02.png まずはjavaのソースコードを編集する。新たにNativeViewというビュークラスを作り、そこでネイティブ描画処理が呼ばれるようにした。
package com.Test107;

import android.app.Activity;
import android.os.Bundle;
import android.content.Context;
import android.view.View;
import android.graphics.Bitmap;
import android.graphics.Canvas;

public class Test107Act extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(new NativeView(this));
    }

    static {
        System.loadLibrary("Test107jni");
    }
}

class NativeView extends View
{
    private Bitmap mBitmap;

    private static native void RenderBitmap(Bitmap bitmap);

    public NativeView(Context context)
    {
        super(context);

        final int W = 200;
        final int H = 200;

        mBitmap = Bitmap.createBitmap(W, H, Bitmap.Config.RGB_565);
    }

    @Override protected void onDraw(Canvas canvas)
    {
    	RenderBitmap(mBitmap);
        canvas.drawBitmap(mBitmap, 0, 0, null);
    }
}

test107_03.png 次にネイティブ描画処理を実装する。今回はグラデーションが描画した。
#include <jni.h>
#include <android/bitmap.h>

/* this function is from Android NDK bitmap-plasma */
static uint16_t  make565(int red, int green, int blue)
{
    return (uint16_t)( ((red   << 8) & 0xf800) |
                       ((green << 2) & 0x03e0) |
                       ((blue  >> 3) & 0x001f) );
}


static void DrawBitmap(AndroidBitmapInfo* pBitmapInfo, void* pPixels)
{
    int		yy;

    for(yy = 0; yy < pBitmapInfo->height; yy++)
    {
        int		xx;
        uint16_t*  pLine = (uint16_t*)pPixels;

        for(xx = 0; xx < pBitmapInfo->width; xx++)
        {
        	pLine[xx] = make565(xx % 256,yy % 256,0);
        }

        // go to next line
        pPixels = (char*)pPixels + pBitmapInfo->stride;
    }
}




JNIEXPORT void JNICALL Java_com_Test107_NativeView_RenderBitmap(JNIEnv * env, jobject  obj, jobject bitmap)
{
    AndroidBitmapInfo  info;
    void*              pixels;
    int                ret;

    if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0)
        return;

    if (info.format != ANDROID_BITMAP_FORMAT_RGB_565)
        return;

    if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0)
        return;

    DrawBitmap(&info,pixels);

    AndroidBitmap_unlockPixels(env, bitmap);
}

test107_04.png Android.mkファイルも編集しておく。今回はログ出力していないので-llogは除外するしても構わない。
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := Test107jni
LOCAL_SRC_FILES := Test107jni.c
LOCAL_LDLIBS    := -lm -llog -ljnigraphics

include $(BUILD_SHARED_LIBRARY)

test107_05.png
ソースコードの編集が終わったらファイルを保存してndk-buildによりビルドする。

test107_06.png
そしてAndroidエミュレーターで実行するとネイティブの描画処理によるグラデーションが表示された。

※実際にはネイティブ側ではビットマップ処理のみ。描画はjava側で行っています、、、




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

Android NDKの「bitmap-plasma」のソースコードを見る

plasma01.png
今回はAndroid NDKに含まれるサンプルプロジェクト「bitmap-plasma」を見てみる。このプロジェクトはネイティブコードからの画面描画を行うサンプルだ。

EclipseでAndroidプロジェクトを作成する。その際に、「Create project from existing source」をチェックして、Android NDKのサンプルフォルダにある「bitmap-plasma」を指定する。

plasma02.png
これでEclipseに「bitmap-plasma」プロジェクトが取り込まれた。

plasma03.png
ネイティブコードのビルドにわざわざCygwinを開くのは面倒なので、プロジェクトフォルダ内にEasyProjectGeneratorにあるビルド用のバッチファイルをコピーしておく。

plasma04.png
jniフォルダ内にApplication.mkというmakeファイルがある。これは不要っぽいので削除した。(本当は必要なのかもしれませんが、、、)

plasma05.png
そしてndk-buildによりネイティブコードをビルドする。

plasma06.png
最後にEclipseでプロジェクトを実行する。

plasma07.png
これでAndroidエミュレーターでサンプルプロジェクトが実行された。







plasma08.png
サンプルソースコードを少し見てみる。Plasma.javaのOnDraw()内でネイティブの描画処理が呼ばれている。また描画後すぐにinvalidate()が呼ばれるために描画領域が無効化されて再描画していた。

plasma09.png
次にネイティブコードのplasma.cを見てみる。メイン処理の中では、javaから渡された引数をAndroidBitmap_lockPixels()によりメモリとして取得、AndroidBitmap_unlockPixels()により開放、その間に描画がされていた。

plasma10.png
さらに見ると、AndroidBitmap_lockPixels()により取得したメモリには、x方向のピクセルデータ1列をfor()によりy軸方向に回していた。別に疑っていた訳ではないが、本当にベタなピクセルデータとしてネイティブ側からアクセスできるようだ。


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

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

https://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ファイルを確認できた。



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

2010年12月27日

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

test105_01.png
今回はオープンソースのデータベース「SQLite」をAndroid NDKから呼び出して利用してみる。

まずhttps://www.sqlite.org/ download.htmlからSQLiteのソースコードをダウンロードする。利用したバージョンはSQLite 3.7.4だ。

test105_02.png
次にEasyProjectGenerator for Android Ver 1.00を利用してAndroid NDKプロジェクトを生成、Eclipseに取り込む。

test105_03.png
そしてプロジェクトフォルダのjniフォルダの下に「sqlite」というフォルダを作り、中に先ほどダウンロードしたSQLiteのソースコードを一式解凍する。

test105_04.png
さらに自動生成されていたソースコードとmakefileを「test105」というフォルダを作り、その中へ移動する。

test105_05.png
これでプロジェクトフォルダ内が図のようになった。

test105_06.png
ここでjniフォルダ直下にAndroid.mkファイルを新規作成する。

test105_07.png jniフォルダ直下にAndroid.mkファイルの中に1行追加。サブフォルダのmakefileを検索してビルドされるようにした。
include $(call all-subdir-makefiles)

test105_08.png 次にsqliteフォルダ直下にAndroid.mkファイルを新規作成し、内容を編集する。
このmakefileはAndroidプロジェクトのhttps://code.google.com/ p/rowboat/内で使われていたものを改変した。
#
# from rowboat-external-sqlite-master and modified
#

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := sqlite3.c

ifneq ($(TARGET_ARCH),arm)
LOCAL_LDLIBS += -lpthread -ldl
endif

LOCAL_CFLAGS += -DHAVE_USLEEP=1 -DSQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576 -DSQLITE_THREADSAFE=1 -DNDEBUG=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_DEFAULT_AUTOVACUUM=1 -DSQLITE_TEMP_STORE=3 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_BACKWARDS -DSQLITE_ENABLE_POISON -Dfdatasync=fsync

ifneq ($(TARGET_SIMULATOR),true)
LOCAL_SHARED_LIBRARIES := libdl
endif

LOCAL_MODULE:= libsqlite
#new sqlite 3.5.6 no longer support external allocator
#LOCAL_CFLAGS += -DSQLITE_OMIT_MEMORY_ALLOCATION
LOCAL_C_INCLUDES += $(call include-path-for, system-core)/cutils
LOCAL_SHARED_LIBRARIES += liblog \
            libicuuc \
            libicui18n \
            libutils

# include android specific methods
LOCAL_WHOLE_STATIC_LIBRARIES := libsqlite3_android

include $(BUILD_SHARED_LIBRARY)

test105_09.png 次にJNIにより実行される関数でSQLiteが利用されるようにする。
#include <string.h>
#include <jni.h>

#include "../sqlite/sqlite3.h"

jstring
Java_com_Test105_Test105Act_stringFromJNI(JNIEnv* env,jobject thiz)
{
	char	pszRet[256];
	strcpy(pszRet,"Failed.");

	sqlite3 *db;
	int rc = sqlite3_open("/sdcard/a.db", &db);
	sqlite3_stmt *st;

	rc = sqlite3_prepare(db, "CREATE TABLE test(id INTEGER PRIMARY KEY,name TEXT);", -1, &st, NULL);
	rc = sqlite3_step(st);
	rc = sqlite3_finalize(st);

	rc = sqlite3_prepare(db, "INSERT INTO test(name) VALUES (?);", -1, &st, NULL);
	sqlite3_bind_text(st, 1, "abcdef", -1, SQLITE_STATIC);
	rc = sqlite3_step(st);
	rc = sqlite3_finalize(st);

	rc = sqlite3_prepare(db, "SELECT name FROM test", -1, &st, NULL);
	while((rc = sqlite3_step(st)) == SQLITE_ROW)
	{
		char* pszName = (char*)sqlite3_column_text(st, 0);
		strcpy(pszRet,pszName);
		break;
	}
	sqlite3_finalize(st);

	sqlite3_close(db);

	return (*env)->NewStringUTF(env, pszRet);
}

test105_10.png そして共有ライブラリとしてSQLiteが読み込まれるようにAndroid.mkを編集する。
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := Test105jni
LOCAL_SRC_FILES := Test105jni.c

LOCAL_SHARED_LIBRARIES := libsqlite

include $(BUILD_SHARED_LIBRARY)

test105_11.png
これでndk-buildによりネイティブコードをビルドする。

test105_12.png
そしてプロジェクトをAndroidエミュレーターで実行。

test105_13.png
これで正常に動いた。

test105_14.png
EclipseのDDMSから仮想SDカード内にSQLiteが作成したデータベースファイルも確認できる。




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

AndroidネイティブアプリからSDカードへファイルを保存する

test104_01.png
今回はAndroidネイティブアプリからSDカードへファイルを読み書きしてみる。
前回紹介したEasyProjectGenerator for Android Ver 1.00を利用してAndroidプロジェクトを生成、Eclipseに取り込む。

test104_02.png そしてjniフォルダにあるネイティブソースコードにファイル関連処理を入れる。ソースコードを編集したら忘れずにファイル保存する。
#include <string.h>
#include <jni.h>
#include <stdio.h>

jstring
Java_com_Test104_Test104Act_stringFromJNI(JNIEnv* env,jobject thiz)
{
	char*	pszRet;
	char	pszBuff[256];
	FILE	*fp;

	/* file WRITE */
	fp = fopen("/sdcard/test.txt","w");
	if(fp)
	{
		fputs("Test line.",fp);
		fclose(fp);
	}

	pszBuff[0] = NULL;
	pszRet = NULL;

	/* file READ */
	fp = fopen("/sdcard/test.txt","r");
	if(fp)
	{
		pszRet = fgets(pszBuff,256,fp);
		fclose(fp);
	}

	if(pszRet)
	    return (*env)->NewStringUTF(env, pszBuff);
	else
	    return (*env)->NewStringUTF(env, "Error.");
}

test104_03.png
そしてプロジェクトフォルダ内にあるバッチファイルを利用してネイティブコードをビルドする。

test104_04.png
ネイティブのビルドが終わったら、Eclipse上から実行する。

test104_05.png
これでAndroidエミュレーター上でエラーが表示されず、実行が確認できた。

test104_06.png Eclipseの「DDMS」画面の「File Explorer」見ると、実際にファイルが保存されていた。
本来であればAndroidManifest.xmlにandroid. permission. WRITE_EXTERNAL_STORAGEを設定する必要があると思うのだがなくても動作するようだ。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>



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

Android JNIプロジェクト用のウイザードを使う(EasyProjectGenerator for Android Ver 1.00)

epg01.png
ネイティブなAndroid開発は、雛形となるプロジェクトを作るのが面倒で、ちょっとしたソースコードテストをしにくい。そのため、簡単にAndroidプロジェクトを自動生成する「EasyProjectGenerator for Android」を作りました。

EasyProjectGenerator for Android Ver 1.00」をダウンロードしてデスクトップへ解凍する。これでインストールが終ります。

epg02.png
インストールしたフォルダにある「HelloJni.bat」を実行する。

epg03.png
すると自動生成するAndroidプロジェクト名を入力するダイヤログが開く。今回は「Test103」とした。

epg04.png
するとEasyProjectGenerator for Androidのインストールフォルダ内にプロジェクト名と同じフォルダができる。これが自動生成されたAndroidプロジェクトです。

epg05.png
実際に自動生成したプロジェクトを利用するためEclipseを起動し、「File」メニューの「New」にある「Android Project」を選択する。

epg06.png
そして「Create project from existing source」を選択し、先ほど生成されたフォルダを指定する。

epg07.png
これでEclipseにAndroidプロジェクトとして取り込めた。

epg08.png
プロジェクトフォルダ内には「_build.jni.bat」がある。これを実行すると、、、

epg09.png
ダブルクリックひとつでAndroidネイティブソースコードがビルドされる。



もしもbashが見つからないというエラーが生じる場合は、環境変数のパスに「c:\cygwin\bin」を追加する。

epg10.png
次にEclipseでプロジェクトを右クリックして現れるメニューの「Run As」にある「Android Application」を選択する。

epg11.png
するとAndroidエミュレーターが起動して、自動生成したネイティブアプリが実行される。



まだまだ未完成な部分もあるが、これからはこの「EasyProjectGenerator for Android」を利用して雛形プロジェクトを生成、利用する。


2010年12月26日

Androidエミュレーターの仮想SDカードを使う

sd01.png
今回はAndroidアプリ上でSDカードにデータファイルを保存する前段階として、Androidエミュレーターで仮想SDカード上に保存したmp3ファイルを再生してみる。

まず仮想SDカードのイメージファイルを作るためにコマンドラインを開く。「スタート」メニューから「cmd」と入力して検索、コマンドラインを開く。

sd02.png コマンドラインが開いたら、Android SDKに含まれるmksdcard.exeを、「mksdcard 容量 作成イメージファイル名」というように実行する。ここでは64MBの仮想SDカードを作成した。
"C:\Program Files\Android\android-sdk-windows\tools\mksdcard.exe" 64M c:\workspace\sd.img

sd03.png
次に作成した仮想SDカードのイメージファイルをAndroidエミュレーターに関連付ける。Eclispeを起動して、「Window」メニューの「Android SDK and AVD Manager」を開く。

sd04.png
古いエミュレーター設定が残っていると紛らわしくなるので、今回は既存の設定を削除した。削除するAndroidエミュレーターを選択して「Delete」ボタンを押す。

sd05.png
「Yes」ボタンで削除する。

sd06.png
そして「New」ボタンから新しいエミュレーター設定をする。「Name」と「Target」は適当に設定、「SD Card」欄で先ほど作成した仮想SDカードのイメージファイルを指定する。

sd07.png
新しいエミュレーター設定ができた。さっそく「Start」ボタンで起動する。

sd08.png

sd09.png
しばらく待つとAndroidエミュレーターが起動した。

sd10.png Androidエミュレーターが起動したら、再びコマンドラインを開き、今度は仮想SDカードへmp3ファイルをコピーする。コピーにはAndroid SDKに含まれる「adb.exe」を利用する。「adb push ファイル名 /sdcard/」とすればコピーできる。
"C:\Program Files\Android\android-sdk-windows\platform-tools\adb.exe" push C:\Users\assist\Desktop\test.mp3 /sdcard/




sd11.png
次に仮想SDカードへmp3ファイルがコピーされたことを確認する。Eclipseを開き、「Window」メニューの「Open Perspectiv」にある「DDMS」を選択する。

sd12.png
そして「File Explorer」タブでAndroidエミュレーター上のファイルを一覧できる。/mnt/sdcard/の中を見ると、コピーしたmp3ファイルが確認できた。

sd21.png
ちなみにこの画面のアイコンから、マウス操作だけで簡単に仮想SDカードへファイルのコピーや削除ができる、、、が、どうもバグがあるようで、「Failed to push the item(s).」というエラーメッセージでファイル転送に失敗することがある。そのため上の方法でコマンドラインから転送した方がいいだろう。






sd13.png
最後に転送したmp3ファイルをAndroidエミュレーター上で再生してみる。ホーム画面でアプリケーションボタン?を押す。

sd14.png
最初はSDカードのmp3ファイルを認識させる必要があるた。「Dev Tools」を開く。

sd15.png
そして「Media Scanner」を実行する。

sd16.png
「Medea Scanner finished scanning /mnt/sdcard」と表示され、仮想SDカード内のファイルが認識された。

sd17.png
一度ホーム画面に戻り、再びアプリケーションボタン?を押す。

sd18.png
そして再生ソフトの「Music」を開く。

sd19.png
これでmp3ファイルのアーティストが表示され、、、

sd20.png
Androidエミュレーター上でTylor SwiftのMineを再生できた。


2010年12月24日

Android JNIプロジェクトをゼロから作る

test102_01.png
前回はAndroid NDKに含まれるJNIサンプルプロジェクト「Hello-jni」をビルド実行した。今回はAndroid JNIプロジェクトの構造を知るために、「Hello-jni」とまったく同じプロジェクトをゼロから作成してみる。

test102_02.png
Eclipseを起動したら、「File」メニューから「Android Project」を作成する。

test102_03.png
今回はプロジェクト名を「Test102Prj」、ターゲットを「Android 2.3」、パッケージ名を「com.test102」、アクティビティ名を「Test102Act」とし、プロジェクト名、パッケージ名、アクティビティ名を区別できるようにした。

test102_04.png
次にC言語ソースファイルを保存するフォルダをプロジェクト内に作成する。プロジェクトを右クリックして現れるメニューの「New」にある「Folder」を選択する。

test102_05.png
フォルダ名は「jni」とする。

test102_06.png
次にjniフォルダの中にmakefileを作成する。「jni」フォルダを右クリックして現れるメニューの「New」にある「File」を選択する。

test102_07.png
ファイル名は「Android.mk」とする。これは常に固定のファイル名で、大文字小文字を区別するので要注意だ。

test102_08.png 「Android.mk」ファイルの中身を実装する。

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := test102jni
LOCAL_SRC_FILES := test102jni.c

include $(BUILD_SHARED_LIBRARY)

test102_09.png
次にjniフォルダの中にC言語のソースファイルを作成する。「jni」フォルダを右クリックして現れるメニューの「New」にある「File」を選択する。

test102_10.png
ファイル名は「test102jni.c」とする。

test102_11.png 「test102jni.c」ファイルの中身を実装する。
Javaへエクスポートする関数名は「Java_com_test102_Test102Act_stringFromJNI」のように、「Java_プロジェクト名_アクティビティ名_関数名」と設定する。
#include <string.h>
#include <jni.h>

jstring
Java_com_test102_Test102Act_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
    return (*env)->NewStringUTF(env, "Test102text");
}

test102_12.png 次にJavaソースファイルの「Test102Act.java」を開き、編集する。赤枠の8行を追加した。

package com.test102;

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

public class Test102Act extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        TextView  tv = new TextView(this);
        tv.setText( stringFromJNI() );
        setContentView(tv);
    }

    public native String  stringFromJNI();

    static {
        System.loadLibrary("test102jni");
    }
}

test102_13.png
最後に「Save All」で全ファイルを保存する。

test102_14.png そしてCygwinを開き、作成したJNIソースファイルをビルドする。
cd /cygdrive/c/workspace/Test102Prj
ndk-build

test102_15.png
Cygwinでビルドできたら、Androidパッケージのビルド/実行をする。プロジェクトを右クリックして現れたメニューの「Run As」にある「Android Application」を選択する。

test102_16.png
これでAndroidエミュレーター上で実行を確認できた。


前の10件 6  7  8  9  10  11  12  13  14  15  16