Technology at mSale - Tips & Tricks part 1 - Native extensions for iOS using Kivy

Target reader: Intermediate Kivy and Python user, people curious about the Kivy framework.

Here at mSale, we use a multitude of different technologies, depending on the needs of our projects. Most of our tech stack is heavily based on Python, however, and therefore it was only natural that we would gravitate towards the Kivy framework. 

Kivy is, as per Kivy.org is a "Open source Python library for rapid development of applications
that make use of innovative user interfaces, such as multi-touch apps."
We will not go too deep in the merits of Kivy in this article, but it has served us extremely well and is in use for both our maintenance tooling aimed at mobile phones, and the gift card machines themselves.

The problem

Kivy, by nature of being a not-first-class framework for the platforms it is used on (such as using Swift/Objective-c on iOS and Android/Kotlin on Android), does not have a significant or large extension ecosystem. Given that it also has a relatively low userbase, compared to more popular frameworks and implementations, like React Native, Ionic and the native implementations, there aren't enough people there for the third parties creating these extra services to make their own implementation aimed specifically towards Kivy.

This means that we do not have easy access to things like Fabric crash logs, OneSignal push notifications and so forth. I have often seen people comment that this is often the dealbreaker when it comes to using the framework, considering the multitude of content and extensions for the other frameworks.
But not any more!

The solution

From this point on, I am going to demonstrate how you can use just about any (disclaimer: I have not tried every single third party library out there) extension out there, just like you would in a normal iOS project.

Part 1:

Create the base of your kivy app!
For reference, I'll include a full main.py from one of the apps we are currently developing: 
gist
The actual look and structure of your app does not particularly matter, but make notice of the naming conventions for the initialisation of the libraries in the finish_ios_init method. The actual code is merely a pyobjus  translation of the official fabric and onesignal installation instructions - and those instructions should be followed for all non-kivy things.
After your skeleton is up, you should do your initial buildozer build: buildozer ios debug.

Part 2:

After your initial build is done, the iOS project itself resides in .buildozer/ios/platform/kivy-ios/<project-name>-ios/ and it is within that folder we will do our cocoapods setup. For this project, the Podfile should look something like this. After the podfile is set up, you can run pod install like normal in this folder and work with the <projectname>.xcworkspace like any other project, and finish the initialisation from there.

Once these relatively simple steps are done, the app should work with the extentions when run from the xcode workspace, like a normal iOS project utilizing cocoapods. 
An important takeaway is how methods with parameters are called with pyobjus.
Take the Fabric initialisation, for example: 

self.Crashlytics = autoclass("Crashlytics")
self.Fabric = autoclass("Fabric").with_([self.Crashlytics])

For pyobjus, it would appear that anything that has a unnamed parameter ends the method call with an underscore. Similarly, for named parameters, we see it follows a similar pattern:
methodCall_namedParameter_(unnamed first parameter, named parameter)
This can be seen with the onesignal initialisation:

self.onesignal_object = autoclass("OneSignal")
mock_launch_options = objc_dict({})
self.onesignal_object.initWithLaunchOptions_appId_(mock_launch_options, "onesignal-appid-goes-here")

This would be the equivalent of the official way, taken from the install instructions:

   // Replace 'YOUR_APP_ID' with your OneSignal App ID.
   OneSignal.initWithLaunchOptions(launchOptions,
       appId: "YOUR_APP_ID",
       handleNotificationAction: nil,
       settings: onesignalInitSettings)

In conclusion

I hope this little blog entry has been a useful tip on unlocking more power from the Kivy framework! It has been but a minor peek into the potential possibilities you can unlock, combining Kivy with the power of native third party libraries. 

This is but a small part of the technology we use at mSale, and we are always interested in talking to other people and sharing our knowledge, so leave a comment! Have you used Kivy before? Does it sound like something you would consider for your next project?

I have been Kjetil A. Liknes, thank you for reading.

 Live example of the OneSignal notifications coming in

Live example of the OneSignal notifications coming in