Exposing an Obj-C const NSString via a MonoTouch b

2019-07-30 02:45发布

问题:

I've got a working MonoTouch binding for ZBar up and running, but am having troubles exposing a constant NSString that the Obj-C library defines for use as a Key in an NSDictionary:

inside ZBarReaderController.h:

extern NSString* const ZBarReaderControllerResults;  

I first tried via the actual MonoTouch binding as documented here:

[Static]
interface ZBarSDK
{
    [Field ("ZBarReaderControllerResults")]
    NSString BarcodeResultsKey { get; }
}

Attempting to build the project containing this gave these errors from btouch:

Unhandled Exception: System.ArgumentOutOfRangeException: Argument is out of range.
Parameter name: startIndex
at System.String.Substring (Int32 startIndex) [0x00000] in :0
at Generator.Generate (System.Type type) [0x00000] in :0
at Generator.Go () [0x00000] in :0
at BindingTouch.Main (System.String[] args) [0x00000] in :0
[ERROR] FATAL UNHANDLED EXCEPTION: System.ArgumentOutOfRangeException: Argument is out of range.
Parameter name: startIndex
at System.String.Substring (Int32 startIndex) [0x00000] in :0
at Generator.Generate (System.Type type) [0x00000] in :0
at Generator.Go () [0x00000] in :0
at BindingTouch.Main (System.String[] args) [0x00000] in :0

I next attempted to manually call into the code as suggested in this other SO answer.

public static NSString BarcodeResultsKey
{
    get
    {
        var libHandle = Dlfcn.dlopen("libzbar.a",0);
        // I also tried this with "__Internal", rather than "libzbar.a"
        return Dlfcn.GetStringConstant(libHandle, "ZBarReaderControllerResults");
    }
}

It builds and executes fine, but just returns an empty string (as the Dlfcn.GetStringConstant documents it will do if it fails to link).

So, anyone else accessed const strings from a 3rd party Obj-C library?

回答1:

The generator, btouch, had a limitation (before 5.2.11) for [Field] bindings that requires the namespace to start with MonoTouch..

A quick workaround for this issue is to rename the namespaces from ZBar to MonoTouch.ZBar and the binding definitions will build correctly.

Since iOS applications must link with static libraries (.a) for libraries that are included with an application it's also required to supply a library name "__Internal" in the bindings as described in the documentation.

[Static]
interface ZBarSDK {
    [Field ("ZBarReaderControllerResults", "__Internal")]
    NSString BarcodeResultsKey { get; }
}

There was also a compilation issue (on the generated code) which required some manual adjustment for the library (i.e. you can use null instead of the library name since it's linked inside the main app). This is also fixed in the MonoTouch 5.2.11 release.

With the workarounds (or MonoTouch 5.2.11) and the __Internal change you should be able to use [Field] inside your bindings.