32
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Swift だけで Unity の iOS の Native Plugin を作る

Last updated at Posted at 2021-05-12

Swift だけで Unity の iOS の Native Plugin を作る

  • Unity は Native Plugin を作成することで、Unity から提供されていない、OS 固有の機能を使用することができます
  • 例えば iOS では、Bluetooth や MP4 動画の作成、アルバムの利用などが出来るようになります
  • これらの Native の機能を Swift で実装し、C# から呼び出す手順です
  • Swift Package Manager (以下 SwiftPM) を使って、Framework を作成し、Unity に組み込みます
  • ついでに、ライブラリの開発用の Native のアプリターゲットを作成します
  • Framework 化するメリット
    • PostProcess の設定が不要です
    • Unity の Inspector 上で Embed の設定が完了します
    • 合わせて Native でアプリターゲットを実装する事で、動作確認のために Unity のビルドをせずに、ライブラリの開発が可能です
  • 今回の話のリポジトリです↓

やりたい事

  • 今回は、Swift で文字列型の数値を long 型に変換する Native Plugin を実装します
  • [DllImport("__Internal")] を付けて定義された、関数 swiftPmPlugin_toNumber が Swift で実装された関数です
  • 今回は、C# にも存在する機能ですが、呼び出した先の Swift で iOS 固有の機能を利用することが可能です

https://github.com/fuziki/UnityPluginXcodeTemplate/blob/develop/Examples/UnityExample/Assets/Scripts/Cube.cs

public class Cube : MonoBehaviour
{
    // Swift で実装された関数の定義
    [DllImport("__Internal")]
    private static extern long swiftPmPlugin_toNumber(string numberString);

    void Update()
    {
        // 呼び出し
        Debug.Log("number is: " + swiftPmPlugin_toNumber("30"));
    }
}

Native Plugin の実装

  • Swift Package Manager (SwiftPM) を使って実装し Framework を出力します
  • 上記の swiftPmPlugin_toNumber が実装された SwiftPmPlugin.framework を作成します

環境

  • maxOS 11.3.1
  • Xcode 12.5
  • Swift 5.4.0
  • Unity 2020.3.5f1

Swift Package Manager

  • type に libraryを、name に 作りたいパッケージの名前 (今回は SwiftPmPlugin) を指定して、package を初期化します
  • library package が作成されるので、Package.swift を開きます
  • Xcode が起動するので、SwiftPmPlugin.swift に実装していきます
swift package init --type=library --name=SwiftPmPlugin
open Package.swift

Select_SwiftPmPlugin_swift.png

SwiftPmPlugin の実装

  • Swift でロジックを実装します
  • SwiftPmPlugin クラスに、文字列を数値に変換する toNumber 関数を実装しました
  • Int(string) ?? 0 として数値変換に失敗したときは、0 を返すようにしました

https://github.com/fuziki/UnityPluginXcodeTemplate/blob/develop/Sources/SwiftPmPlugin/SwiftPmPlugin.swift

class SwiftPmPlugin {
    var text = "Hello, World!"
    static func toNumber(string: String) -> Int {
        return Int(string) ?? 0
    }
}

Swift で関数を公開する

  • Swift で公開する関数を作成します
  • @_cdecl を使って、C の関数として定義します
  • char 配列のポインタを受け取って、Swift の String 型に変換します
  • 先ほど作った SwiftPmPlugin.toNumber を使って、String から Int に変換します
  • C# で定義した関数が戻り値が long 型で 64bit 整数なので戻り値も、揃えます
@_cdecl("swiftPmPlugin_toNumber")
public func swiftPmPlugin_toNumber(_ stringPtr: UnsafePointer<CChar>?) -> Int64 {
    let str = String(cString: stringPtr!)
    return Int64(SwiftPmPlugin.toNumber(string: str))
}

Framework でビルドする

  1. SwiftPM から xcodeproj を出力して
  2. xcodebuild を使って出力した xcodeproj から framework を作成します
  3. CONFIGURATION_BUILD_DIR に指定したディレクトリに、SwiftPmPlugin.framework 作成されています
swift package generate-xcodeproj --skip-extra-files
xcodebuild -project SwiftPmPlugin.xcodeproj -scheme SwiftPmPlugin-Package -configuration Release -sdk iphoneos CONFIGURATION_BUILD_DIR=.
  • Framework の Headers を確認すると、先ほど実装した swiftPmPlugin_toNumber が公開されていることが分かります
open SwiftPmPlugin.framework/Headers/SwiftPmPlugin-Swift.h

header.png

Unity でビルドする

Framework の設定

  • Plugins/iOS/ を作成して、SwiftPmPlugin.framework を配置します
  • SwiftPmPlugin.framework の Inspector で、Add To Embedded Binaries を有効にします
    • Add To Embedded Binaries を有効にすることで、ビルドしたときに Framework が自動で Embed され
      ます

inspector.png

iOSアプリをビルドする

  • Unity で、通常通り iOS 向けにビルドします
  • PostProcess などは、設定していないです
  • 作成した target の frameworks に、SwiftPmPlugin.framework があり、
  • Embed の項目が、Embed & Sign になっていることを確認します
    • 自動で追加されていない場合は、Unity の設定に失敗している可能性があります
    • 手動で追加しても問題ないです
  • 確認できれば通常通り iOS アプリを実行できるはずです

embed_framework.png

(おまけ)Framework 開発用の Native のアプリターゲットを作る

  • Framework の開発が便利になる tips 的なやつです
  • Unity で使う Framework の動作確認のために、Framework のビルド→Unityのビルド→iOSのサイクルを回すのは大変です
  • そこで、SwiftPM で作ったライブラリを取り込んだ、アプリターゲットを作成し、開発すると効率的だと考えています

xcworkspace を作成する

  • xcworkspace を作成し、Package を取り込み、アプリターゲットのターゲットを用意します
    ※ アプリを Objective-C で作る必要はないです、Swift でも問題ないです

xcworkspace.png

  • アプリターゲットの Frameworks に SwiftPmPlugin を追加します

embed_native.png

  • コードから呼び出すことが可能なので、呼び出します
#import "ViewController.h"
@import SwiftPmPlugin;
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    NSLog(@"value: %lld", swiftPmPlugin_toNumber("20"));
}
@end
  • Swift からも呼び出すことが可能です
import SwiftUI
import SwiftPmPlugin

struct ContentView: View {
    var body: some View {
        Text("number: \(swiftPmPlugin_toNumber("20"))")
            .padding()
    }
}

おわりに

  • Native Plugin を実装することで、ゲームの開発は Unity に集中しつつ、OS 固有の機能を十分に利用することが可能です
  • Swift で実装し、SwiftPM で管理し、Native アプリで動作確認することで、効率的な開発を目指しています

関連記事です

  • この実装を拡張して、Unity の Texture をやりとりする事が可能です

  • SendMessage のやり方はこちら

  • この実装を拡張して、Unity から関数のポインタを受け取って、コールバックすることも可能です

  • Bundle target を作成することで Unity Editor と共通化させて実装することが可能です

32
19
1

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
32
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?