Creating Common Class Library for iOS and Android

Hello,

I’m a bit new to silver and want some clarifications. What I’m trying to do is create a class library that has some logic to make network calls to backend so that I can share it between iOS and Android. I’d like to use this class library natively in Xcode and Android studio where the iOS and Android teams are creating individual apps. Is this possible using Silver?

Thank you.

2 Likes

It’s possible, yes. It’s a (slight) bit outside of how you’d normally do this with Silver/Elements though, but doable.

The main notch for Silver is that you’d use it for your iOS and Android app as well. This way, you could just create a Shared Project with all thecae you wanna share across platforms, and be done.

For what you need, the setup will be slight bit different, but not much. Essentially, you’d create an Android library project, and an iOS static library project in Silver. You’d then create a Shared Project for your shared code, and have both libraries reference that.The compiled library would then be usable from both Xcode and your Android project, respectively.

Check out http://docs.elementscompiler.com/Projects/SharedProjects/ for more on Shared Projects.

Awesome! So do I put the network code in the shared project or just data structures? If I put the network code into the shared project will the Elements compiler transpile the swift network code to use the android networking libraries? I’m slightly confused…

Put in the shared project whatever source files you want to share (whether completely or with #if java/#if cocoa.); but in the individual projects any code files that are specific to one platform or the other.

the shared project is essentially just a placeholder, Elements will compile each of the two “real” projects as if it contained the combined set of files.

obviously any code you share will need to be cross-platform. platform-specific code you’ll want to write twice, and expose with the same API. does that make sense?

hmm so if I understand right, I won’t be able to write any “shared networking” code. So in the iOS project, I’ll use NSURLSession and in Android I’ll use HttpClient. If that is the case, then there is no benefit for me to use Silver and Elements as the iOS and Android teams can write it themselves using swift and java. Am I getting it right? What I want to do is write an implementation once that is unified across both the platforms.

Besides that’s not trivial, It’s possible to create unified Swift wrapper for native libraries. There’s a ModernHttpClient project which does that for C#.

right. The benefit only comes in when there code that builds ON TOP of your “shared network code” can be shared too. Then you’d write two sets of network code abstractions (or use Sugar’s), one for iOS and one for Android, but the code on top (e.g. the code that decides where to connect to and what to do with the data) would then be shared.

@rudyryk @mh so what you guys are suggesting is that I write the ‘n’ sets of platform dependent network code for ‘n’ platforms and expose it as a unified library. This way my network code would be platform dependent but any code that is reactive to a network request completion/failure (for example JSON parsing) would be shared. Am I correct?

I guess what suits my case better is something that transpiles code. I happen to come across j2objc (https://github.com/google/j2objc) from Google where you write code once in Java (which can be used in Android) and then it transpiles it to Objc that can be used natively in iOS. This way I write my network code once in Java using java libraries that they have transpiled like HttpUrlConnection and use it across both platforms as HttpUrlConnection transpiles to using NSUrlSession in iOS.

Wouldn’t this be a good thing to do as a road map for elements? All your developers to write all network, and data code once and then write UI natively across each platform? It seems that Google has shared around 70% of their code this way for their new product Inbox.

@mh on the other hand, while browsing Sugar on Github I came across Http.pas (https://github.com/remobjects/sugar/blob/master/Sugar/HTTP.pas) Does this allow me to write Http code in Silver that will become native on both platforms (iOS and Android) ? If so, then this is exactly what I’m looking for isn’t it?

It is yes.

Yes. But Sugar won;t be consumable from Xcode or the Java Language, only from Elements, as its types use a special feature of the Elements compiler, called Mapped Types (see here).

So you can use Sugar in the libraries you write in Elements, for there underlying network access (and other functionality).

TBH, it really seems you are trying to save at the wrong end, if yo just want to share a network API you’re not writing yourself anyways, in order to then use that from two distinct apps, iOS and Android. IMHO the sensible approach really would be to try and share the layer on top of the networking code, i.e. the “business logic”, as well. Implement that in Elements, make it use Sugar’s network stack (and other shared classes from Sugar). and then expose that layer to be used from your iOS and Android apps.

Does that make sense?

@mh so in the shared project, I’ll use Sugar and its Http class along with Json Parsing and then create methods within the 2 iOS and Android class libraries to call this shared Sugar code correct? The thing I like about this approach, although it seems more work than lets say j2objc where you write code once in Java, is that the method names in the individual libraries can be exposed using the name conventions on swift and Android to make the library seem more natural (j2objc seems to really mangle the resulting method and variable names in objc). So am I getting this right?

The problem is that sharable code will go only as far as Networking and Json Parsing since the data layer on top of the networking layer has objects written using the data context layers of the individual platforms for (e.g. Core Data on iOS) which can’t be used in a shared fashion. So the native app will make a call to this networking library which then will perform the request, parse the Json and then hand the control back to the native app which will then use the ORM of the individual platform to make changes and then update the views accordingly. This is how I plan to use it. Can the data layer be abstracted using Elements as well?

That’s interesting! I’ve managed to run this on Android:

let url = Url("http://httpbin.org/get")
let completion: HttpResponseBlock<String!>! = { response in {
        println(response.getContent())
    }
}
Http.DownloadStringAsync(url, Encoding.UTF8, completion)

So, sugar.Http seems to be working!

BTW, println() writes to global LogCat and I haven’t found how to write output to “this application”-only output.

I was giving Sugar a try in Fire and I’m unable to add Sugar to a shared project. Any ideas how I can get that working? Without it I’m unable to test anything out.

As I see, we should reference Sugar in platform-specific project and then just use it in shared one. In theory :smile:

Here’s the workflow described:
http://docs.elementscompiler.com/Projects/SharedProjects/

But I didn’t succeed in referencing shared project from platform specific one! Drag’n’drop for referencing in Fire is not working. And there is no my shared project in references list:

In Visual Studio or Fire, you right-click the “References” node of the real project and choose “Add Reference”, and then pick the shared project from the list. In Fire, you can also directly drag a shared project onto the “References” node to add a reference.

And while trying to add with “Browse” I can only pick .jar files.

Correct.

In theory, sure. you can write anything in Elements, and its up to at what level to draw the line between shared code and platforms-specific code (both at the low and high level). Right now Sugar doesn’t have any data-level abstraction yet, but i’d really like it see a SQLite abstraction added to it soon, so that could be used for example.

cool. FWIW, i’m currently working (started yesterday) on expanding/improving the HTTP layer in Sugar. We realize that Sugar is still pretty basic, and many areas can and do need to be expanded and improved. See hope that can be a community effort as well, as Sugar is fully open source, but it will be a major focus from our side internally, for the foreseeable, as well.

Good Q. i’m not familiar with the Android APIs much, myself. I’d assume there’d be some System API for that? If so, the same that would work in Java will work in Silver. Silver’s println() maps to writing to the system’s standard STDOUT, on all three platforms (actually, it maps to Element’s writeLn() function, which in run does that).

Shared Projects are only containers for files. Add your references (Sugar and otherwise) to the “real” projects. (After all, the referenes will be differed for iOS vs Android — libSugar.fx vs sugar.jar)

Unfortunately in Fire only dragging the project works, for now. Adding support for project and shared project references via Add References is still on my todo list. Sorry about that. Sugar isn still in Beta :wink:

I can’t make it work via drag’n’drop. Well, I think it would be OK for now to add via manual editing .elements file. What is format definition for dirs references?

This one is not recognized (1st reference tag):

<ItemGroup>
    <Reference Include="com.example.hellofire.shared"/>
    <Reference Include="android.jar"/>
    <Reference Include="swift.jar">
        <Private>True</Private>
    </Reference>
    <Reference Include="com.remobjects.elements.rtl.jar">
        <Private>True</Private>
    </Reference>
    <Reference Include="sugar.jar">
        <Private>True</Private>
    </Reference>
    <Reference Include="sugar.data.jar">
        <Private>True</Private>
    </Reference>
</ItemGroup>

Aha! I’ve found a shared project reference example in https://github.com/remobjects/SwiftBaseLibrary/blob/master/Source/Swift.Nougat.iOS.elements

<Project>
    ...
    <Import Project="Swift.Shared.projitems" Label="Swift.Shared"/>
</Project>

It’s working! :smile:

1 Like

This method works! I’ve noticed the main project and the shared project all have to be in the same directory for this work.
@mh i’ve also noticed that code completion in the shared project doesn’t work. So at the moment, I’m write swift code in the iOS Library (since code completion works there) and then copy that file into the Shared Project :stuck_out_tongue:

Another thing, it seems that in Silver the Swift method syntax doesn’t seem to work. For instance
Http.DownloadStringAsync(anUrl: url, Encoding: Encoding.UTF8) { response in } doesn’t seem to work instead I have to do this,
Http.DownloadString(url, Encoding.UTF8) {response in }
Am I doing something wrong or is this the expected behaviour?

I’m still testing Http.pas and will update here if it works complete with a unit test for what I’m trying to…

@mh @rudyryk
Is EUnit supported in Fire? I’m getting this error after adding an EUnit Project into my solution. Any ideas?