Journey in “Electrino”

I was wondering on GitHub one day when I saw this project called Electrino which happened to be rising up in the trending page. I decided to take a quick look at it, and discovered it was a project that aimed to use native web browser frameworks, rather than bundling a framework within the application (i.e. Electron). I thought “Hey this would be cool to do some stuff with”, and proceeded to submit a PR on adding a basic feature.

I then thought that creating seperate “module” files for each module would decrease app size as developers could pick and choose which modules they actually needed. Someone replied saying that we should try and have a “multiplatform codebase”, and we got talking in one of the issues.

IMO, I think having something like this project on multiple platforms with the same codebase would be very difficult. The main reasons are that the frameworks treat exposing objects/functions differently, and trying to support all of them in one application would make the application size bigger.

C++ mixing with Objective-C

I tried playing around with the idea of using C++ for creating the modules. I created a basic class which contains a string, and began creating a method to “convert” the C++ object to an Objective-C object. I did this by using the Objective-C Runtime. I looked at what existing objects looked like in terms of how the methods were exposed to the JSExport protocol, and tried to replicate it.

One issue that I came across was how none of the methods were actually accessible in JavaScript, including properties. After changing little things and searching for a while, I came across this gist which showed the issue I was facing. Apparently, it was due to how the compiler adds a full method signature to the protocol. JSC relies on this to ensure that the correct Objective-C types are handled correctly. Since the compiler does this, everyone thought that it wouldn’t be possible to do this at runtime. But I managed to “fix” this issue.

If we look at the Objective-C runtime source and at _protocol_getMethodTypeEncoding, we notice that in the _nolock variant, it accesses the extendedMethodTypes property. I try look for that property on the normal Protocol object, but I could’t find anything. I noticed that the Protocol type argument is actually converted to the protocol_t type when the function is called:

#define newprotocol(p) ((protocol_t *)p)
...
const char * _protocol_getMethodTypeEncoding(Protocol *proto_gen, SEL sel, BOOL isRequiredMethod, BOOL isInstanceMethod) {
    protocol_t *proto = newprotocol(proto_gen);
...

I copied the headers of protocol_t, typecasted my runtime-generated protocol, set a breakpoint just after it, and looked at what it stored. I wasn’t surprised when I saw that the extendedMethodTypes object was NULL. I malloced some memory, created the appropriate method signatures, and tried running the project. Surprisingly it worked!

You can view the source of the whole ‘converter’ here: https://github.com/ninjaprawn/electrino/blob/cplusplus/Electrino/Electrino/ENOCPPExposer.mm

Just a note: you have to disable ARC on that particular file. This is because ARC decides to remove our memory, and therefore the signatures won’t be correct when you attempt to get them (in some edge cases, but it’s best to be safe).

Trying out C#

After thinking for a while, I thought that maybe we could try writing the app in C# with Xamarin.Mac in Visual Studio 2017 for Mac. Mono (the library) pushes a bare-bones application size to about 40mb. This seemed pretty good, and I decided to pursue trying writing Electrino in C#.

While trying to expose a C# class to JSC with the JSExport protocol, I discovered some interesting things. Firstly, exposing methods is very easy. You just add the [Export("")] attribute(?) and it works! My main problem was trying to expose a property. I tried using the Export attribute, but it didn’t want to work. I would have had to write the getter and setter for each property, as well as have a “private” variable to actually store the contents. After a bit of research, I discovered the [ExportAttribute("")] attribute, which automatically handles the getter and setter methods.

During the time of playing with Xamarin, I had realised how hard it would be to have multi-platform code due to the layout of different frameworks, etc. The chances of that happening are pretty low.

Hope you enjoyed reading some interesting stuff about all of this :) Feel free to ask questions

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.