The development of App is more inclined to the user level, from UI display to business logic processing, processing user behavior in the whole process. SDK is for developers, development is more inclined to function, focus on the implementation of function development. In today’s post, FinCliip’s engineers talk to us about designing the SDK.
What is SDK?
SDK stands for Software Development Kit. In a broad sense, SDK is a collection of Development tools used to build applications for specific Software packages, Software frameworks, hardware platforms, operating systems, etc. (In iOS projects, SDK is also called library).
In iOS or Android development, it is inevitable to use third-party tools to improve product development efficiency, such as aurora for message push, Alipay for third-party payment and login, wechat and so on. However, most commercial products don’t give the source code directly (perhaps only open source projects for love power will do so selflessly), and we need to integrate these third-party SDKS into our projects when developing apps.
SDK stands for Software Development Kit, which translates as Software Development Kit. It is a specific Software package written to assist in the Development of certain kinds of Software.
Ii. Basic principles of SDK design
A good and well-designed SDK must follow the following four basic principles:
- SDK is secure and stable
- Uniform development specifications
- Library is small but good
- Do not rely on third-party SDKS
- Security and stability: Considering that SDK needs to be embedded into App, the most important feature of SDK is security, which will not lead to App data leakage due to randomly open interfaces; The second important thing is the stability of SDK. If THE Crash of SDK is not captured and processed, the application will completely Crash (which will lead to the poor experience of third-party access App), and even directly lead to the loss of users of the access party.
- Unified development specification: For SDK development specification, unified naming specification is very important, the best state is “access party can know which manufacturer’s SDK after seeing the interface naming”, in other words, the unified naming specification of SDK forms its own brand effect, in addition, it is also convenient for developers to access and use. In addition, you also need to have their own coding standards. You can find the standard templates of big factories on the Internet, and sort out their own specifications by referring to them, so as to unify the code style as soon as possible.
- Library is small but fine: Small means to avoid a large increase in the number of apps of access parties, or it will cause dissatisfaction of access parties, or even the removal of the App. Fine means to focus on the function, such as aurora push, is focused on pushing related functions;
- Not relying on third-party SDK: This is also easy to understand. If the SDK relies on other third-party SDKS, it will not only increase the size of SDK, but also affect the related costs of SDK integration for access party.
3. Develop SDK in iOS environment
1. SDK in iOS
As mentioned above, in iOS development, we refer to the SDK as a “library,” and here’s how we define it:
- A collection of independent programs that provide a general service to an application.
- Are generally compiled, easy to use.
We will divide the library into “static library” and “dynamic library” according to the call method:
- Static linking: Generally, libraries are integrated into an application when it is created. The advantage of this is that the application package itself can run independently, but the disadvantage is that the package is a bit bloated and libraries cannot be shared (static libraries often end in.a).
- Dynamic connection: The application is created with the convention of the call relationship with the library rather than the complete integration of the library package into the application. This requires libraries to be provided in the runtime environment and connected to load when the application runs. In contrast to static libraries, dynamically linked libraries require a library environment, but they are smaller because they do not integrate library content. At the same time, it is possible to share libraries with other applications (common dynamic libraries are.dll under Windows, so under Linux,.dylib/.tbd under Mac).
Note: The Framework (in Apple) is used in Cocoa/Cocoa Touch applications as a way of packaging resources. It can put code files, header files, resource files, documentation, etc., in one place for developers to use. In other words, our Framework is actually a way of packaging resources, which has nothing to do with the nature of static libraries and dynamic libraries.
2. The difference between static and dynamic libraries
The difference between a static library and a dynamic library can be explained in terms of file linking (each source code module is compiled independently and assembled as needed, the process of assembling modules is called linking) :
- Static libraries: Links are copied in their entirety into executables, so if both programs use a static library, each binary executable will contain the code for that static library.
- Dynamic library: Linking is not copied, but is dynamically loaded after the program is started, followed by symbolic resolution (symbolic binding). Theoretically, only one copy of the dynamic library exists. Other programs can dynamically link to the library to save memory (there is only one copy of the library in memory). Another benefit is that since a dynamic library is not tied to an executable, it is easy to upgrade the dynamic library, as is common with plug-in and module mechanisms on Windows and Linux.
The specific advantages and disadvantages can be seen in this table:
Library type | advantages | disadvantages |
---|---|---|
Static library | 1. The target program can run directly without external dependencies. 2. Higher efficiency than dynamic library. | 1. Will use the target program’s size increases. |
The dynamic library | 1. It does not need to be copied to the target program and does not affect the volume of the target program. 2. The same library can be used by multiple programs (for this reason, dynamic libraries are also called shared libraries). 3. Features that are loaded at compile time also allow us to replace libraries at any time without recompiling the code. Implementing dynamic updates | 2. Dynamic libraries also make programs dependent on the external environment. If the environment is missing dynamic libraries or the library version is not correct, the program will not run (Linux lib Not found error). |
A static library can be understood simply as a package of object files (.o/.obj) (not a binary), while a dynamic library can be understood simply as an executable without the main function.
3. Understand iOS dynamic libraries (i.e., emasculated dynamic libraries)
As a bit of background note, iOS officially does not allow dynamic libraries, and all ipAs need to be encrypted with Apple’s private key before they can be used. Even if you use dynamic libraries, they will not load due to the wrong signature (jailbreak and non-App Store excepted). This makes it impossible for developers to develop their own dynamic libraries.
Before iOS8, iOS apps were running in a sandbox, different programs could not share code, and iOS is a single process (that is, only one process is running at a time), so even if you write a shared library can not be shared with others.
Dynamic downloading of code is officially prohibited by Apple, which means that the benefits of dynamic libraries are completely out of play, so there is no need for dynamic libraries.
But all of this has changed dramatically with the release of iOS8 with the Extesion feature for Swift.
Because the main iOS App needed to share code with Extension, and the Swift language mechanism also needed a dynamic library, Apple later proposed the Embedded Framework, This dynamic library allows the APP and APP Extension to share code (the life of the dynamic library is limited to one APP process).
A simpler explanation: dynamic libraries are provided, but they are neutered.
However, there is a big difference between Embedded Framework and THE SYSTEM’s UIKit.Framework. While traditional dynamic libraries are used by multiple processes, Embedded Framework is used by multiple executables in a single process.
The system Framework no longer needs to be copied to the target program. Even if the Embedded Framework is dynamic, it still needs to be copied to the App (the Bundle of App and Extension is shared). So Instead of calling it a dynamic library, Apple calls it Embedded Framework.
Swift is mentioned above for a reason. In a Swift project, if you want to use external code in a project, there are only two options, one is to copy the code into the project, the other is to use dynamic Framework. Using static libraries is not supported.
The root cause of this problem is that the Swift runtime is not included in the iOS system, but packaged into the App (which is also the reason for the large size of the Swift App), and the static library will result in the final target application containing duplicate runtime.
4. Using the dynamic library as an example, start making the SDK
Step 1: Create App project, named RealDemo
If you don’t know how to create it, you can click here, okay
Step 2: Close the RealDemo project, and create the Framework project in the RealDemo directory, named RealSDK
Select the Framework below to create
Remember not to choose the wrong directory
Step 3: Set the Build Settings for the Framework project
Select Dynamic Library to create Dynamic libraries and Static Library to create Static libraries
Step 4: Close the RealSDK project and create a WorkSpace named RealDemo
Click file-new-workspace one by one
The corresponding workspace file will appear after the creation
Step 5: Connect the Framework project and App project
We need to open up RealDemo.xcWorkspace, which you’ll find empty.
Then we directly need to connect to the Framework project (realsdK.xcodeProj) and App project (realDemo.xcodeProj) drag in!
Just drag it into Xcode
If you drag and drop, you’ll see that they have the same hierarchy
Step 6: Add the Framework to the App project
Click one by one, don’t point wrong
Select the framework you created earlier
Students who have SDK development experience should have seen it clearly here. The so-called real-time integration is to connect two projects with WorkSpace, which is somewhat similar to the principle of Pod.
Step 7: Add features to the Framework
We need to add a RealDog class that defines an eat method that prints the words “eat bones”. Then change the Target Membership of realdog. h to Public, meaning that it is a Public starting file.
Here I define the eat method RealDog as follows:
@implementation RealDog + (void)eat {NSLog(@" eat bone "); } @endCopy the code
Step 8: Call the SDK methods in the App ViewController
#import "ViewController.h"
#import <RealSDK/RealDog.h>
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[RealDog eat];
}
@end
Copy the code
Step 9: Run it to see that the App project successfully called the SDK’s methods
Okay, this is the end of the live feed
5. Use scripts to merge multiple architectures such as real machine and simulator
Step 1: Add an Aggregate Target
RealSDK Project -> TARGETS -> “+”(lower left) -> cross-platform-other -> Aggregate
Step 2: Name Aggregate Target “RealSDK-script”
After naming it, click Finish
Step 3: Rely on the RealSDK
Configure the Dependencies in Dependencies
Step 4: Add the script
Click on New Run Script Phase here
This script is universal, you can directly copy and paste:
# Type a script or drag a script file from your workspace to insert its path. UNIVERSAL_OUTPUTFOLDER=.. /Framework/ # create output directory, Mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" rm -rf "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}. Framework "# Build -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH= no-configuration ${configuration} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" BUILD_ROOT="${BUILD_ROOT} IPHONE_BUILD=${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework SIMULATOR_BUILD=${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}. Framework # Copy framework to univer cp -r ${IPHONE_BUILD}" "${UNIVERSAL_OUTPUTFOLDER}/" #cp -r "${SIMULATOR_BUILD}" "${UNIVERSAL_OUTPUTFOLDER}/" # define the output path variable ${PROJECT_NAME}. Framework Output the final framework to the build directory lipo -create "${IPHONE_BUILD}/${PROJECT_NAME}" "${SIMULATOR_BUILD}/${PROJECT_NAME}" -output "${OUTPUT_PATH}/${PROJECT_NAME}"Copy the code
Step 5: Run the script
Again, click the play button on the left
Step 6: View the results
If you can see this folder, you have compiled successfully!
If your Mac is the latest M1 chip, you may get the following error:
fatal error: lipo: /Users/hujianhui/Library/Developer/Xcode/DerivedData/RealDemo-ckvcidkkuvgpadeiqrvgjdyikcdc/Build/Products/Debug-iphoneos /RealSDK.framework/RealSDK and /Users/hujianhui/Library/Developer/Xcode/DerivedData/RealDemo-ckvcidkkuvgpadeiqrvgjdyikcdc/Build/Products/Debug-iphonesi mulator/RealSDK.framework/RealSDK have the same architectures (arm64) and can't be in the same fat output fileCopy the code
You just need to remove the ARM64 architecture of the iOS emulator, and here’s how:
Click on the minus sign in front of arm64 to copy and paste this script:
# Type a script or drag a script file from your workspace to insert its path. UNIVERSAL_OUTPUTFOLDER=.. /Framework/ # create output directory, Mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" rm -rf "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}. Framework "# Build -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH= no-configuration ${configuration} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" BUILD_ROOT="${BUILD_ROOT} IPHONE_BUILD=${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework SIMULATOR_BUILD=${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}. Framework # Copy framework to univer cp -r ${IPHONE_BUILD}" "${UNIVERSAL_OUTPUTFOLDER}/" #cp -r "${SIMULATOR_BUILD}" "${UNIVERSAL_OUTPUTFOLDER}/" # define the output path variable ${PROJECT_NAME}. Framework Output the final framework to the build directory lipo -create "${IPHONE_BUILD}/${PROJECT_NAME}" "${SIMULATOR_BUILD}/${PROJECT_NAME}" -output "${OUTPUT_PATH}/${PROJECT_NAME}"Copy the code
Step 5: Run the script
Again, click the play button on the left
Step 6: View the results
If you can see this folder, you have compiled successfully!
If your Mac is the latest M1 chip, you may get the following error:
fatal error: lipo: /Users/hujianhui/Library/Developer/Xcode/DerivedData/RealDemo-ckvcidkkuvgpadeiqrvgjdyikcdc/Build/Products/Debug-iphoneos /RealSDK.framework/RealSDK and /Users/hujianhui/Library/Developer/Xcode/DerivedData/RealDemo-ckvcidkkuvgpadeiqrvgjdyikcdc/Build/Products/Debug-iphonesi mulator/RealSDK.framework/RealSDK have the same architectures (arm64) and can't be in the same fat output fileCopy the code
You just need to remove the ARM64 architecture of the iOS emulator, and here’s how:
Click on the minus sign in front of arm64
6. Tips:
- The Framework uses categories
Add -objc to the Framework project Build Setting. In addition, -objc should also be added to the Build Setting of the App using our SDK.
- The Framework supports bitcode
4. Develop SDK in Android environment
1. Introduction to Android SDK
There are three main file types for Android App to integrate third-party SDK. One is JAR package file and SO file, and the other is AAR file. JAR package is the SDK file type provided by Java, which contains pure Java compiled code. SO is generally C and C++ packaged as a library file.
AAR, named after Android Archive, is a binary Archive of Android library projects. Using Android Studio, you can easily generate an AAR file. AAR library file contains JAR, SO, resource Res and other files, the structure is equivalent to an App.
It provides everything you need to build your application, including source code, resource files, and Android listings. However, the Android library will be compiled as an Android ARchive (AAR) file that you can use as an Android application module dependency, rather than an APK that runs on the device.
Unlike JAR files, AAR files provide the following capabilities for Android applications:
- An AAR file can contain multiple Android resources and a manifest file, allowing you to bundle in shared resources such as layouts and drawable objects in addition to Java classes and methods;
- An AAR file can contain C/C++ libraries for use with the C/C++ code of a module.
2. Create an SDK project
Open the sample project we created in the previous section, create a Library Module on the project, named GPush, and let’s simulate implementing an interface that pushes short news items.
If you forget how to do it, you can click here, okay
Select Android Library and type GPush in the name
Once added, we’ll see the corresponding Libray file on the left
3. Add dependencies
To use the new Android library code in another application or library module in the same project, add a project-level dependency like this:
- Go to File > Project Structure > Dependencies;
- Select the module in which you want to use the library;
- On the Declared Dependencies TAB, click +, then select Module Dependency from the drop-down menu.
Click the plus sign and then the corresponding Module Dependency
Add it to the dependency
4. Interface design
Since it is an interface to push news, it must be divided into client side and push side, namely Client#onReceiveMessage and GPush#pushMessage.
As you can see from the UML diagram below, there is only one method to listen to the newsfeed, GPushImpl#start(Client Client).
Take a look at the UML diagrams I drew to help you understand more
GPush class
package com.myname.library;
interface GPush {
void pushMessage(String msg);
}
Copy the code
GPushImpl class
package com.myname.library; import android.os.Handler; import android.os.HandlerThread; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; public class GPushImpl implements GPush { private List<Client> mClients; private HandlerThread mHandlerThread; private Handler mHandler; private Random mRandom = new Random(); Private List<String> MSGS = new ArrayList<String>() {{add("1, "); 2. Accelerate the reform of household registration along the Yangtze River to serve the high-quality development of the Yangtze Economic Belt. ); The websites of 10 illegal social organizations were shut down in the first batch this year, including the China Literary and Art Celebrities Association. ); Shanghai: From May 1, electric bike riders must wear helmets. ); 5, Guangzhou: Tomb-sweeping day to implement real-name appointment, advocating online worship, wrong peak delayed worship. ); 6. The accident of 6 deaths in Hebei Wuan Iron Mine was suspected of concealing the report, and the relevant personnel of the enterprise were controlled. ); 7. Huang Zheng resigned as chairman of PINDUoduo: He will give up super voting rights and devote himself to scientific research. ); 8. Breaking the 20-year monopoly of foreign countries, the domestic artificial heart has been successfully developed, but the time of commercial implementation is uncertain. ); 9, survey: 60% of young people fall asleep later than 23 o 'clock, dream more sleep light into young people sleep main problem. ); }}; GPushImpl() { mClients = new ArrayList<>(); mHandlerThread = new HandlerThread("Push-Thread"); mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper()); } @Override public void pushMessage(String msg) { Iterator<Client> iterator = mClients.iterator(); while (iterator.hasNext()) { iterator.next().onReceiveMessage(msg); } } public static void start(Client client) { GPushImpl gPush = new GPushImpl(); gPush.mClients.add(client); gPush.mHandler.post(gPush.mRunnable); } private Runnable mRunnable = new Runnable() { @Override public void run() { mHandler.postDelayed(mRunnable, mRandom.nextInt(10000)); pushMessage(msgs.get(mRandom.nextInt(msgs.size()))); }}; }Copy the code
The Client class
public interface Client {
void onReceiveMessage(String msg);
}
Copy the code
Start listening to your news feed
GPushImpl.start {
Toast.makeText(MainActivity@this,it,Toast.LENGTH_LONG).show()
}
Copy the code
The SDK package
./gradlew :GPush:assembleRelease
Copy the code
When the package is complete, an AAR file is generated, which is the result of our package
5. Last note –confusion
For code protection purposes, Gradle packaging by default confuses code based on build. Gradle and proGuard-rules.pro obturation rules. If the library uses techniques such as GSON or reflection, some classes need to be kept.
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
Copy the code
-keep class com.myname.library.** {*; }Copy the code
If you follow this tutorial correctly, you have successfully created your first iOS and Android SDK. This tutorial is still implemented on a MAC, but if you have a Windows or other operating system, you will need to make some flexible configurations.