Choosing between declares vs plugin for wrapping a SDK

Hi all,

as I would like to embed and expose Couchbase Lite (https://www.couchbase.com/products/lite), a embeddable NoSQL Multiplatform database into a Xojo application, I have to decide if it’s better to build a plugin wrapping its SDK (available in Swift, Objective-C, Java, C#) or to use declare to expose some of its APIs.

Couchbase Lite can also be used through a REST APIs, so in principle I could just need to wrap a few classes/methods to start the listening daemon and then use HTTP/JSON to interact with it.

In particular I am trying to wrap this Objective-C calls at the moment:

CBLManager* manager = [CBLManager sharedInstance];
self.listener = [[CBLListener alloc] initWithManager:manager port:55000];
self.listener.passwords = @{@"hello": @"pw123"};
[listener start:nil];

(from Objective-C | Couchbase Docs Archive)

I am starting with macOS at the moment, and I was able to embed the .framework files into my app bundle.

In the above example I need to get access to the CBLManager class, but as far as I have understood Xojo Declare maps just methods(selectors)/functions.

So should I go with plugin even for this simple experiment?
Are there any examples of wrapping other Objective-C non-apple frameworks I can look at?

thank you

If your going to wrap it in plugin then you should take their C SDK, since Objective C would only tie you into single platform and likely add extra overhead.

Unfortunately, for this specific library, I cannot use their C (cross-platform) SDK. The reason is that they completely changed their architecture from Couchbase Lite 1.x to Couchbase Lite > 2.x. For example in 2.x peer-to-peer replication is not available anymore in the community version, and they switched from a CouchDB lite protocol to a proprietary one.
So I am currently forced to use their old 1.x version, that works quite well and it’s CouchDB compliant.

So the plan would be to use their Objective-C SDK for macOS/iOS and trying with the C# SDK for Windows/Linux, even if this path would be more complicated.

The simplest path would be just to start the listening daemon, and than talk to it via the HTTP and REST APIs. So I just need to wrap very few calls.
What about declares in this case? Could they be used to init the listener, as in the above code?

thanks

You will need to get the class reference with NSClassFromString, then you should be able to create it. Try the following (typed into the web, untested). To setup the dictionary there are other declares available on the forum that I can try to find later if needed. But this should give you a start on how it would work

const YOUR_FRAMEWORK =  "@executable_path/../Frameworks/YourFramework.framework"

declare function sharedInstance lib YOUR_FRAMEWORK selector "sharedInstance" (clsRef as Ptr) as Ptr
declare function NSClassFromString lib "Foundation.framework" (clsName as CFStringRef) as Ptr
declare function alloc lib "Foundation.framework" selector "alloc" (clsRef as Ptr) as Ptr
declare function initWithManagerAndPort lib YOUR_FRAMEWORK selector "initWithManager:port:" (handle as Ptr, manager as Ptr, port as Interger) as Ptr

var manager as ptr = sharedInstance(NSClassFromString("CBLManager"))
var listener as ptr = initWithManagerAndPort(alloc(NSClassFromString("CBLListener")), manager, 55000)

2 Likes