web-dev-qa-db-fra.com

Comment construire le plugin Unity3d pour iOS

J'ai une toute petite bibliothèque Objective-C construite pour iOS et je veux l'exporter vers Unity. Je comprends le processus de base de l'écriture d'un wrapper csharp qui rassemble toutes les invocations à la bibliothèque native, mais je ne sais absolument pas par où commencer. Quelqu'un pourrait-il expliquer étape par étape comment créer un package d'unité avec ma bibliothèque afin que je puisse également le distribuer à d'autres développeurs.

La documentation Unity3d est assez brève et n'explique rien.

Merci.

61
highmaintenance

D'accord, après avoir joué quelques jours avec Unity3d sur Mac, j'ai finalement compris. Tout le code de ce guide est factice. J'ai écrit ces trucs en 15 minutes environ, alors ne soyez pas dérangé par les erreurs et les fautes de frappe.

1) Ouvrez Unity, créez un nouveau projet (Fichier -> Nouveau projet) et enregistrez-le quelque part

2) Lorsque le projet est généré, il a la structure suivante:

  • ProjectName/Assets (C'est ce dont vous avez besoin)
  • ProjectName/Library (Peu importe ce qu'il y a)
  • ProjectName/ProjectSettings (Vous ne vous en souciez pas)
  • ProjectName/ProjectName.sln (Projet MonoDevelop)

3) Allez dans ProjectName/Assets Et créez les dossiers suivants: Plugins/iOS, Donc à la fin vous aurez une structure de dossiers comme celle-ci: ProjectName/Assets/Plugins/iOS

4) Placez votre fichier de bibliothèque compilé (.a) et les en-têtes nécessaires dans ProjectName/Assets/Plugins/iOS Ou copiez-y le code source de votre bibliothèque (.mm, .h, .m, etc.). Rappelez-vous, normalement, vous ne pouvez accéder aux fonctions C qu'à partir de C #, vous devrez donc envelopper vos trucs Objective-C dans du code C d'une manière ou d'une autre, dans mon cas, tous les objets Objective-C ont été implémentés sous la forme de Singleton, donc ce n'était pas '' t difficile de créer un wrapper de style C, par exemple:

CWrapper.h :

extern "C" void MySDKFooBarCFunction();

CWrapper.mm

#import "CWrapper.h"
#import "MyObjectiveCLibrary.h" // your actual iOS library header

void MySDKFooBarCFunction() {
    [MyObjectiveCLibrary doSomeStuff];
}

5) Ensuite, allez dans ProjectName/Assets Et créez un dossier pour les classes d'encapsuleurs CSharp, appelez-le comme vous voulez, par exemple: ProjectName/Assets/MySDK

6) À l'intérieur du dossier MySDK, créez le fichier MySDK.cs, l'exemple factice du wrapper C # ressemblerait à ceci:

using UnityEngine;
using System;
using System.Runtime.InteropServices;

public class MySDK
{
    // import a single C-function from our plugin
    [DllImport ("__Internal")]
    private static extern void MySDKFooBarCFunction();

    // wrap imported C-function to C# method
    public static void FooBarCFunction() {
        // it won't work in Editor, so don't run it there
        if(Application.platform != RuntimePlatform.OSXEditor) {
            MySDKFooBarCFunction();
        }
    }
}

7) Créez un script Shell pour emballer ces éléments dans .unitypackage Et placez-le à côté de votre dossier de projet (pas à l'intérieur). Ajustez les variables EXPORT_PATH Et PROJECT_PATH Dans le script selon vos besoins.

#!/bin/sh

WORKDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
UNITY_BIN="/Applications/Unity/Unity.app/Contents/MacOS/Unity"
EXPORT_PATH="${WORKDIR}/ProjectName.unitypackage"
PROJECT_PATH="${WORKDIR}/ProjectName"
ASSETS_PATH="Assets"

$UNITY_BIN -batchmode -quit \
-logFile export.log \
-projectPath $PROJECT_PATH \
-exportPackage $ASSETS_PATH $EXPORT_PATH

8) Exécutez le script bash créé pour obtenir la construction de votre package. Tous les éléments des actifs seront inclus dans le projet XCode pour votre projet Unity lorsque vous le générez via Fichier -> Paramètres de construction dans l'éditeur Unity. Vous pouvez utiliser le package généré pour distribuer votre code à d'autres développeurs afin qu'ils puissent simplement inclure votre bibliothèque dans leurs projets Unity en double-cliquant sur le fichier du package.

N'oubliez pas d'arrêter Unity Editor lorsque vous exécutez ce script, sinon il peut échouer à construire un paquet.

Si vous avez des problèmes et que le paquet ne s'affiche pas, ce script affiche toujours le journal dans export.log

Les étapes suivantes n'ont de sens que si vous souhaitez créer un projet d'unité de démonstration pour votre bibliothèque (bon pour tester au moins)

9) Vous pouvez placer le projet Unity créé (ProjectName.unity) dans Assets/MySDKDemo Afin d'avoir une démo à l'intérieur de votre package.

10) Créez un script simple pour votre scène Demo Unity3d dans Assets/MySDKDemo/MySDKDemo.cs, Par exemple:

using UnityEngine;
using System;
using System.Collections;

public class MySDKDemo : MonoBehaviour
{   
    private GUIStyle labelStyle = new GUIStyle();
    private float centerX = Screen.width / 2;

    // Use this for initialization
    void Start ()
    {   
        labelStyle.fontSize = 24;
        labelStyle.normal.textColor = Color.black;
        labelStyle.alignment = TextAnchor.MiddleCenter;
    }

    void OnGUI ()
    {
        GUI.Label(new Rect(centerX - 200, 20, 400, 35), "MySDK Demo", labelStyle);
        if (GUI.Button(new Rect(centerX - 75, 80, 150, 35), "DoStuff"))
        {
            MySDK.FooBarCFunction();
        }
    }

}

11) Accédez à l'éditeur Unity. Trouvez la "Caméra principale" dans la barre latérale gauche dans l'éditeur Unity, sélectionnez-la et en bas du panneau Inspecteur (barre latérale droite) cliquez sur Ajouter un composant, sélectionnez Scripts -> Script MySDKDemo

12) Générez le projet XCode et exécutez-le sur l'appareil.

Peu de notes

1) Les plugins ne fonctionnent pas dans Unity Editor, simplement parce qu'ils ne sont pas compilés en temps réel, enfin, pas sûr mais probablement jusqu'à ce que vous utilisiez C # dans vos plugins, probablement les choses C # sont liées immédiatement et fonctionnent dans l'environnement Editor.

2) Cet article ne couvre pas le marshaling, ni la gestion des données/mémoire entre le code géré <-> natif, car il est très bien documenté.

Interopérer avec les bibliothèques natives @ projet Mono

3) Les rappels de C # à C peuvent être passés en utilisant des délégués C #, du côté C vous utilisez des déclarations de fonctions standard, du côté C # vous déclarez des délégués avec la même signature. Il semble que les booléens, les entiers et les chaînes (C: char *) soient parfaitement organisés (je ne parle pas de la politique de gestion de la mémoire et de qui est responsable de libérer de la mémoire ou des politiques de valeur de retour).

Cependant, cela ne fonctionnera pas sur les versions iOS prêtes à l'emploi en raison des limitations de la plate-forme, mais les rappels C # -to-C peuvent toujours être implémentés à l'aide de MonoPInvokeCallbackAttribute, des liens utiles sur ce sujet:

En fait, dans Unity 4, AOT.MonoPInvokeCallbackAttribute Est déjà implémenté, il est limité aux délégués statiques qui peuvent être passés au code non managé, mais encore mieux que rien.

4) Il existe un moyen d'obtenir Unity RootViewController en utilisant la fonction UnityGetGLViewController. Déclarez simplement cette fonction dans votre fichier d'implémentation, c'est-à-dire:

extern UIViewController *UnityGetGLViewController();

Et utilisez UnityGetGLViewController() chaque fois que vous avez besoin d'obtenir un accès à RootViewController.

5) Il y a beaucoup plus de magie et de laideur dans les détails, gardez vos interfaces C aussi simples que possible, sinon le marshaling peut devenir votre cauchemar et gardez à l'esprit que le géré-non géré est généralement coûteux.

6) Vous utilisez certainement certains frameworks dans votre code natif et vous ne voulez pas de problèmes avec l'éditeur de liens. Par exemple, si vous utilisez le trousseau dans votre bibliothèque, vous devez inclure Security.framework dans le projet Xcode.

Je suggère d'essayer XUPorter , cela aide Unity à intégrer toutes les dépendances supplémentaires dans le projet Xcode.

Bonne chance!

83
highmaintenance

J'ai écrit un article sur la façon de créer un plugin iOS pour l'unité. Vous pouvez le vérifier ici . J'espère que ça aide. Merci.

5
Ashwani K