iPhone/iPadのプラグインを作成する方法(改訂版)
※以前作成したエントリーでは Plugins/iOS フォルダを使って自動的にXcodeプロジェクトにファイルに含める方法を使って無かったので使う様に修正。
※ソースコードをGitHubからの配布に変更。
UnityからXcodeで記述した機能が呼べるiPhone/iPadのプラグインを作成する方法を解説。今回のサンプルはこちらからDL出来ます。
プラグインを作ればネイティブコードで出来る事はなんでも出来ちゃいます。作成したプラグインはiOS Proライセンスはもちろん、iOSライセンスでも使用可能です。
手順は以下の様になります。
1. ビルドしてXcodeのプロジェクトを作成。
2. Xcode側のプログラムを作成する為にファイルを生成。プログラムを記述する。
3. Unity側でXcode側のプログラムとUnity側のプログラムを橋渡しするプログラムを作成。
順番に詳しく解説します。 1. は問題無いと思うので 2. から
Xcode側のプログラムを作成する為にファイルを生成
今回はiPhone/iPadで設定されている言語を取得するプログラムを例に解説します。
※言語はプラグインを作らなくても Application.systemLanguage で取得出来そうな気がしますが実はiPhone/iPadでは Unknown が返され取得出来ません。
Xcode上で LanguagePlugin.h/LanguagePlugin.m を作成し、.mファイルに以下の様に記述します。
char* MakeStringCopy (const char* string) { if (string == NULL) return NULL; char* res = (char*)malloc(strlen(string) + 1); strcpy(res, string); return res; } char *CurrentLanguage_ () { NSArray *languages = [NSLocale preferredLanguages]; NSString *currentLanguage = [languages objectAtIndex:0]; return MakeStringCopy([currentLanguage UTF8String]); }
CurrentLanguage_ () がメインの関数で MakeStringCopy() で文字列を加工しているのは以下を詳しく読んで貰うと分かりますが
Unity - Plugins - Pro/Mobile-Only Feature
http://unity3d.com/support/documentation/Manual/Plugins.html
文字列についてはこの様なルールが有るからです。
String values returned from a native method should be UTF-8 encoded and allocated on the heap. Mono marshaling calls are free for them.
コレに対処する為の処理は自分で作成しても良かったのですが公式で配布しているこちらのサンプルに記述が有ったのでそのまま流用しています。それが MakeStringCopy () となります。
このXcode側のプログラムのファイルは置く場所によってはUnityでビルドしてXcodeプロジェクトが再生成された時に(場合によっては)上書きされてしまうので以下のいずれかの位置に置くのが推奨されています。
・Unity側のプロジェクトの Assets フォルダ
・Xcode側のプロジェクトの Classes フォルダ
なお、Unity側のプロジェクトの Assets フォルダの中に Plugins/iOS というフォルダを作成し、そのフォルダにファイルを置いておくとiOS向けにビルドした時に、自動的に生成されるXcodeのファイルに含まれます。なお、サブフォルダには対応してないみたいなので Plugins/iOS/image/hoge.png などという位置にファイルを置くとそのファイルは対象に含まれないので注意して下さい。
Unity側でXcode側のプログラムとUnity側のプログラムを橋渡しするプログラムを作成
Unityに戻ってプログラムの橋渡しをするプログラムを作成します。
Plugins フォルダ( Plugins/iOS では有りません)にC#のファイルを Binding という名前で作成します。
プログラムは以下。
using UnityEngine; using System.Runtime.InteropServices; public class Binding { [DllImport("__Internal")] private static extern string CurrentLanguage_ (); public static string CurrentLanguage () { if (Application.platform != RuntimePlatform.OSXEditor) { return CurrentLanguage_ (); } else { return ""; } } }
この CurrentLanguage_ () がXcode側で作成した関数になります。
UnityのIDE上で実行した時にはこの関数を呼ぶことは出来ないので Application.platform でチェックをし、IDE上で実行中の場合は "" を返しています。
実際にこの CurrentLanguage() を呼ぶ場合はこの様にします。
Debug.Log( Binding.CurrentLanguage() );
今回は画面の左上に取得した言語を表示される様に、こんなプログラムを作成しました。
private var lang: String; function Start () { lang = Binding.CurrentLanguage(); } function OnGUI () { GUI.Label(Rect(20, 20, 100, 100), lang); }
これを実行すると以下の様に画面の左上に小さく(※)現在の言語設定が表示されます。日本語に設定されている場合は ja と表示されます。
※UnityでiOS向けビルドで動的に大きい文字を使うのはちょっと手間なのでこうなってます。
補足情報
もし、Xcode側のプログラムをC++や.mmファイルで作成する場合はCから呼べるC++のプログラムを作成する時と同様に以下の様に extern "C" (リンケージ指定)が必要です。
extern "C" { float FooPluginFunction (); }
プラグインのプログラム作成中になんだか上手く動かない場合には自分は以下の様なアラートを表示してデバッグしました。
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"テスト" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil]; [alert show]; [alert release];
関連情報
Unity向けのARプラグインの制作手法について解説したスライド資料。
UnityでのARアプリケーション開発
http://qoncept.jp/ar/seminar/unity_20110716.pdf
こちらは以下のイベントで使われたものです。
IGDA日本ゲーム開発セミナー「Unityの導入と実践」に参加して来ました - 強火で進め
http://d.hatena.ne.jp/nakamura001/20110716/1310821202
構造体を引数にする場合。
Specific steps to set up a plugin for iphone in XCode - Unity Answers
http://answers.unity3d.com/questions/10110/specific-steps-to-set-up-a-plugin-for-iphone-in-xc.html
Byte配列を引数にする場合。
Returning a byte array from ObjC to C# script on ios - Unity Answers
http://answers.unity3d.com/questions/132083/returning-a-byte-array-from-objc-to-c-script-on-io.html
Unity - Plugins (Pro/Mobile-Only Feature)
http://unity3d.com/support/documentation/Manual/Plugins.html関連リンク
【Unity Proのみ対応】 Mac 環境のプラグインを作成 - 強火で進め
http://d.hatena.ne.jp/nakamura001/20120901/1346529070