Help us understand the problem. What is going on with this article?

Unity Native Pluginの作り方(iOS編)

概要

iOS向けに開発したSDKをUnityアプリに対応させる場合、プラグインを作ってSDKとUnityアプリの橋渡しをしてやる必要があります。本記事ではUnity側のコードをC#、プラグイン側のコードをObjective-C++ (.mm)で記載するケースについて紹介します。

補足

iOS, Android共通で使用するコードについては共通編を参考にして下さい。

プラグイン側

まずはプラグイン側のコードの一例です。Sample, SampleDelegateといったクラスはSDK側で定義されており、それらのメソッドにUnity側からアクセスするために各Wrapperメソッドを実装しています。このコードはUnityプロジェクトのAssets/Plugins/iOSディレクトリ配下に入れておくと良いでしょう。

SamplePlugin.mm
#include <stdio.h>
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <SampleSDK/SampleSDK.h>
#import <SapleSDK/SampleSDK-Swift.h>

#define kSample_DefaultCallbackGameObjectName @"Main Camera"

@interface SamplePlugin: NSObject
@end

SamplePlugin *__unityClientSharedInstance;

@interface SamplePlugin() <SampleDelegate>
@property(nonatomic, strong) NSString *callbackGameObjectName;

- (void)invokeUnityGameObjectMethod:(NSString *)methodName message:(NSString *)message;

@end

@implementation SamplePlugin

+ (SamplePlugin *)sharedInstance {
    if (!__unityClientSharedInstance) {
        __unityClientSharedInstance = [[SamplePlugin alloc] init];
    }

    return __unityClientSharedInstance;
}

# pragma mark - SampleDelegate

- (void)didStatusChange:(enum SampleStatus)status {
    NSString *statusStr = [NSString stringWithFormat:@"%ld", status];
    [self invokeUnityGameObjectMethod:@"_Sample_didStatusChange" message:statusStr];
}

# pragma mark - Private

- (void)invokeUnityGameObjectMethod:(NSString *)methodName message:(NSString *)message {
    NSString *gameObject = self.callbackGameObjectName == nil ?
    kSample_DefaultCallbackGameObjectName : self.callbackGameObjectName;

    const char *gameObjectStr = [gameObject cStringUsingEncoding:NSUTF8StringEncoding];
    const char *methodNameStr = [methodName cStringUsingEncoding:NSUTF8StringEncoding];
    const char *messageStr = [message cStringUsingEncoding:NSUTF8StringEncoding];

    UnitySendMessage(gameObjectStr, methodNameStr, messageStr);
}

@end

// Declare each wrapper methods
extern "C" {
    void SPStart(const char *sampleCode);
    void SPDoSomething();
    int SPGetStatus();
    int SPGetScore();
    bool SPIsAvailable();
    const char* SPGetSomeText();
}

extern UIViewController* UnityGetGLViewController();
extern void UnitySendMessage(const char* obje, const char* method, const char* msg);

void SPSetCallbackGameObjectName(char *gameObjectName) {
    NSString *name = [NSString stringWithCString:gameObjectName encoding:NSUTF8StringEncoding];
    SamplePlugin *client = [SamplePlugin sharedInstance];
    client.callbackGameObjectName = name;
}

void SPStart(const char *sampleCode) {
    NSString *sampleCodeStr = [NSString stringWithCString:sampleCode encoding:NSUTF8StringEncoding];

    [[Sample sharedInstance] startWithSampleCode: sampleCodeStr];
    [Sample sharedInstance].delegate = [SamplePlugin sharedInstance];
}

void SPDoSomething() {
    [[Sample sharedInstance] doSomething];
}

int SPGetStatus() {
    return [[Sample sharedInstance] getStatus];
}

int SPGetScore() {
    return [[Sample sharedInstance] getScore];
}

bool SPIsAvailable() {
    return [[Sample sharedInstance] isAvailable];
}

const char* SPGetSomeText() {
    NSString *textStr = [[Sample sharedInstance] getSomeText];
    const char *textChar = [textStr cStringUsingEncoding:NSUTF8StringEncoding];

    return textChar ? strdup(textChar) : NULL;
}

Unity側

Sample_iOS.cs
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;

#if UNITY_IOS

public class Sample_iOS : ISample {
    private Sample sampleGameObject;
    private SampleEventListener listener;

    [DllImport ("__Internal")]
    protected static extern void SPSetCallbackGameObjectName(string gameObjectName);

    public Sample_iOS(Sample sampleParent) {
        sampleGameObject = sampleParent;

        if (sampleParent.iosAppCode != null) {
            Start(null);
        }

        CreateListenerObject();
    }

    private void CreateListenerObject() {
        listener = sampleGameObject.gameObject.AddComponent<SampleEventListener>();
        listener.SetNativeParent(this);

        SPSetCallbackGameObjectName(sampleGameObject.gameObject.name);
    }

    [DllImport("__Internal")]
    private static extern void SPStart(string sampleCode);
    public void Start(string sampleCode) {
        if (sampleGameObject.iosSampleCode != null) {
            SPStart(sampleGameObject.iosSampleCode);
        } else if (sampleCode != null) {
            SPStart(sampleCode);
        }
    }

    [DllImport("__Internal")]
    private static extern void SPDoSomething();
    public void DoSomething() {
        SPDoSomething();
    }

    [DllImport("__Internal")]
    private static extern int SPGetStatus();
    public SampleStatus GetStatus() {
        return (SampleStatus)SPGetStatus();
    }

    [DllImport("__Internal")]
    private static extern int SPGetScore();
    public int GetScore() {
        return SPGetScore();
    }

    [DllImport("__Internal")]
    private static extern bool SPIsAvailable();
    public bool IsAvailable() {
        return SPIsAvailable();
    }

    [DllImport("__Internal")]
    private static extern string SPGetSomeText();
    public string GetSomeText() {
        return SPGetSomeText();
    }
}

#endif

参考

https://docs.unity3d.com/ja/540/Manual/PluginsForIOS.html

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away