iOS Objective C plugin linker error

I’m trying to get a simple objective C iOS plugin working and am having problems with linker errors. There’s various discussions about this but no clear simple working samples that I can find. See my code below. I’m getting the following error:

Undefined symbols for architecture armv7:
“__getO2”, referenced from:
RegisterMonoModules() in RegisterMonoModules.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Here’s my code. (Note that it’s the .h and .m files that don’t work. If I replace the .h and .m with the .mm file it runs perfectly):

Assets/Scripts/CubeLevitate.cs:

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

public class CubeLevitate : MonoBehaviour {

[DllImport ("__Internal")]
private static extern float _getO2();

	private float o2Val;

	void Start () {
		o2Val = getO2();
		Debug.Log("Return Float = " + o2Val);
	}
	
	void Update () {
	}
	
	float getO2()
	{
		if (Application.platform == RuntimePlatform.IPhonePlayer)
			return _getO2();
		else
			return 95f;
	}
}

Assets/Plugins/iOS/O2Plugin.h:

#import <Foundation/Foundation.h>

@interface O2Plugin : NSObject

{
    float _getO2;
}

@end

Assets/Plugins/iOS/O2Plugin.m:

#import "O2Plugin.h"

@implementation O2Plugin

-(float)_getO2
{
    return 98.2f;
}

@end

Assets/Plugins/iOS/O2Plugin.mm (this works when I replace the .h and .m above with this C++ code, but I want to use Objective C directly. Do I really have to call the obj C from C++??

extern "C"
{

	float _getO2(void)
	{
		return 98.2f;
	}
    
    bool _initializeBT(void)
    {
        
    }
}

Got it working!

  1. Now calling from C++
  2. Changed extension from .m to .mm to accommodate C++ code
  3. Now instantiating the class. Doh!

Here’s the fixed code in Assets/Plugins/iOS/O2Plugin.mm:

#import "O2Plugin.h"

@implementation O2Plugin

static O2Plugin* _O2PluginSingleton = nil;

+ (O2Plugin *) O2PluginSingleton
{
	@synchronized([O2Plugin class])
	{
		if (!_O2PluginSingleton)
		{
			_O2PluginSingleton = [[self alloc] init];
		}
		return _O2PluginSingleton;
	}
	return nil;
}

-(float) _getO2
{
    return 98.2f;
}

@end

extern "C"
{
    float PGgetO2()
    {
        return [[O2Plugin O2PluginSingleton] _getO2];
    }
    

}

Do I really have to call the obj C from C++??

Yes. The documentation is pretty clear on this. (You think that’s annoying? Wait until you’ll need to pass complex structures to and forth and P/Invoke…)

As for samples, take a look at existing plugins, such as Facebook’s.

EDIT: the simple “Yes” given at the beginning is technically wrong (oops). You don’t have to use C++ for this, though Objective-C++ is natural for this purpose (as Unity’s own files are .mm). You could use Objective C, but as Objective C method calls are actually message passes (which call the C function objc_msgSend behind the scenes), your C/C# interface still has to go through vanilla C functions, which can then use all the nice runtime Objective C facilities. (Technically, since Objective C is a superset of C, you can say that C# is calling Objective C directly! But that’s misleading, as only functions can be invoked this way, not methods.)

Still, apart from the use of the extern keyword, this is mostly an academic point, since using C doesn’t make your life any user.

And yes, the docs are not too clear, but they’re still correct, in their own way.