Author: GSC

I recently encountered a problem in the development of the project. Users reported some screen display abnormalities on the iPhone Xs Max. But I don’t have the phone on hand, and since integrating fluorite Cloud’s SDK, the project can’t be debugable on the emulator. It’s too late to apply for an XS Max, and you can’t just apply for a new phone every time you don’t have one. Then you need to think about how to make the SDK that integrates without emulator support run on the emulator as well, so that you can solve the bugs that arise from the differences between individual models in such projects.

First, when does this problem occur

As mentioned earlier, this problem is caused by the integration of a third party SDK, which does not support emulator running. In fact, the problem is more specific, because this type of SDK does not support x86 compilation, will not be able to test run in the emulator.

Second, the idea of solving this problem.

In fact, the solution to this kind of problem is four words: conditional compilation. Conditional compilation is used to avoid compiling SDKS that do not support x86 in the emulator environment.

For some SDKS, there are two versions, a Release environment and a Debug environment. The Debug environment can be run on the simulator, and for such SDKS, the simulator debugging problem can be solved by replacing the framework of the SDK. Such as Ali Cloud short video SDK, Seven Cattle video playback SDK and so on.

Third, specific solutions to the problem.

We’ll set up a precompiled macro to handle conditional compilation, such as EZDISABLE. Under the Build Settings TAB of Target, we find the Preprocessor Macros TAB and double-click to add EZDISABLE=1. You can add this macro only to Debug or just to Release, depending on your needs. I’m in on all of this.

Here are the calls that will use the SDK that does not support x86, “quarantined” by the EZDISABLE macro. In my project, fluorite cloud’S SDK needs to be “isolated”.

/ / if no EZDISABLE macros defined, compile the following content, otherwise don't compile # # ifndef EZDISABLE # import < EZOpenSDKFramework/EZOpenSDKFramework. H > # endif... . #ifndef EZDISABLE [EZOpenSDK initLibWithAppKey:@" XXXXXX "] #ifndef EZDISABLE [EZOpenSDK initLibWithAppKey:@" XXXXXX "]; #endif }Copy the code

The code may be spread out a lot and need to be patiently removed one by one.

As mentioned above, some SDKS come in two versions: Release and Debug. Debug supports emulator compilation. For this type of SDK, if your SDK is integrated manually, you can replace the SDK one by one manually. If you are using cocoaPods, you will usually only need to modify the references to the **Podfile. I use cocoaPods to integrate the seven Cattle video playback SDK. I’ll change my Podfile to the following:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios.'8.0'
inhibit_all_warnings!
target 'BBTSer' do. . pod"PLPlayerKit".:podspec= >'https://raw.githubusercontent.com/pili-engineering/PLPlayerKit/master/PLPlayerKit-Universal.podspec'	The official version of the simulator provided by Seven Cows can be found on the official website
end
Copy the code

Sometimes, to facilitate code reuse, we make many private Pod sublibraries available for main project integration. What if an SDK like Seven Cows is referenced in one of these private libraries? We can change the SDK references in the main project Podfile without thinking about the sublibraries according to cocoaPods’ rules. CocoaPods handles these dependencies automatically, conveniently.

Fourth, problem optimization.

Above, you’ve basically solved the problem of how to compile on the emulator. We can’t just change our precompiled macros and podfiles every time we switch between the real machine and the emulator.

Specific how to optimize can let us easily switch debugging environment?

For precompiled macro Settings, we can handle this by setting another Target, we copy the project Target, such as the original project Target name: BBTSer. The copied one is renamed: BBTSer Simulator. We just add the precompiled macro EZDISABLE=1 to Preprocessor Macros in the Build Settings TAB of the BBTSer Simulator. Original Target unchanged. If you’re using cocoaPods, you’ll need to modify your Podfile to add support for a new Target after you add it. In this way, the debugging switch between the real machine and the simulator can be handled by switching the Targe mode.

Again, Podfile optimization. As mentioned above, the SDK for Seven Cow officially supports debugging in the simulator, but it is a different POD library address. You need to switch. So how can we make cocoaPod handle this switch in a relatively automatic way? This requires a better understanding of the Podfile syntax. First, we set up two targets above. So Podfile handles integration of both targets at the same time. Then, for different Target may integrate different seven cow SDK address, how to handle this difference when pod install?

For the first question is actually very simple, baidu a lot of ways, not here. The second question needs to be addressed. In podfiles, an error is reported if two or more targets reference the same POD library, but the source file addresses are different. Then we need to add a switch to handle this. If the switch is on, it introduces the normal address, and if the switch is off, it introduces another address. As you can see, Podfile syntax is pretty much Ruby. So, we can add a variable release and then introduce different source addresses by determining whether the release variable is false or true. Thus, our Podfile becomes the following line.

source 'https://github.com/CocoaPods/Specs.git'
platform :ios.'8.0'
inhibit_all_warnings!
# Switch variable
release=false
# abstract_target: abstract target. It contains two targets: BBTSer and BBTSer Simulator. The two targes inherit this abstract target. The name of the abstract target can be defined arbitrarily; in this case, I'll define it as BBT
abstract_target 'BBT' do. .if release then
    target 'BBTSer' do
      pod "PLPlayerKit"
    end
  else
    target 'BBTSer Simulator' do
      pod "PLPlayerKit".:podspec= >'https://raw.githubusercontent.com/pili-engineering/PLPlayerKit/master/PLPlayerKit-Universal.podspec'
    end
  end
end
Copy the code

So at this point, every time we switch between the simulator and the real machine, we just change the state of release to true for the real machine and false for the emulator. Then pod Install or POD Update. You might say, well, that’s not good either. You have to change your Podfile every time. Well, I’ll add a shell script to help us handle this change, instead of changing the Podfile every time you accidentally change it. The shell file is named podinstall.sh. As follows:

#! /bin/bashfile="Podfile" if [ ! -f "$file" ]; Then echo 'exit fi if [! -n "$1"]; Then echo "Enter parameters. Debug "exit FI MODE=$1 if ["$MODE"!= "release"] && ["$MODE"!= "debug"]; Then echo "Enter the correct parameters. For real machine debugging and release to AppStore, please enter release and debug" exit FI echo "for simulator debugging. $MODE" podmodel="release=false" if [ "$MODE" == "release" ]; then podmodel="release=true" fi echo $podmodel# sed -i "s/release=true/$podmodel/g" 
# sed -i ' ' '/release=true/$podmodel/g' $file
sed -i '' "s#release=true#$podmodel#g" $file
sed -i '' "s#release=false#$podmodel#g" $file

#Update pod ConfigurationEcho "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *" echo "* configured, Start Pod integration "echo" * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * "Pod installCopy the code

Use this shell instead every time pod install is performed. Add it to the Podfile file. /podinstall.sh release. Simulator pod calls./podinstall.sh debug. How about that? Is that easier?