Series of articles:OC Basic principle series.OC Basic knowledge series.Swift bottom exploration series.IOS Advanced advanced series

preface

In front of the article about static library and dynamic library, the content is to prepare for this article, here we talk about the actual SDK development of static library and dynamic library application, usually development will also use the content of the article.

XCFramework

XCFramework profile

  • 1. It is officially recommended and supported by Apple, which can be expressed more convenientlyMultiple platformsandarchitecturetheThe format for distributing the binary library. in19 years with
  • Need 2.Xcode11 supports the above. (notIOS Version, it isXcode11 has this feature)
  • 3. Is forbettertheMac Catalyst support(It’s a feature of macOS to better port iPad apps to ARM chips) andARM chip macOS. Another type of framework specifically proposed in 2019Advanced format.

Compare that to a traditional framework

  • 1. Can be usedA single. Xcframework file provides distribution binaries for multiple platforms;
  • And 2.Fat HeaderCompared withBy platform, you canContain the same architecturetheDifferent platformsThe file;
  • 3. In use,Don't needagainThrough scriptGo to theStripping doesn't requiretheArchitecture system.

Dynamic library merging

I wrote a function calledSYTimerAnd we put itCompile into a dynamic library

Simulator architecture

You need to compile the command:If you hit Enter, you’ll see that the project starts compiling and ends inSpecify file generationweNeed to bethefile

O files have been generated during the compilation process, and the above files are the files we usually compile with Xcode

Let’s show you the contents of the package and take a look at what’s inside

SKIP_INSTALL is set to NO to copy the framework to this directory

Real machine architecture

We’ve compiled it up hereSimulator architecture, let’s compile toReal machine architecture

The red box is the difference, one is the distribution platform, one is the name, hit Enter

At this point we see that there are two files in the folder, one is the emulator, one is the real machine, let’s merge

merge

In making the SDK, we need to provideThe SDK needs to support real machinesAnd needSupport simulator! Now we need quantityTwo dynamic libraries mergeIn this case, the lipo command is commonly used

Create or manipulate a file.

Fat binary

Let’s talk about it firstFat binary.Fat binaryisMultiple architectures are packaged togetherBut there is a problem that is packaged togetherThe architecture cannot be the sameLet’s look at the architecture of the generated real machine SYTimer executable

We found two architectures named ARM_V7 and ARM64!

When we did the packaging above, we only specified the distribution platform, not the architecture, but why are there two?

  • This is because the Build Settings in the Xcode project are executed at package time.

Moving on to the fat binary, the fat binary is going toIndividual dynamic librariestheMach - headers are put together.Each librarythefileSide by sidePut togetherAnd,It's not really a merger.

merge

Here we useLipo command to merge And when we hit enter, we find that we got an error, and the reason for the error is thatArm64 exists in both architectures

The main reason for this is that when we pack the emulator, we set the Build Settings to arm64

If we have to merge, then we need to extract the x86 architecture of the simulator and remove the award-winning ARM64 architecture. Let’s do the extractionOnce we extract it, we’ll merge it

At this point, a SYTimer with multiple schemas is generated

Question:

  • 1. Generated SYTimerThe header file needs to be reprocessed
  • Need 2.Wrap it into a new framework
  • 3. Need toThe signature again

All of the above have to be done manually and there are other things that we will do when we packGenerate sdYM and map

DsYM should be familiar, but if map supports Bitcode, it needs BCSymbolMaps, otherwise dsYM won’t be able to parse it

How to solve the problem, which leads us to the content of the topic: Apple in 19 introduced the XCFramework

Using XCFramework

Let’s compile one by commandXCFramework Hit Enter and we’ll seegenerateourNeed XCFramework

  • We can see thatThe same architecture, and it is alsoCan mergeAnd,Automatically generate corresponding schemastheframeworkAs we said aboveSdYM didn't put it inLet’s put it in

  • Pay attention to is-debug-symbols links filesNeed to beAn absolute path.Can'tmakeRelative path

  • What we said aboveSdYM and MAP are linked in

Now let’s use the XCFramework

  • 1. Drag sytimer.xcFramework directly into the project

  • 2. Import the header file and create the attributes

  • 3. Select the simulator to compile

It says,xcframeworkwillAccording to the differentthePlatforms choose different architecturesUnlike the traditional framework, which contains all of them, let’s verify

  • 1. According toSimulator compiled successfully, generates an executable file, we see the Frameworks in the executable file package content, contains SYTimer. The structure of the framework

This is aSimulator architecture

  • 2. Switch toArm64 architectureforcompileTo check theExecutable file

This is aReal machine architecture

conclusion

Xcframework is much better than the LIPo command

  • 1.You don't have to deal with header files
  • 2.No need to worry about repetitive architectures
  • 3.Debug symbols can be exposed

So get your XCFramework up and running

Practical application of project

A weak reference

Create a project in which we want to introduce sytimer.frameworkAs we talked about earlier, linking to a frameworkThe three elements

  • 1.Specify the header file -i

  • 2.Specify the framework file directory -f

  • 3.Specify framework name -l

After writing, write code to run, run successfullyNow let’s run the projectProject error, familiar error, this is because of usIt doesn't tell you where the framework is, weYou can drag the framework into the projectBut I don’t want to. I doSet @rPath via xcConfig Then this@ rpath settingandThe error/SYTimer. The framework/SYTimer joining togetherWe find the path, we run it again, it works

Weak reference symbol

We said weak references, if this thing is not defined at runtime, it has a weak reference symbol, then the linker automatically sets it to null, which means it can be null at runtime, it can’t be found at runtime

  • It says ifAn error is reported when no path runs

  • We canSet sytimer.framework as a weak reference, so that no error will be reported

  • We look at the-weak-frameworkinDefinition in the linker

  • Consistent with the above explanation, no more narration, directly run the project to see whether it will report errors

No errors were reported in the project, butThe print is nullAt this time weSettings workWhat good is this when the projectNo error will be reported if a library is missing

  • So what does Mach-O do at this point

At this point itCMD is no longer:LC_LOAD_DYLIBBut:LC_LOAD_WEAK_DYLIB

Link to the conflict

We have a situation in our program where,Introduce third Party AInside,There's a library called E, before introducing aThird party BInside,There's also a library called E, then it willconflictBecause theTwo E's are introducedSo how to solve this problem? Let’s simulate this by introducing two AFNetworking libraries in a project and linking themNow let’s create the xcConfig file and operate in it

  • So once we’re done, we compile, no problem, so now we’re going to introduce a header file and we’re going to do it, and we’re going to compile without any problem.

weTwo static libraries are linked, justThe name is different, butThere are no conflicts at compile timeWhy?

Because the default is -noall_load when linking to static libraries, which means it will be code removed, AFNetworking2 will no longer be linked to AFNetworking when it is found

  • If you switch to-all_loadAnd compile

There are 223 symbol conflicts, so how to solve the problem?

  • We look at theXcconfig file from CocoapodAnd found thatA - ObjC OTHER_LDFLAGSRefers to theAll OC codeWill be imported because AFNetworking and AFNetworking2 are both OC codes! So what do we do here? We can use-load_hidden

Static library files can be hidden without exporting anything

Here is a rewrite of the xcConfig file

  • The successful running

Dynamic libraries link dynamic libraries

  • 1. Let’s create a Fremework calledLJNetworkManager“, and then import through cocoaPodsThe dynamic library AFN

  • 2. Now we are in the dynamic libraryLJNetworkManagertheLJAFNetworkingManager.mTo introduceThe dynamic library AFNetworkingIn theLjNetworkManagerTests.Call the LJAFNetworkingManager method

  • 3. At this timeCompilation is no problem, butThe LjNetworkManagerTestsforrunwhenAn errorthe

  • 4. The reasonAFNetworking was not foundNow let’s seePackage contents for LjNetworkManagerTests

There is no Frameworks folder, let alone AFNetworking

  • 5. How to solve it? We canThe AFNtheThe absolute path goes to LjNetworkManagerTests

  • 6. Run it again and you will find that everything is successful

But the problem can’t be solved that way, so absolute paths are not really desirable

  • 7. We can passcopyIn the form ofCopy the framework to the package

This is code in the.sh script in Cocoapods, which means to copy the project to the appropriate directory. This is why the dynamic libraries managed by Cocoapods do not have this problem

  • 8.Have Cocoapods import AFN to LjNetworkManagerTests as wellAnd then update

  • 9.updateAfter therunAnd we found thatsuccessfulthe

expand

If LJNetworkManager wants to reference the code in LjNetworkManagerTests (reverse dependency), dylid will put all the exported symbols together during the linking process, as long as it can be found when running again, it will work fine

  • 1. The Header

  • 2. Import the header file inLJNetworkManager introduced LJTestAppObject. HYou need to change itPods-LjNetworkManager.debug.xcconfig

  • In 3.LJAFNetworkingManagerIn theThe introduction of LJTestAppObject, found that identified

  • 4. An error occurs and the symbol cannot be found

We said that once the project is running, it’s going to find itself, how do we get it to run? -undefined

This is successful, but there is a problem, we write arbitrary symbols will be ignored, no error!

  • 5.Specify the symbol -u

It will also be successful

  • 6. Verify

And we see that we’ve switched to the LJTestAppObject method, so we’re doing the right thing, we’re doing the reverse dependency

Dynamic libraries link static libraries

This is the same code up hereWill PodfileTo introduce AFNuse_frameworks! To get rid of

  • 1. When you update your Podfile, you’ll find thatAFN static library

  • 2. At this timeCompilation does not report errors

  • 3. At this time weLjNetworkManagerTestswhetherIntroduce static library AFNThe answer is yes, let’s configure it

  • 4. Just set it up, because weThe linked libraries are static, you only need toFind the header fileThat’s it. As mentioned in the previous article, I won’t explain it here. Successful at runtime

expand

When I give someone a dynamic library, I don’t want the symbols of the static library to be exposed. How do I do that?

  • 1.The linkerProvides us with parameters to hide:-hidden-l

  • 2. At this point we recompile

Error, undefined symbol! This is how we control whether static library symbols are displayed

Static libraries link static libraries

Again, the above project, at this point we will create theLibraries become static librariesAnd theAFN is also a static library

Does LjNetworkManagerTests use LJAFNetworkingManager?

Let’s examine: LjNetworkManagerTestsWhat's wrong with introducing static libraries, butA component is a static library, itIntroducing static libraries, you need toManual integrationLet’s compile:

If we can’t find the symbol, we need to expose ourselves

  • 1. In the Build Settings

  • 2. At this point inCompile the project,successfulthe

The component links to the static library and is not exposed to LjNetworkManagerTests, so it needs to be imported manually

Static libraries link dynamic libraries

Again, the above project, at this point weImport AFN as dynamic library

  • LjNetworkManagerTestsUsing static libraries.No problem, but beUsing dynamic LibrariesYou need toPlace dynamic libraries in LjNetworkManagerTestsTo just go. Project error found when compiling project

LjNetworkManagerTests uses LJAFNetworkingManager. LJAFNetworkingManager uses the dynamic library AFN. LjNetworkManagerTests does not know the location of AFN. Therefore, an error

  • Tell LjNetworkManagerTests what to useLocation of the AFN dynamic library

  • Failed to run project

Because our LjNetworkManagerTests do not have AFN packages, this problem is similar to the dynamic library link dynamic library we will not say here, you can try it yourself.

LjNetworkManagerTests is a new App. I'm using LjNetworkManagerTests instead of App to make things easier

expand

Podfile imports multiple libraries

We talked about that aboveThe dynamic libraryandStatic librarySo betweenLinks to each otherWe know that we useCocoapods imports AFN through use_frameworks! toDetermines whether to import static or dynamic librariesNow there is a question I would like in the projectImport both dynamic and static librariesWhat should I do

For example, I want AFN to be a static library import and SDWebImage to be a dynamic library import

  • Do the following in your Podfile

When importing a podfile from a third party, we decide to import it as a static library if it is AFN, or as a dynamic library if it is not

Import multiple projects simultaneously through podfile

Testtestis based on Testtestc, and TesttestManager is a third-party library with Podfile

  • We pass LjNetworkManager’sPodfileGo to theAt the same timetoTestOCandLjNetworkManager adds the dependency libraryMake the following changes to the Podfile of LjNetworkManager:

  • Update the Podfile

Simple summary

XCFramework

  • 1.The header file
  • 2.Debug symbols
  • 3.Processing of the same architecture

The project application

  • 1.weak_import:The dynamic library The runtime -> location
  • 2.Static library conflict:App -> all_load\ObjC
  • 3.App -> Dynamic libraries link dynamic libraries -> Pod \ Script replication -> Rexport dynamic libraries
  • 4.App -> Dynamic libraries link static libraries -> Static library code does not want to be exposed -> Hidden - l static library
  • 5.App -> Static libraries link static libraries-> Three elements:1. Name 2. Header file location 3
  • 6.App -> Static libraries link dynamic libraries-> Compile error:Do not know the location of the dynamic library, run error:Dynamic library @rpath -> pod\ script copy

Write in the last

More content, write about a week! I have written more than 5000 words, and I have written them down in detail. I hope you can practice them according to the article. This part is also boring, but it is the way that advanced students must go. Have any question can leave a message below, also hope everybody exchanges a lot, praise!

supplement

You can run man ld, man nm to query the preceding commands