MacOSXでAndroid開発環境を構築する

2011/8/13の情報です。環境はMac OS X 10.7(Lion) & eclipse indigo日本語化済み
android-sdk_r12-mac_x86android-ndk-r6を導入してプロジェクトを作成するまでの手順になります。
自分用のメモですので手順が明らかなところは少し省略しているかもしれません、ご注意ください。

Android SDKの導入

Android SDKのダウンロード

本家サイト http://developer.android.com/sdk/index.html からandroid-sdk_r12-mac_x86.zip
をダウンロードして、適当な場所に解凍する。(例えば /Applications/android/android-sdk-mac_x86)

ADTをインストールする

ヘルプ→新規ソフトウェアのインストール→追加で以下のサイトを登録する

名前: "android" (適当な名称)
ロケーション:https://dl-ssl.google.com/android/eclipse/

開発ツール→Android開発ツールにチェック→次へ→使用条項に同意した場合は"完了"→自動インストール開始→eclipseを再起動

その他コンポーネントのインストール

ウインドウ→Android SDK および AVD マネージャー→AVD Managerが起動する
→Available Packages→Android Repository→インストールしたいコンポーネントを選択
例えば、SDK Platform Android 2.1, 2.2, 2.3.3, SDK Platform Android 3.1, 3.2 , Android SDK Toolsなど
→選択項目をインストール→使用条項に許諾した場合は選択してから完了→インストール開始→eclipse再起動

SDKロケーションの設定

AndroidSDKのパスを通します。
Eclipse→環境設定→Android→使用統計を送信するかどうか選択する→続行→SDKロケーションに

//android-sdk-mac_x86

を設定する。ちなみにこの時点でまだコンポーネントがインストールされてない場合は警告が表示されるので一旦無視する。(その後コンポーネントをインストールすればよい。)

新規エミュレータの作成

ウインドウ→Android SDKおよびAVDマネージャー→Virtual Devices→新規
名前:新規作成するデバイス名、例えば"avd10"
ターゲット:ターゲットとなるSDKのバージョンを選択する。例えばAndroid 2.3.3 API Level 10
SDカードのサイズ→適当な値を設定する。例えば"32MB"
Skin:ビルトイン→適当な画面の種類を選択する。Defaultのままなど→"Create AVD"
Virtual Devices画面に戻り、作成したデバイスを選択して"開始"→"起動"→エミュレーターが起動する
エミュレータを終了するには、emulator arm→Quit emulator arm

プロジェクトを作成する

ファイル→新規→プロジェクト→Android→Android Project→次へ
→プロジェクト名に名称を入力 "HelloAndroid"
→アプリケーション名とActivity名に自動的に名称が入力されるので必要があれば名称を変更する
→ビルド・ターゲットにターゲットとなるAndroidのバージョンを選択する "Android 2.3.3"
→パッケージ名→学習用途なので適当に設定する"com.test" (リリースする場合は自分のドメインをパッケージ名として利用する "com.yourdomain")→完了
実行→Android アプリケーション→OK
以上で実行ファイル(apk)が作成されて自動的にエミュレータにインストールされます。Hello World HelloAndroidActivity!が表示されるアプリが起動すれば成功です。

ログの出力

コンソールにログを出力するにはLogCatという仕組みを使います。LogCatを表示する手順は以下のとおり
ウインドウ→ビューの表示→その他→Android→LogCat

Android NDK開発環境を導入する

ここからandroid-ndk-r6-darwin-x86.tar.bz2をダウンロードします↓
http://developer.android.com/sdk/ndk/index.html
ダウンロード完了後、任意のディレクトリに解凍します。(解凍先は例えば/Applications/android/android-ndk-r6など)。解凍したディレクトリのパスをと書くことにします。

メインプロジェクトを作成する

ファイル→新規→プロジェクト→Android→Android Project→次へ
→プロジェクト名に名称を入力 "AndroidNative"
→ビルド・ターゲット>Androidのバージョンを選択 "Android 2.3.3"
→パッケージ名→適切に設定する"com.yourdomain"→完了
(ここで作成したプロジェクトディレクトリのパスをとする。)
→ディレクトリ/jniを作成する
(つまり//内にassets, bin, gen, jni, res, srcディレクトリなどが存在しています。)

Native側モジュールを実装する

//jni/native.c を作成し、上側から呼び出すAPIを実装します。
例えばコンソールにデバッグメッセージを表示する関数をネイティブ側で実装してみます。まずはJNI部分の定義です。
native.h

#ifndef NATIVE_H
#define NATIVE_H

#ifdef __cplusplus
extern "C" {
#endif

#include <jni.h>

/**
 * native API to print debug messages
 */
JNIEXPORT void JNICALL Java_com_yourdomain_AndroidNativeActivity_nativeLog
(JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif

#endif // include guard

次にその実装です。Native側でログを出力する関数__android_log_vprintを利用していますので、”android/log.h”をインクルードしています。また、.cpp, .c共用ですので宣言部分をextern "C"で囲っています。
native.cまたはnative.cpp

#include "native.h"
#include <android/log.h>

void native_printf(const char *format, ...);

void native_printf(const char *format, ...){
	va_list	args;
	va_start (args,format);
	// call native log print API
	__android_log_vprint(ANDROID_LOG_DEBUG, "libnative.so", format, args);
	va_end (args);
}

JNIEXPORT void JNICALL Java_com_yourdomain_AndroidNativeActivity_nativeLog
(JNIEnv * env, jobject obj, jstring javaString){
	const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0);
	native_printf(nativeString);
	// release memory
	(*env)->ReleaseStringUTFChars(env, javaString, nativeString);
}

JNIによってネイティブな関数を定義するには

#include <jni.h>

をインクルードしておきます。JNIを利用して関数を宣言する場合、次のような規則で命名します。

Java_パッケージ名_クラス名_メソッド名
makefileを作成する

以下の場所に、ネイティブ側共有ライブラリ(.so)をコンパイルするためのmakefileを作成します。
/jni/Android.mk
このmakefileはAndroidNDK専用ですので、通常のmakefileとは少し使い勝手が異なります。

# get current local path
LOCAL_PATH := $(call my-dir)
# clear all LOCAL_*** definitions except LOCAL_PATH
include $(CLEAR_VARS)

# source file paths
LOCAL_SRC_FILES := native.c
# external libraries
LOCAL_LDLIBS := -llog

# output module name
LOCAL_MODULE    := native
# a kind of output library (static or shared)
include $(BUILD_SHARED_LIBRARY)

※__android_log_vprintが実装されているlogライブラリをリンクしなければリンクエラーになってしまいます。

Java側モジュールを実装する

既にActivityがプロジェクトに追加されているので、ここにNative側を呼び出すコードを記述します。

package com.yourdomain;

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

public class AndroidNativeActivity extends Activity {
	static {
		// load native shared library
		System.loadLibrary("native");
	}
	/**
	 * on create activity
	 */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        nativeLog("hello android native");
    }
    /**
     * print debug messages
     */
    public native void nativeLog(String message);
}

共有ライブラリを読み込むには以下のメソッドを利用します。

System.loadLibrary("native");

また、ネイティブなメソッドを定義するには接頭辞nativeを関数名の前につけるとよいです。

public native 戻り値 関数名(引数);
native側モジュールをビルドする

ターミナルでAndroid.mkが置いてあるパスに移動します。

cd /<project root>/jni

android NDKで用意されているndk-buildを実行します。

/<ndk root>/ndk-build

その結果、以下のように表示されればコンパイルが成功しています。

Compile thumb  : native <= native.c
SharedLibrary  : libnative.so
Install        : libnative.so => libs/armeabi/libnative.so

実際に//libs/armeabi/libnative.soが作成されていることが確認できます。

Java側モジュールをビルドする

apkの作成は通常のAndroidSDKと同様です。プロジェクト→プロジェクトのビルド, 実行→"実行"でapkを作成され、エミュレータに転送されます。エミュレータへの自動インストール完了後、アプリが動作するのを確認することができます。最終的にLogCatに以下のようなログが表示されていれば成功です。

libnative.so: hello android native