Blog

UnityでAndroid、iOS両対応のC++プラグインの実装

はじめに

Unityでは、プラグインとしてC言語(C++)で作成したスタティックライブラリの呼び出しが可能です。
今回は、Android、iOSで共通のコードで作成したライブラリの作成について紹介します。

前提条件

  • Unity 5.0.1 Personal Edition
  • 開発環境:Mac OS
  • Xcode
  • Andorid SDK, NDK
  • 実機での実行(Unity Pro版ではシミュレータでの実行も可能※1)

※1 iOSではすこし工夫が必要なようです。参考

サンプル用のプロジェクトの準備

今回は、Survival Shooterを利用しました。

Asset Storeからインポート後、ビルドしてiOS、Androidの実機で動作することを確認します。※Unity5だと、「NavMesh asset format has changed. Please rebake the NavMesh data」というエラーがコンソールに出ます。「_CompletedAssets/Scenes/Level 01」を開いて、NavigationタブをBakeに切り替えて右下のBakeボタンで解消できますがそのままでも問題ありません。

プラグイン用のディレクトリを作成

ここにしたがって、「Plugins/Andorid」と「Plugins/iOS」を作成します。さらに、ソースコード用のディレクトリ「Plugins/src」を作成します。

C++のプロジェクトをXcodeで作成

XcodeでFile > New > Project…でプロジェクトテンプレートの選択画面を開き、iOS / Framework & Library / Cocoa Touch Static Library を選択してNext、Product Nameはhello、保存先を先ほど作成した「Plugins/src」にします。

作成したプロジェクトにはhello.h、hello.mという2つのファイルがありますが今回はC++で作成するので削除して、新たにhello.cppというC++のファイルを作成します。

helloTestsフォルダも今回は使用しないので削除しておきます。

PROJECTの設定の下記を変更します。

  • Per-configuration Build Products Path を「../iOS」に
    ※ライブラリが「Plugins/iOS」に出力されるようになります。
  • iOS Deployment Targetは「iOS 5.0」に

C++のプログラムの作成

hello.h、hello.cppは下記のようなものを作成しました。
今回は、実行されていることが確認できれば良いので、ログへの出力だけを行います。

#ifdef __ANDROID__ の部分は、AndroidとiOSの作り分けの実装です。

hello.h

#ifndef __hello__hello__
#define __hello__hello__

extern "C" {
    int test();
}

#endif /* defined(__hello__hello__) */

hello.cpp

#include "hello.h"
#include 

#ifdef __ANDROID__
# include <android/log.h>
#endif

int test(){
#ifdef __ANDROID__
    __android_log_write(ANDROID_LOG_DEBUG, "hello.cpp", "Hello,World!");
#else
    printf("Hello,World!\n");
#endif
    return 0;
}

Androidビルド用のスクリプトの作成

ソースコードと同じ階層に、Android.mk、Application.mk、build_plugin.shの各ファイルを作成します。

Android.mk

include $(CLEAR_VARS)

LOCAL_ARM_MODE  := arm
LOCAL_PATH      := $(NDK_PROJECT_PATH)
LOCAL_MODULE    := libhello
LOCAL_CFLAGS    := -Werror
LOCAL_SRC_FILES := hello.cpp
LOCAL_LDLIBS    := -llog

include $(BUILD_SHARED_LIBRARY)

Application.mk

APP_OPTIM        := release
APP_ABI          := armeabi
APP_PLATFORM     := android-8
APP_BUILD_SCRIPT := Android.mk

build_plugin.sh
※path_to_android_ndkは環境に合わせて書き換えてください

#!/bin/sh
ANDROID_NDK_ROOT=path_to_android_ndk

$ANDROID_NDK_ROOT/ndk-build NDK_PROJECT_PATH=. NDK_APPLICATION_MK=Application.mk $*
mv libs/armeabi/libhello.so ../../Android/

rm -rf libs
rm -rf obj

ライブラリのビルド

Androidはbuild_plugin.shをソースディレクトリ上で実行して、iOSはxcodeのPruduct > Buildからライブラリのビルドを行います。

「Plugins/Andorid」libhello.so、「Plugins/iOS」にlibhello.aがそれぞれ作成されていることを確認します。


Unityのコンソールに、
Plugin ‘hello.h’ is used from several locations:
Assets/Plugins/src/hello/hello.h would be copied to /hello.h
のようなエラーが出たら、該当のファイルのInspectorから、「Select platfoms for plugin」のチェックを全て外します。

プラグイン用スクリプトの作成

「Plugins」内に下記のような「PliginTest.cs」を作成します。
「DllImport」は作成したライブラリの読み込みです。AndroidとiOSで記述方法が異なります。
「private static extern 〜」はC++で実装した関数の呼び出しです。

PliginTest.cs

using UnityEngine;
using System.Runtime.InteropServices;

public class PliginTest {

	#if UNITY_IPHONE || UNITY_XBOX360
	[DllImport ("__Internal")]
	#else
	[DllImport ("hello")]
	#endif

	private static extern int test ();

	public static int helloTest() {
		return test ();
	}
}

プラグインの呼び出し

今回は、下記のスクリプトのFixedUpdate内に追加をしました。
関数呼び出し確認のログとプラグイン関数の呼び出しを行います。

/Assets/_CompletedAssets/Scripts/Player/PlayerMovement.cs

		void FixedUpdate ()
		{
			Debug.Log("FixedUpdate");
			PliginTest.helloTest ();

			~以下変更無し
		}

プロジェクトの実行

UnityのFile > Build Settings…からPlatformを選択して「Switch Platform」(現在のPlatformと異なる場合)、「Build And Run」をクリックして実行を行います。

ログに
FixedUpdate
Hello,World!
が出力されれば、呼び出しは成功です。

Android

iOS

参考サイト

http://docs.unity3d.com/Manual/Plugins.html
http://docs.unity3d.com/Manual/PluginsForIOS.html
http://docs.unity3d.com/ja/current/Manual/PluginsForIOS.html

, , , , ,
Blog