LoginSignup
5
9

More than 3 years have passed since last update.

UnityでSwiftの自作「Static Library」を使う

Posted at

環境

  • Unity 2018.4.23f1
  • Xcode 11.5
  • Swift 5
  • iOS 13.4.1(iPhone 11)

手順の概要

「Unity」から直接「Swift」のコードを呼び出すことはできないようです。。。orz
その為、下記のような形で、「Objective-C++」を経由する事で、「Swift」の関数を呼び出します。

設定手順

「Swift」の「Static Library」を作成

「Xcode」で、プロジェクトを作成

  • 「iOS」→「Framework & Library」→「Static Library」を選択して、「Next」を押下

  • 下記の項目を設定して、「Next」を押下
    ※記載以外はデフォルト値

項目
Product Name 任意
Team 任意
Organization Name 任意
Organaization Identifier 任意
Language Objective-C

  • 任意のディレクトリにプロジェクトを作成

呼び出される「Swift」ファイルの作成

  • 「プロジェクト」→「コンテキストメニュー」→「New File」を押下

  • 「iOS」→「Source」→「Swift File」を選択して、「Next」を押下

  • 任意の名前を設定して、「Create」を押下

  • 「Create Briding Header」を押下

  • 作成した「Swift」ファイルを選択して、呼び出す関数を作成

//
//  SwiftTest.swift
//  SwiftStaticLibrary
//
//  Created by Kumatta_ss on 2020/05/31.
//  Copyright © 2020 Kumatta_ss. All rights reserved.
//

import Foundation

class SwiftTest: NSObject {
    /// 呼び出しのみ
    @objc static func swiftCallTest() {
        NSLog("swiftCallTest OK!")
    }
    /// 引数のみ
    /// - Parameters:
    ///     - val1: 引数1
    @objc static func swiftCallTestArgument(val1: String) {
        NSLog("swiftCallTestArgument OK! Argument:" + val1)
    }

    /// 引数、戻り値あり
    /// - Parameters:
    ///     - val1: 引数1
    /// - Returns:戻り値
    @objc static func swiftCallTestArgumentReturn(val1: String) -> String {
        NSLog("swiftCallTestArgumentReturn OK!")
        return "Return swiftCallTestArgumentReturn Argument:" + val1;
    }
}

外部公開用の「Objective-C++」を作成する

  • 「Command + B」で、Buildする
    ※Swiftのヘッダーファイルを生成させる
  • 初期で作成されている、「Objective-C」のファイルの拡張子を、「m」を、「mm」にする
    ※「Objective-C++」に変更
  • 変更したファイルに、Swiftを呼び出す関数を作成

// Swiftの関数宣言ヘッダー(名称は、「{プロジェクト名}-Swift.h」形式)
#import <SwiftStaticLibrary-Swift.h>

// 外部に公開用の関数宣言
extern "C" {
    void CallTest();
    void CallTestArgument(const char *val1);
    const char* CallTestArgumentReturn(const char *val1);
}

// 呼び出しのみ
void CallTest() {
    NSLog(@"CallTest");
    [SwiftTest swiftCallTest];
}

// 引数のみ
void CallTestArgument(const char *val1) {
    NSLog(@"CallTestArgument");
    [SwiftTest swiftCallTestArgumentWithVal1:@(val1)];
}

// 引数、戻り値あり
const char* CallTestArgumentReturn(const char *val1) {
    NSLog(@"CallTestArgumentReturn");
    NSString *result = [SwiftTest swiftCallTestArgumentReturnWithVal1:@(val1)];

    const char *resultEncodeVal = [result cStringUsingEncoding:NSUTF8StringEncoding];
    char *returnVal = (char*)malloc(strlen(resultEncodeVal) + 1);
    strcpy(returnVal, resultEncodeVal);
    return returnVal;
}

ライブラリの生成

  • ビルドすると「Products」ディレクトリ配下に、「a」ファイルが作成される
    ファイルを選択した状態で、右のメニューの「Indentity andType」→「Full Path」の矢印を押下すると、格納ディレクトリを開きます

Unityで「Sttaic Library」を使用する

ライブラリの配置

  • 格納用ディレクトリを、下記の構成で作成
Assets
 ├─ Efitor
 ├─ Plugins
 | └─ iOS
 └─ Scripts

  • 「Assets/Plugins/iOS」に生成された、「a」ファイルを格納

  • 格納した「a」ファイル選択して、「Inspector」の下記の項目を設定して、「Apply」を押下
項目 
Select platforms for plugin -> Include Platfprms 「iOS」のみにチェック
Platform settings デフォルト

呼び出しクラスの作成

  • 呼び出し確認用のクラスを、「Assets/Scripts」に作成

using System.Runtime.InteropServices;
using UnityEngine;

public class UnityCallTest : MonoBehaviour
{
    [DllImport("__Internal")]
    private static extern void CallTest();

    [DllImport("__Internal")]
    private static extern void CallTestArgument(string val1);

    [DllImport("__Internal")]
    private static extern string CallTestArgumentReturn(string val1);

    // Start is called before the first frame update
    void Start()
    {
        CallTest();

        CallTestArgument("1.Unityからの呼び出しだ!");

        string result = CallTestArgumentReturn("2.Unityからの呼び出しだ!");
        Debug.Log("============================ Unity Result:" + result);
    }

    // Update is called once per frame
    void Update()
    {

    }
}


  • 「Hierarchy」に、任意のGameObjectを作成して、作成したスクリプトをアタッチ

ビルド設定

  • 「Player setting」で、任意の設定をする
    ※今回は下記の赤い部分のみを変更しました

  • 「Assets/Editor」配下に、拡張エディタを作成
    そのままだと、ビルドしたXcodeプロジェクトに、毎回設定をしないといけないので、拡張エディタを作成

using System.IO;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;

public class TestPostProcessBuild
{
    [PostProcessBuild]
    public static void BuildTest(BuildTarget buildTarget, string projectPath)
    {
        // iOSの場合のみ
        if (BuildTarget.iOS == buildTarget)
        {
            string projectFilePath = PBXProject.GetPBXProjectPath(projectPath);
            var proj = new PBXProject();
            proj.ReadFromFile(projectFilePath);
            string target = proj.TargetGuidByName(PBXProject.GetUnityTargetName());


            // BridgingHeaderを作成・設定
            string projSwiftBridgingFile = "Classes/Unity-iPhone-Bridging-Header.h";
            string swiftBridgingFile = Path.Combine(projectPath, projSwiftBridgingFile);
            var fs = File.Create(swiftBridgingFile);
            fs.Close();

            string swiftBridgingFileGuid = proj.AddFile(swiftBridgingFile, projSwiftBridgingFile, PBXSourceTree.Source);
            proj.AddFileToBuild(target, swiftBridgingFileGuid);
            proj.SetBuildProperty(target, "SWIFT_OBJC_BRIDGING_HEADER", projSwiftBridgingFile);

            // Xcodeのビルド設定
            proj.SetBuildProperty(target, "CLANG_ENABLE_MODULES", "YES");
            proj.AddBuildProperty(target, "LD_RUNPATH_SEARCH_PATHS", "$(inherited) @executable_path/Frameworks");
            proj.SetBuildProperty(target, "SWIFT_VERSION", "5.0");
            proj.SetBuildProperty(target, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "YES");
            proj.SetBuildProperty(target, "SWIFT_INSTALL_OBJC_HEADER", "YES");
            proj.SetBuildProperty(target, "SWIFT_PRECOMPILE_BRIDGING_HEADER", "YES");
            proj.SetBuildProperty(target, "SWIFT_OBJC_INTERFACE_HEADER_NAME", "$(PRODUCT_NAME)-Swift.h");

            proj.AddBuildProperty(target, "LIBRARY_SEARCH_PATHS", "/usr/lib/swift/");
            proj.AddFileToBuild(target, proj.AddFile("usr/lib/swift/libswiftFoundation.tbd", "Frameworks/libswiftFoundation.tbd", PBXSourceTree.Sdk));

            proj.WriteToFile(projectFilePath);
        }
    }
}

ビルドして実機で実行

  • ログに実行結果が出力されると思います

あとがき

今回、Swiftで作成されたライブラリを、Unityで呼び出す必要があり、
「Objective-C」、「Swift」を触った事ない状態から、色々試した結果です。

ビルドのプロパティについては、「Xcode」でネイティブアプリとして、
「Objective-C」と、「Objective-C + Swift」の二つを作成、解析して、必要な設定を割り出した物になります。

問題や追加の説明が欲しいなどが、あったらコメントなどで、教えていただけたら嬉しいです。

5
9
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
5
9