The background that
The company required other project teams to provide an entry to access the interface of our project, so we decided to adopt the form of framework, package our project into a framework for other project teams, and then provide the corresponding interface call. However, due to historical reasons, another project team couldn’t rely on third parties through cocoaPod, so we had to integrate the third party source code into our framework. More on how to make a framework that relies on third-party libraries through cocoaPod later.
Knowledge sorting before production
What is a framework
The framework is essentially a library that can be made available to others but hides the implementation inside. The. Framework of the system is a dynamic library, which we build ourselves. The framework is a static library.
Static and dynamic libraries
Static libraries are fully copied to executable files when they are connected, and there are multiple redundant copies when they are used many times. Exist in the form of. A and. Framework dynamic library connection does not copy, the program is dynamically loaded into the memory by the system when running, for the program to call, the system only load once, multiple programs share, saving memory. It exists in the form of. Framework,.dylib,.tbd
The difference between.a and. Framework
A file cannot be used directly, but at least a. H file must be used together. The. Framework file can be used directly
Next comes the creation process
1 Create a Demo project
The Demo project is used to run and test the framework, because the framework is not a project and cannot be run directly
2 create a framework
TARGETS -> +
3 the configuration framework
Deployment Info Minimum system requirements
Of course, it is better to recommend low, (example ios9)
Build Active Architecture Only Builds the Active Architecture Only
If set to NO, not only the current schema will be compiled. If set to Yes, only the currently selected schema will be edited. For example, if you select iPhone 13 emulator to compile, the compiled framework will only be used by iPhone 13 emulator
Excluded Architecture
This is to remove the duplicate arm64 architecture, because the real machine and emulator compile, the framework in the arm64 framework is the same, which will cause the merge failure, so remove the arm64 architecture in the emulator
IOS instruction set knowledge
armv6
IPhone iPhone2 iPhone3G first generation and second generation iPod Touch
armv7
iPhone4 iPhone4S
armv7s
iPhone5 iPhone5C
arm64
iPhone5S iPhone6 iPhone6+
Instructions are backward compatible, such as the iPhone5s CPU which supports arm64, but it is also armv7s compatible, although if the program is compiled using armv7s instructions, it may not make the most of its 64-bit features.
Architecture
The device to which the program is compiled (armV7, armV7s…) Compile-time generates proprietary installation packages for different instruction sets (devices). Different devices will execute the command set corresponding to the device, such as iPhone5s will preferentially execute arm64 (if available)
Dead Code Stripping
Compilation option optimization is used to Strip the code that is not actually used in the executable binary compiled by the program to slim down the framework package. However, for the framework, it should be set to NO to prevent the code and debugging symbols from being stripped.
The Mach – O Type Type
Set the type to static library
Build Configutation Compiles the configuration
Set to release
5 Developing code
Swift does not expose interfaces like OC. To call interfaces to other projects in SWIFT, prefix classes, methods, or properties with public or open.
Swift Permission control letters
open
Maximum permission, can be accessed by external modules, overriding public
Internal can be accessed by external projects
Default file creation permissions can be accessed in this project private
It can only be accessed within the created file
For project reasons, the third-party framework can only be introduced through source code. Take SnapKit as an example, drag the source code of SnapKit into the project
At the same time create a test file gpkitController.swift, targets select GPKit
// // gpkitcontroller. swift // GPKit // // Created by Darren on 2022/3/25. // import UIKit /** GPKit controller */ public class GPKitController: UIViewController { public override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white Navigationitem. title = "GPKit" let label = UILabel() label.text = "I am the controller inside GPKit" label.textColor =.red view.addSubview(label) label.snp.makeConstraints { make in make.center.equalToSuperview() } } }Copy the code
6 Add compile merge script
The compilation of the framework is divided into simulator compilation and real machine compilation, and the framework we provide to others to use is generally run by the simulator and real machine, so we must merge the two versions of the framework into a general framework
targets -> +
There is no merge script code using cocoaPod
#! /bin/sh # SDK UNIVERSAL_OUTPUTFOLDER="${SRCROOT}/Products/" ${PROJECT_NAME}. Xcodeproj # if I use cocoaPod, ${PROJECT_NAME}. Xcworkspace WORKSPACE_NAME=${PROJECT_NAME}. Xcodeproj # create output path folder mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" Rm -rf "${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}. Framework "${SDK_NAME}" -configuration ${CONFIGURATION} -sdk iphoneos ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build # Build simulator framework xcodebuild-target "${SDK_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean Cp -r "${BUILD_DIR}/${CONFIGURATION} -iphoneOS /${SDK_NAME}. Framework" "${UNIVERSAL_OUTPUTFOLDER}" # copy the swift module of the simulator framework to the path of the final output SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SDK_NAME}.framework/Modules/${SDK_NAME}.swi ftmodule/." if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" ${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}. Framework /Modules/${SDK_NAME}. Swiftmodule" ${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}. Framework /${SDK_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SDK_NAME}.framework/${SDK_NAME}" ${BUILD_DIR}/${CONFIGURATION}- iphoneOS /${SDK_NAME}. Framework /${SDK_NAME} dir_path="${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}.framework/" for file in ls $dir_path do if [[ ${file} =~ ".xcconfig" ]] Then rm -f "${dir_path}/${file}" fi done ${UNIVERSAL_OUTPUTFOLDER}"Copy the code
Use cocoaPod’s merge script code
If the.xcworkspace file is created through cocoaPod, the script code is as follows
#! /bin/sh # SDK UNIVERSAL_OUTPUTFOLDER="${SRCROOT}/Products/" WORKSPACE_NAME=${PROJECT_NAME}. Xcworkspace # Create an output path folder mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" # Remove the framework rm -rf generated last time ${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}. Framework "${WORKSPACE_NAME}" -scheme "${SDK_NAME}" -configuration ${CONFIGURATION} -sdk iphoneos ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" ${WORKSPACE_NAME}" -scheme "${SDK_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build # Copy the generated real framework to the final output path cp -r "${BUILD_DIR}/${CONFIGURATION}- iphoneOS /${SDK_NAME}. Framework ""${UNIVERSAL_OUTPUTFOLDER}" # copy the swift module of the simulator framework to the final output path SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SDK_NAME}.framework/Modules/${SDK_NAME}.swi ftmodule/." if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" ${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}. Framework /Modules/${SDK_NAME}. Swiftmodule" ${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}. Framework /${SDK_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SDK_NAME}.framework/${SDK_NAME}" ${BUILD_DIR}/${CONFIGURATION}- iphoneOS /${SDK_NAME}. Framework /${SDK_NAME} dir_path="${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}.framework/" for file in ls $dir_path do if [[ ${file} =~ ".xcconfig" ]] Then rm -f "${dir_path}/${file}" fi done ${UNIVERSAL_OUTPUTFOLDER}"Copy the code
7 generated framework
To execute the script, simply select GPKitAggregate and run
The resulting directory is as follows
8 test framework
Create a new project and drag the generated framework into it to create a jump point
Then run it respectively with the simulator and the real machine. If both can run successfully and jump, the framework is successfully made
9 Third-party reuse
The test creates a new framework called GPKit1, which also references the source code of SnapKit, and then imports GPK and GPKit1 into the test project at the same time, and jumps to the corresponding page respectively