Tips when writing SDKs for iOS

Tips when writing SDKs for iOS

Foreword

If you (app developer) have developed an app for a big or relatively big client it is likely you have been asked/required to add some SDKs to the app because of some regulations/security policies/other departments requirements/estrange specification/what ever non-technical requirement. These SDKs are usually not available to the world in an open way. App developers get to access to it after a contract between client and company that provide this SDK has been made.

App developers have a rough idea of what the SDK will do but don't know details it is received. These SDK are usually closed source so app developers never know real details. This is a usual thing when developing a enterprise app.

I have been in this situation several times and it is always the same story... weird SDKs doing things too smart, weird configuration rules, akwardly designed, not running in simulators,...

Who is writing this?

Aside from using various OSS libraries, tools, etc as everybody else. I have developed a couple of SDKs for commercial purposes in my previous companies and I have used dozens of SDKs from other companies in my current app. I think I have some experience and would like to write about the bad/worsts things I encounter in these SDKs.

Why this happen?

These SDKs exists not because they are technically good in what they do, not because they are well designed. They exist because sales people are good at selling the product. And buyers are non technical people, rather they are people from other completely different departments that need certain functionality to do their jobs. In this sense these SDK are good at their job. It is only technically speaking they are far away from shine.

Wording

Library/SDK/framework

In this post the words library/SDK/framework, all are interchangeable. Library is the most general word. Framework means the same in ios/macos worlds. SDKs is basically the same but usually provided/developed by some company and provides functions to use/access functions provided by that company.

App developer

Developer that makes an app that uses the SDK. The app hosts the SDK.

SDK developer

Developer that makes the SDK. The SDK needs to be used by Ann app to effectively function.

Tips

Tip 1: Do not forget you are just a mere library.

Some SDKs forget this. They forget this and try hard to enforce their programming practices/models/architecture into the host application. Host application should be able to do whatever they need to in they way they want to. Not just in the way the SDK prefers.

Example:

SDK that send push notifications, suddenly you realize they provide a view controller to show the push notifications and this is the only way to get history (old list) of push notifications?!

Tip 2: Please provide framework that works in all architectures possible.

There are some companies that only provide SDK that run in real iOS devices but no simulator. Even though SDK developer doesn't want to expose things to simulator for X reasons a compilable version should be provided. A dummy implementation is enough sometimes.

Why?: Because app developers usually work with the simulator the entire day. Running/Debugging things in real device requires much more effort and with your SDK not running in the simulator this is a extra effort that is usually not well estimated ahed of time.

App developers that use this incomplete SDK will need to create a wrapper with lots of <code>#if ... #else #endif</code> and this work is 99.9% unexpected and not taken in account at estimation time. It could be the origin of bugs ... lets avoid this.

Tip 3: SDKs should not fire user permission alerts at their own will.

This is better explained with an example; Lets say SDK uses/needs bluetooth connectivity internally. So SDK attempts to use bluetooth device at initialization moment then bluetooth usage permission alert might show as soon as the app start. Taking care of UI/UX of the app is also a task of app developers and showing this alerts on unwanted random moments is definitely a bad experience.

Please make sure you provide a way to instantiate the SDK silentiously without firing all alerts as it passes. If using Bluetooth (in this example) is everything or mainly what the SDK does, please document this behaviour so app developers can know about this before implementing or even before they get to get the binary.

Tip 4: SDKs should not use other libraries in a way that will cause linker clashes in hosting app.

For example, a few years ago AFNetworking was a major library in iOS world. If you are a SDK/library you don't get to use other libraries like this because chances are that the host can use it. If versions are exactly the same linker warnings will rise: Bad developer experience. If versions are not the same then who knows what will happen. It might compile with linker warnings but die at runtime or have some weird behaviour. If SDK really needs to use another library they it should be vendored like "MyCompanyAFNetworking" (providing licensing is not a problem).

If vendoring a library is too much for SDK developer then consider not using it at all too. Host app might be affected in very harmful ways.

Please consider not adding libraries with all purpose functions, rather use a single library for a single purpose. App size also matters :)

objc[679]: Class _AFURLSessionTaskSwizzling is implemented in both /private/var/containers/Bundle/Application/3DFCB136-D020-42C1-AF8A-75C13C4F47AA/SMBC.app/Frameworks/MyFramework.framework/MyFramework (0x10c046c50) and /private/var/containers/Bundle/Application/3DFCB136-D020-42C1-AF8A-75C13C4F47AA/MyApp.app/MyApp (0x106216768). One of the two will be used. Which one is undefined.

Tip 5: Please remember you are not the only cityzen

Specially in enterprise apps there might be various SDKs that serve to the same technical purpose but it is used for a different requirement. Example: Push notification SDK from company A and other from B. push notifications from A are used by department Z and push notifications from B are used by department Y.

No push notification SDK should request notifications permission because the other one might not be prepared yet! Let that job to the app developer... you are just a mere library so just wait until you get a push notification token when the app wants to give it to you.

No push notification SDK should steal other notifications. Please send payloads in a way the push notification is identifiable. As a SDK developer you should provide this functionality or allow it.

If you are using method swizzling for something make sure it will work if other party do the same!

Tip 6: Initialization

If SDK requires a server URL key String and let's say options [String: Any] then simply provide an initializer that receives them. Do not try to make things easier, clever. It will make things worst. SDK developers varely know the real needs of enterprise app developers.

Read things from a file called MySDK.plist? -> No because there is usually at least two environments with two configurations and interchanging files is possible in scripts in Xcode but it is just harder than simply variables.

Read things from a simbol (something like static String mySDKURL = "clientA.mySDK.com")? -> No because this API has bad discoverability... Also this will usually require much more work in SDK side to properly handle bad settings from app developer side.

Tip 7: Provide Version number

Provide version number somewhere in the SDK. In the main header or as an API of the SDK itself. This is important because depending on the way you provide the SDK, it might not be in a library manager. It might be simply copy and pasted entirely inside the app.

Tip 8: Provide various ways of installation

  1. Prefer Swift package manager support (Currently not all SDK are shippable in this way but if you can please support it. It is the strictest PM so if you support this supporting others later will not be a big problem)
  2. Offer Carthage support (Cocoa pods seems like the default however this semi-auto package manager is good and does not complicate entire xcode project.)
  3. Offer cocoapods support (but do not make it the default, it complicates the entire project... and projects might not be using cocoapods!)
  4. Offer manual installation instructions (It is nice to have this, although)