Using the Xcode Simulator with a Unity 3 Native iOS Plug-In

As you saw in “Building a Unity 3 Application with Native Plugin for iOS” we can create a plug in for native code in iOS with Unity 3. The problem is that by default you can’t test it on the Simulator of Xcode. May be it doesn’t make too much sense to use the Simulator to try a Unity 3 application as the performance in 3D applications may vary significantly from the real device, but if you still don’t own a iOS device you can save the day with this.

Inside the Xcode project in the “Libraries/RegisterMonoModules.cpp” file you can see how the calls to the functions registered as “extern” are inside a block that is only processed it the target IS NOT the Simulator (#if !(TARGET_IPHONE_SIMULATOR)). So we have to pull out from that block both the definition of the function that registers our functions (mono_dl_register_symbol) and our functions them self. Look at the bold lines in the following code:

#include "RegisterMonoModules.h"

extern bool gEnableGyroscope;

extern "C"
{
	typedef void* gpointer;
	typedef int gboolean;
#if !(TARGET_IPHONE_SIMULATOR)
	const char*			UnityIPhoneRuntimeVersion = "3.5.0f5";

	extern int 			mono_ficall_flag;
	void				mono_aot_register_module(gpointer *aot_info);
	extern gboolean		mono_aot_only;
	extern gpointer*	mono_aot_module_Assembly_CSharp_firstpass_info; // Assembly-CSharp-firstpass.dll
	extern gpointer*	mono_aot_module_UnityEngine_info; // UnityEngine.dll
	extern gpointer*	mono_aot_module_mscorlib_info; // mscorlib.dll
#endif // !(TARGET_IPHONE_SIMULATOR)
	void				mono_dl_register_symbol (const char* name, void *addr);
	void	_PassStructFromObjCToUnity();
	void	_Test();
}
void RegisterMonoModules()
{
    gEnableGyroscope = false;
#if !(TARGET_IPHONE_SIMULATOR)
	mono_aot_only = true;
	mono_ficall_flag = false;
	mono_aot_register_module(mono_aot_module_Assembly_CSharp_firstpass_info);
	mono_aot_register_module(mono_aot_module_UnityEngine_info);
	mono_aot_register_module(mono_aot_module_mscorlib_info);


#endif // !(TARGET_IPHONE_SIMULATOR)
	mono_dl_register_symbol("_PassStructFromObjCToUnity", (void*)&_PassStructFromObjCToUnity);
	mono_dl_register_symbol("_HaveObjCDoSomething", (void*)&_HaveObjCDoSomething);
}

We can modify the “PostprocessBuildPlayerscript so we don’t have to do this by hand every time we change our code. Some awk magic will do the trick (not very fancy but it works…):

#!/bin/bash
cp -fR ./iOS Build/Libraries ~/Documents/Xcode/my-project/
cp -fR ./iOS Build/Data ~/Documents/Xcode/my-project/
rm file.tmp
awk '
{
  if ($0 == "#if !(TARGET_IPHONE_SIMULATOR)" && NR == 9) {
    getline var1;
    getline var2;
    printf "%sn%sn%sn", var2, $0, var1 >> "file.tmp"
  } else if (NR == 32) {
     printf "#endif // !(TARGET_IPHONE_SIMULATOR)" >> "file.tmp"
     printf "n%sn", $0 >> "file.tmp"
  } else if ($0 == "#endif // !(TARGET_IPHONE_SIMULATOR)" && NR > 32) {
  } else {
    print $0 >> "file.tmp"
  }
}' ~/Documents/Xcode/my-project/Libraries/RegisterMonoModules.cpp
mv file.tmp ~/Documents/Xcode/my-project/Libraries/RegisterMonoModules.cpp

It is probably a good idea to deactivate “Dead Code Stripping” option in the Xcode project (located in “Linking” from the “Build Settings”) as Xcode might think our extern defined functions will never be called as they are called only from Unity and not from Xcode.

Source: http://answers.unity3d.com/questions/49945/gamekit-linker-failure.html?sort=oldest

You might also like

Building a Unity 3 Application with Native Plugin for iOS
Create a Unity project. Go to “File->Build Settings”, select the iOS platform and then “Player...

Building a Unity 3 Application with Native Plugin for iOS
Create a Unity project. Go to “File->Build Settings”, select the iOS platform and then “Player...

Building a Unity 3 Application with Native Plugin for iOS
Create a Unity project. Go to “File->Build Settings”, select the iOS platform and then “Player...

Avoid Android File Transfer starting automatically in Mac OS X after Android device plugin to USB port
"Android File Transfer" application starts automatically in Mac OS X when you plug your Android device...

Leave a comment ?

15 Comments.

  1. Thank you very much!!! You realy help me!

  2. Thank you very much!!! You realy help me too!

  3. Thanks. Good find. I’ve augmented your script a little to use the path provided by Unity instead of hardcoded path, and also to be a little more resilient to changes in the file format. Works (for me) for Unity 4.3.

    #!/bin/bash
    rm file.tmp
    awk '
    {
      if ($0 == "#if !(TARGET_IPHONE_SIMULATOR)" && NR == 9) {
        getline var1;
        getline var2;
        printf "%s\n%s\n%s\n", var2, $0, var1 >> "file.tmp"
      } else if (length(newend)==0 && $0 ~ /mono_dl_register_symbol/) {
         newend=NR
         printf "#endif // !(TARGET_IPHONE_SIMULATOR)" >> "file.tmp"
         printf "\n%s\n", $0 >> "file.tmp"
      } else if (length(newend)>0 && $0 == "#endif // !(TARGET_IPHONE_SIMULATOR)") {
      } else {
        print $0 >> "file.tmp"
      }
    }' "$1"/Libraries/RegisterMonoModules.cpp
    mv file.tmp "$1"/Libraries/RegisterMonoModules.cpp
  4. Can you tell me please where to find this PostprocessBuildPlayer script? I found file with the same name only in UnityProject/Assets/Editor/ but it’s executed by /usr/bin/perl

    • You can read in Building a Unity 3 Application with Native Plugin for iOS:

      “… create a PostprocessBuildPlayer script (be careful, this file must have execution permissions) inside “Assets/Editor” (thus we have to create a folder called Editor inside the “Project” view and copy there the script) with the same content as before so the files will be copied automatically to our Xcode project every time we do a “Build” in Unity. The PostprocessBuildPlayer scripts can be shell script or Perl script.”

  5. Jeremy, enekochan:
    thank you for the great article and the update to Unity 4.3
    I am not successful in running in the simulator. Can you please elaborate/advice?
    Steps I did:
    – created “Editor” folder inside the “Assets” folder.
    – created a file called PostprocessBuildPlayer.sh
    – pasted inside such .sh file what Jeremy contributed (I am using Unity 4.3)
    – went to terminal and ran: sudo chmod +x PostprocessBuildPlayer.sh

    After Unity “build and run”, the RegisterMonoModules.cpp file looks like before adding the shell script to Editor, and the simulator still gives EntryPointNotFoundException

    • I don’t know why it doesn’t work. Try my script instead but remember changing the folder “~/Documents/Xcode/my-project/” to your project. Or may be it is because you created the Editor folder outside Unity. In this post I wrote “create a folder called Editor inside the “Project” view and copy there the script”, may be it’s that.

  6. enekochan, I wish to add that your way of running native plugins in the simulator works brilliantly, when I do, manually, the steps that you explained (I can’t automate such steps with Jerome’s RegisterMonoModules script).
    Thank you very much for the great article.
    Still, I hope that you or Jerome can please elaborate/add details on how to make PostprocessBuildPlayer automate the amendments for Unity 4.3 builds. Maybe the script file suffix should not be .sh, maybe the execution rights should be added differently than I explained in the previous post… Thanks in advance!

  7. (Opss! sorry, my previous post was written while you were posting your reply. So I did not read your reply.)
    Thanks for the prompt reply!
    I did save Jeremy’s PostprocessBuildPlayer script inside the UnityProject/Assets/Editor.
    I did not change “~/Documents/Xcode/my-project/” because I used Jerome’s script because I am running Unity4.3, not Unity3 (your script is for Unity3, I understand?).
    In any case, thank you very much! Amazing articles, I hope that you will write more such articles on Unity, on plugins, or on the simulator, etc.

  8. A quick comment to say that it all works for me now with Unity v4.3.3:
    Xcode Simulator with a Native iOS Plug-In. All in smooth “Build and Run” using PostprocessBuildPlayer

    The mistakes I did before:
    (1) PostprocessBuildPlayer should have no suffix, and
    (2) even though I was setting the execution with chmod +x, somehow Unity was not running the script. Maybe, it was because PostprocessBuildPlayer.meta was corrupted (in fact, after I deleted the .meta, “Build and Run” worked in the simulator).
    Thanks again for this super cool article and its comments!

    • I’m glad it works now 🙂 Great tip deleting .meta and “Build and Run” again!

  9. Really thanks! oMG

Leave a Comment