5

I'm currently working on an SDK which is available on both Android & iOS platform.

For Android, we list dependencies in our Gradle file and use Maven to provide the SDK (so our dependencies are listed in the .pom file).

For iOS, we use cocoapods to handle dependendies.

The problem is the following: * Our SDK use a dependency in version X * One of our client might use the same dependency but in version Y * Another client might also use the exact same dependency in version Z

So, this leads to our SDK potentially being broken on one of our client (if not both) because we ensure that it works with dependency X, but not Y and Z.

For now, the legacy code has simply imported source code of libraries causing this problem and namespaced it, such that it simulates we do not use the same library.

But in my opinion, this is not an appriopriate solution: we do not have latest fixes, it is painful to update, client has two times the library instead of one.

So, for now, I'm trying to think about a potential good solution, but couldn't find what I want on Google (maybe I'm not using the right keywords :/).

What I was thinking about was to provide support for a range of versions for each dependency. A bit like "if this method is here, execute it, otherwise, use that method of the previous version" (like selector respondTo on iOS). Then, the client should be able to use any version of the dependency at the condition it is in the supported range.

However, I don't know if it is the right way? Is there any other solutions?

Thanks :)

Simon Ninon
  • 2,371
  • 26
  • 43
  • I don't think what you are trying to achieve is possible. Even if you change your `code` to be version independent, your library still needs to mention exactly what other libraries it depends on. If you do not specify a version, the latest version will be assumed (at least in cocoapods). You cannot mention multiple versions of the same library under dependencies. Unless the versions are explicitly created to be used simultaneously. – Swapnil Luktuke Dec 08 '16 at 19:23
  • What you can do however, is make multiple versions of your **base sdk** with the only difference being the `dependency` version. As you said you could change your **base code** to support all the versions of dependencies for which you plan to create separate version. Then, the only difference between the various versions of your sdk would be pom/pod file mentioning specific version of the dependencies. You will have to maintain a matrix of all combinations of dependency versions for your client to choose the correct version of your sdk. – Swapnil Luktuke Dec 08 '16 at 19:30
  • With above approach, a client still cannot just use one single version of your sdk as you plan, but can simply **choose** the version that supports the other dependency versions in the client code. Since your sdk is meant to be added via maven/cocoapods, changing version of your sdk is just a number change in dependency config file (pom/pod) for the client. Its not ideal but i think its close. – Swapnil Luktuke Dec 08 '16 at 19:34
  • use cocoa pods to add dependency and drag the code of SDK to project? – jhd Dec 09 '16 at 03:51
  • @lukya I see. Actually, I was planning to support multiple version as you said and to specify a specific version used by default by the library. But this version can be overridden technically by the client who can choose a version in the supported range? But I guess it requires lots of work to support multiple version of multiple libraries, so not sure it can be the right choice.. and sooo few information about that apparently. Your solution is interesting though, although it seems hard to achieve and confusing for client I guess? – Simon Ninon Dec 09 '16 at 08:45
  • This part : **(library default) "version can be overridden by the client"** sounds problematic. Because, irrespective of what version for other dependency client mentions, your library will stick to the dependency version it is built with. By the way, what all dependencies doe your library actually have? – Swapnil Luktuke Dec 09 '16 at 08:53
  • I see :/ We don't have that many dependencies. On Android, we are dependent from Volley, a networking library. On iOS, we are using some UI libraries. Problem is that these libraries are popular, and many clients already use them in their project with different version. In some cases, it can cause conflicts... So, even though we don't have a lot of dependencies, they are kind of necessary for our SDK to work. – Simon Ninon Dec 09 '16 at 09:15
  • I could also not use the networking library and provide an interface that the client has to implement with its own networking library also for example. But that looks like extra work to integrate our SDK. I'm kind of wondering how super popular SDK like FB or Twitter SDK do work for that kind of things? They do have dependencies, at least for network I guess, so they might have encounter same problem I suppose? – Simon Ninon Dec 09 '16 at 09:17

1 Answers1

2

For android, there are two possible solutions, a build-tool based one, and an architectural one:

1.-If you build your library with maven, you can use the "provided" scope to force your library to get the dependencies from the container running it. That way, the dependency can be provided by the app consuming your library. Note that this will not help you if the dependencies are wildly different.

2.-Abstraction to the rescue! You can subdivide your project into the main library and plugin libraries. The main library will show the user every class an method and that will be the one they will call from their apps. Inside the main library, all classes will import every external SDK or dependency in an indirect form, a generic wrapper which can be either an abstract class or an interface, and use them that way. For example, maybe you are providing an enhanced facebook login UI. Then, instead of referencing the facebook SDK directly into your View, you will reference a facebookLoginInterface and call it. Then, you'll have a secondary project, facebookLogin41, where you will implement the facebookLoginInterface using the facebook sdk 4.1, and a second one, facebookLogin418, where you implement the same interface using the facebook sdk 4.1.8. Then, implement some sort of providing logic, like a Dependency Injection framework (Roboguice providers are a very good example), maven dependency scope (provided, for example), etc, to make the library instance the facebookLoginInterface. Finally, the client just imports both the main library and the secondary project needed and uses the main library.

Fco P.
  • 2,486
  • 17
  • 20
  • Thanks for the answer, the plugin-based approach can be very interesting. It should work well on our Android project since we mostly have the network library volley as a dependency. So we can easily do an interface and integrate that as a plugin. My main concern is now about the iOS app: we have several small libraries as dependencies (either small design tools or code utilities). One plugin for each would be definitely overkilled. Maybe we should merge multiple plugins into one? Do you have any thoughts about that? – Simon Ninon Dec 13 '16 at 09:51
  • As long as you keep the dependency contract (merge plugins consuming the same conflicting dependencies), you'll be fine merging the plugins. – Fco P. Dec 13 '16 at 15:51