Antecedents feed

Hey guys, I just got back from goji Berry Island. I compiled the outline and part of the content of this article on goji Berry Island. Next, let’s take a look at the scenery of wolfberry Island built by our group.

By the way, I would like to make a small advertisement. Our department is in need of iOS and Android recruitment recently. If you have a chance to see it, please contact me. I have my contact information on Github.

Because before some of the old story have been handed over, I feel there is no new article material can talk with you. I’ve been writing about SDK recently, so I’m going to share my experience with you and give you an article from SDK design perspective.

The body of the

First of all, I was in charge of three SDKS: payment, push and Debug components, among which push and payment in particular were very difficult to deal with. Because they are part of the business, if you offer them as a gift package to others, you will probably be scolded by the access side.

I don’t think my SDK design is particularly good, but I think there are a few things I can share with you. Sometimes more communication with peers can achieve better growth?

I’m going to talk about what I think a reasonable SDK would look like, based on a few different points.

Less dependent on

One problem I often get is that users will say that your SDK is a gift package and why there are so many repository dependencies. I only use a fraction of your features, but because I use the SDK, I have been introduced into a lot of dependencies.

So for example network libraries, data repositories, image libraries and a whole bunch of other things can be relied on. So all the SDK needs is to do what you need without using it, with minimal dependencies. There was a bigwig who did an analysis on this part.

Some personal insights about Android SDK development

The more advice I have for you is to run a Gradle Dependcies command when you have the time and make a rational analysis of what you need and what you don’t.

Also, use design patterns wisely, similar to the asynchronous chain of responsibility I introduced in my previous article. These things will help you maintain your code better in subsequent iterations.

The other thing is that you can load images, web libraries, and burying points into the SDK via interfaces. In addition, I don’t think it’s necessary to write too much in this section. If you’re an internal SDK like I am, it’s very easy for you to introduce these libraries directly.

Of course, it doesn’t have to be all at once. You can break it up into multiple stages, each of which removes dependencies you don’t think are useful. Otherwise, it’s not only risky but also too difficult to do all at once.

Multiple modules

When I developed these SDKS, I thought about breaking up these three SDKS with the simplest dynamic capabilities and then aggregating their commonalities in the form of adapters. Multiple modules are provided to the user for self-arrangement and combination. For example, when A connects to 12 and B connects to 13, the access can choose what it needs by itself. This eliminates the need for package code and enriches business access capabilities.

At the same time, many tripartite libraries are designed with more fine-grained functionality in mind. For example, Retorfit has many adapter and convert submodules, which users can then use by combining them.

How do you split granularity? My recent thinking is that a combinable library should have at least three layers.

  1. In the interface layer, I am only responsible for defining the common correlation of all three parties. From the aspect object, we can use their parent class in the form of dependency inversion.
  2. For the business layer, I will call the interface layer originally defined, and then obtain the concrete implementation class through some dynamic ways (the simplest way is through reflection or service lookup (SPI) related ways), and complete the transformation call between the abstract class and the implementation class.
  3. This part of the tripartite SDK layer is the same as retrofit’s Adapter, and we just need to implement the abstract interface here.

If you have some UI-related content built into your SDK, you may also want to provide users with the ability to customize the UI so that if the business needs to make changes to the page, they can do so themselves.

Add the switch

The SDK is also not static, and in the process of continuous iteration, when a relatively important feature comes online, it is best to configure some online grayscale strategy and rollback mechanism via abtest, so that you can safely push your new features online.

For example, when we replaced the old and new payment SDK, the strategy we adopted was that the two versions existed at the same time, and then we replaced the whole SDK to the new version after the new VERSION was stable through online grayscale test.

What are the benefits? First, we can observe whether the SDK is stable, and then whether the crash problem will affect the original process. If there is a problem, turn off the switch directly on line.

A single export

The last guy in charge of payments defined a lot of methods when calling payments. Call different methods for different parameters, use different methods for each activity or context or fragment, use another set of methods across processes, and then declare page callback onActivityResult, etc.

What’s the downside?

SDK users have to decide what the different function calls are based on the different parameters, so when your SDK starts to extend parameters, or whatever, you will find WTF, which is too hard to change, and the business side will complain to your superiors about the quality of your code.

In computer science, Currying is a technique that converts a function that takes multiple arguments into a function that takes a single argument (the first argument of the original function), and returns a new function that takes the remaining arguments and returns a result. The technique was named after logician Haskell Curry by Christopher Strachey, although it was invented by Moses Schnfinkel and Gottlob Frege.

This part of the design, I think, is a single variable parameter, and then the SDK will actively determine other additional conditions, such as process callbacks, parameter increases or reduces, callback results, etc.

At the same time, fewer code calls means that the SDK can do whatever it wants. Even if I make a big change internally, as long as I don’t change the logic of the calling method, the business caller won’t be aware of it.

Data to talk

When we run a test process and find no problems, and then we publish online, what should we do if there is feedback on online problems?

There should be a set of buried points for troubleshooting online problems and the buried points for SDK callback results. In this way, we can reverse search the user-related buried points through the id-related data provided by users, and then locate the actual problems of users according to the final buried point results.

Some other data can also prove how well we optimized this part of SDK and help us complete my KPI specification plan.

Keep pace with The Times

Now that coroutine dependencies have been added to the project, it is not satisfying for the SDK to only provide an asynchronous callback to the user.

Therefore, on the basis of the original export method, I added a dependency library of coroutines, and modified the asynchronous function to suspend, so that users can use this function directly in the future, and then write code more easily.

At the same time, because it is a newly added warehouse, it will not cause other problems without introducing coroutine projects.

adjustable

Under normal circumstances, an SDK provides users with an AAR. If some problems are found to be difficult to debug during access and aar versions are released one by one, your development progress will be seriously affected. Therefore, a reasonable mixed development mode can help you reduce this problem.

My previous article covered compose Build and I wrote a plugin to make it easier for you to do this. portal

Easier access

This is only compared to the SDK design. In fact, I intend to make it easier for others to access, and it would be best if different codes could be generated automatically according to different apps.

As an internal SDK, due to reduce SDK dependence on external issues, it will naturally be inconvenient to initialize, but we all know the truth of writing more and more mistakes, so if this part of access can also be generated by code automation, then it can solve many pain points.

Based on my previous experience in writing push SDK, I will adopt the way of Plugin pushed by Android manufacturers. The activity that dynamically generates the buried point class and wechat pay callback knows to write its own callback to accept the activity according to the application package name.

To keep up with The Times, this time using the KT code generated by KotlinPoet, also encountered some strange problems. For example, kotlin’s Map class is not a Java Map, and Kotlin’s String is completely different from Java.

At the same time, since plugin knows the applicationID of the current access party, we can automatically import and add the matched applicationID dependencies with Plugin, and at the same time complete the cleaning work of the dependent versions in the project, so that the other developers do not perceive our AAR as much as possible.

TODO

I added some simple logic judgment when adding the buried point code. This part of logic will be automatically generated only when there are dependencies of wechat and buried point library in the project. If there are no dependencies, it will not be generated, so as to avoid exceptions caused by class reference failure.

However, I use the allDependencies method of Gradle Configuration. This method does not check the dependencies passed in, so there is a small flaw in this method.

Anyone who knows can leave a message to me in the underground and let me read it. If it’s Kotlin, it’s the best. Thank you.

At the end

The main content of this article is just my feelings and experiences. If you have any questions, please feel free to discuss in the comments section.

Another point is that since I have been an SDK user before, I actually have some understanding of what users want. So WHEN I encapsulate, I try to get rid of things that I don’t want to write, or things that I didn’t feel comfortable using before.

During the development process, I also add some thoughts of my own. For example, if I think something can be automatically generated, I will automatically generate this class, which is actually more convenient for everyone. If you think about it a lot, you can do a lot of different things.