LoginSignup
4
2

More than 1 year has passed since last update.

UnityC++プラグイン各種プラットフォームのテンプレート

Last updated at Posted at 2022-05-09

はじめに

C++で作成したプラグインをUnityで利用する方法は調べると出てきますが、複数のプラットフォームでの対応の仕方がまとまっている記事がなかったので今回まとめたいと思い立ちました。

主要なプラットフォームのテンプレートを作成してみました。

こちらのテンプレートはC#側に計算結果や文字列を渡して表示するだけのサンプルになります。

主要なプラットフォーム

何が主要なのかと言うのは私の主観になってしまいますが、ソーシャルゲームアプリを開発する上では以下のプラットフォームが対応されれば十分だと考えています。

  • Windows
  • MacOS
  • iOS
  • Android

ビルド周りに関しては、Windows以外はMacでのやり方で書いていきます。

C++のプラグインがなぜ必要なのか?

普段の開発で自前で実装することは少ないと思いますが、必要になる理由は大きく以下の2つがあるかと思います。

1.処理速度が重要になる処理がある
2.C/C++で書かれたライブラリを利用したい

個人的には1よりも2の理由が大きいと感じています。

OpenCVやSQLiteのようにC/C++で作られたライブラリをC#で利用したいことはよくあります。

上記2つのライブラリはすでにUnityで使用できるように対応されてはいますが、自前で実装したかったり、誰も対応していないライブラリを使う必要が出てくるケースも出てくると思います。

UnityCppPluginSampleの説明

サンプルのバージョン情報

Unity 2020.3.15f2
XCode 12.4
VisualStudio Community 2019 16.11.13

サンプル内容

実用性はほとんどないですが、

  • 2つの値の足し算
  • 文字列を生成して返す

のサンプルになっています。

Screen Shot 2022-05-06 at 15.10.59.png

ツリー構造

├── Native // C++のソースとビルドに必要なプロジェクト
│   ├── projects // 各プラットフォームのプロジェクト
│   │   ├── android
│   │   ├── ios
│   │   ├── osx
│   │   └── windows
│   └── src // ソースコード
├── Unity
│   ├── Assets
│   │   ├── Plugins // ビルドしたプラグインを格納する場所

各プラットフォームのプラグインタイプ

プラットフォーム 拡張子
Windows xxx.dll
MacOS xxx.bundle
iOS xxx.a
Android xxx.so

各プラットフォームのプロジェクト作成

Windows

VisualStudioプロジェクト作成時の参考

MacOS

XcodeでmacOS/Bundleのプロジェクトを作成

iOS

XCodeでiOS/StaicLibrary Objective-Cのプロジェクトを作成

Android

mkファイルを作成して、NDKを使用してコマンドビルド

プラットフォームごとのビルド方法

ProjectSettingsのPlayer/OtherSettings/ScriptingBackendはIL2CPPで設定してください。

Windows

1.Native/projects/windows/windows.slnをVisualStudioで開く

2.ビルド/windowsのビルドでビルドを実行

設定はReleaseのx64
image.png

3.UnityのPluginsに配置して設定

dllの出力先はNative\projects\windows\x64\Release\windows.dll

Assets/Plugins/x64内に格納

image.png

32bit版が必要な場合は、x86もビルドして設定

MacOS

ビルドするためにはXCodeが必要で、GUIでのビルド方法を書きます。

1.Native/projects/osx/osx.xcodeprojをXCodeで開く

2.Product/Buildでビルド実行

M1Macが手元にないので、検証できないのですが、ビルドターゲットにAppleSiliconと書いてあるのでM1もいける🤔
Screen Shot 2022-05-06 at 16.05.30.png

3.ビルドの成果物の場所を調べる

Products/osx.bundleを選択すると
Screen Shot 2022-05-06 at 15.24.21.png

インスペクターから場所を知ることができます。
Screen Shot 2022-05-06 at 15.25.10.png

4.UnityのPluginsに配置して設定

Assets/Plugins/OSXの中にいれる
Screen Shot 2022-05-06 at 15.29.35.png

iOS

ビルドするためにはXCodeが必要で、GUIでのビルド方法を書きます。
MacOSとほとんどやり方は同じです。

1.Native/projects/ios/ios.xcodeprojをXCodeで開く

2.Product/Buildでビルド実行

こちらからターゲットデバイスを選択できますが、サンプルに入っているプラグインはシミュレーター用になっています。
Screen Shot 2022-05-06 at 15.57.22.png

所持しているiPhoneとXCodeのバージョンが合わず、直接つないでデバイスにインストールができず・・・

検証が可能になりましたら検証します。

3.ビルドの成果物の場所を調べる

Products/libios.aを選択すると
Screen Shot 2022-05-06 at 15.33.39.png

インスペクターから場所を知ることができます。
Screen Shot 2022-05-06 at 15.47.22.png

4.UnityのPluginsに配置して設定

Assets/Plugins/iOSの中に入れる
Screen Shot 2022-05-06 at 15.49.58.png

Android

Androidのビルドに関しましては、こちらの記事を参考にさせていただきました。

一つAndroidでハマった点がありまして、最初プラグインの名前をSamplePlugin.soという名前で格納して検証したところうまく読み込まれませんでした。
apkに入っていた他のプラグインの名前に合わせてlibsampleplugin.soとしたところうまく読み込まれました。
C#側で読み込むときはlibとsoの部分は除いてsamplepluginで読み込めます。
他にlibSamplePlugin.soで格納してC#側でSamplePluginとしてもうまく読み込まれなかったので、全部小文字にしたほうが良いかもしれません。

1.NDKのパスを調べる

NDKを手動でダウンロードして来ても良いのですが、UnityのPreferenceのAndroid NDK installedwith Unityからパスを知ることができます。
自分の環境の場合は以下のパスでした

/Applications/Unity/Hub/Editor/2020.3.15f2/PlaybackEngines/AndroidPlayer/NDK

Screen Shot 2022-05-06 at 16.19.27.png

2.シェルスクリプトを用意

Native/projects/android/build.shを作成します

ANDROID_NDK_ROOT=/Applications/Unity/Hub/Editor/2020.3.15f2/PlaybackEngines/AndroidPlayer/NDK

$ANDROID_NDK_ROOT/ndk-build NDK_PROJECT_PATH=. NDK_APPLICATION_MK=./Application.mk

ANDROID_NDK_ROOTは各々の環境のパスを指定してください。

Macでビルドすることを想定して、mkファイルを作成しましたが、詳しくないので必要に応じて調べる用にお願いします。

3.シェルスクリプト実行

Native/projects/android/に移動して

./build.sh

権限エラーが出た場合は

chmod 777 ./build.sh

4.Unityのプラグインに配置

ビルドはNative/projects/android/libs配下にそれぞれのアーキテクチャごとに出力されています。

arm64-v8a,armeabi-v7a,x86それぞれフォルダごと、UnityのAssets/Plugins/Androidに配置してください。

設定はインポート時に適切なものに設定されるはずです。

C++のソース

ソースファイル(cpp)は、文字列の渡し方以外特筆する点はないので今回は省きます。

プラットフォームが異なっても1ファイルで対応できるようにしています。

library.hpp
#ifndef SOURCE_LIBRARY_HPP
#define SOURCE_LIBRARY_HPP

#ifdef _WINDOWS
    #define _CRT_SECURE_NO_WARNINGS
    #define DLL_EXPORT __declspec(dllexport)
#endif

#ifndef _WINDOWS
    #define DLL_EXPORT
#endif


extern "C"  {
    DLL_EXPORT int sum(int a, int b);
    DLL_EXPORT char* helloWorld();
};

#endif //SOURCE_LIBRARY_HPP

注目する点はDLL_EXPORTの定義で、Windowsのときだけ__declspec(dllexport)を定義しています。
dllは外に公開する関数を明示的に宣言するために必要で、dllをビルドするときに必要になるみたいです。
Windows以外のプラットフォームだとエラーになってしまうため、Windowsのみ定義しています。

参考

_WINDOWSはVisualStudioプロジェクトのDefineSymbolで定義されます。

_CRT_SECURE_NO_WARNINGSはstd::strcpyを使用するとビルドが止められるので、定義しています。

C#のソース

PluginTest.cs
using UnityEngine;
using System.Runtime.InteropServices;

public class PluginTest
{
#if !UNITY_EDITOR && UNITY_IOS
    private const string PLUGIN_NAME = "__Internal";
#else
    private const string PLUGIN_NAME = "sampleplugin";
#endif
    
    [DllImport(PLUGIN_NAME)]
    public static extern int sum(int a, int b);

    [DllImport(PLUGIN_NAME)]
    public static extern string helloWorld();
}

iOSのみ__Internalで指定します。
他にもプラグインがあると関数名がかぶる可能性があるので、外出しの関数名は被らない名前にしたほうが良さそうです。

最後に

各プラットフォームごとにビルドが違えば、コンパイルエラーも違ったり骨が折れる作業ですね・・・
今回はHelloWorldプラグインサンプルを作成しましたが、実用的なプラグインを作るためには他のライブラリのインポートが必要になってきます。
C++は一つのライブラリを読み込むためにも大変なので、こちらも機会があれば記事にしていきたいと思います。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2