Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a dynamic framework without using a script to strip out simulator slices

I would like to create a dynamic framework and distribute it. It needs to work when running on simulator, an iPhone device, and be able to submit to the App Store.

I am aware of lipo thanks to this guide. It shows how we can combine the simulator architectures with the iphone architectures into a single dynamic framework that can be distributed without distributing the source code. It allows me to use the framework for both simulator and iPhone device. However, it fails when I try to send it to the App Store because of the simulator build.

Carthage provides an interesting solution. It creates a framework that works for both simulator and iPhone. But when it is time to send it to the App Store we need to run a script to rip out the simulator slices.

However, the creators of DoubleClick for Publishers (DFP) have found a way to create a framework that works on both simulator and device; Passes the App Store submission; And doesn't require any script to rip out the simulator slices (AFAIK). All I really have to do is drag the GoogleMobileAds.framework file into Linked Frameworks and Libraries. It is a little surprising that I don't need to add it to Embedded Binaries like most dynamic frameworks)

I created a sample project that uses DFP that demonstrates this.

// clone repository
git clone --recursive https://github.com/wh1pch81n/DoubleClickGoogleExample.git

// Move to correct branch
git submodule foreach 'git checkout master'
git submodule foreach 'git pull origin master' 

Now you can choose the Simulation_mate scheme and run the app. The app will show a single advertisement banner at the bottom to show that the ad is actually working.

The dependency graph looks like this.

Simulation_mate.app
   -> Mate.framework
      -> DFP.framework
         -> GoogleMobileAds.framework

Again, I can run Simulation_mate on simulator, iPhone, and can submit it to the App Store.

My question is how in the world did they create GoogleMobileAds.framework like this? What steps need to be followed to create a framework like this?

like image 522
DerrickHo328 Avatar asked Jan 15 '17 03:01

DerrickHo328


People also ask

What is a dynamic framework?

A dynamic framework is a bundle of code loaded into an executable at runtime, instead of at compile time. Examples in iOS include UIKit and the Foundation frameworks. Frameworks such as these contain a dynamic library and optionally assets, such as images.

Is iOS simulator arm64?

The iOS simulator's architecture is x86_64 (the latest Xcode doesn't support an i386-based simulator that the answer refers to), whereas a real iOS device (such as an iPhone or iPad) can be arm64 or arm64e. So when building an app for the simulator you need to specify x86_64, not an ARM architecture.

What is static framework?

Static framework contain a static library packaged with its resources. Dynamic framework aka Embedded framework - from iOS v8 - contains the dynamic library and resources. In addition to that, dynamic framework can include different versions of the same dynamic library in a single bundle ( versioned bundle ).

How do you add excluded architectures?

You can manually add the Excluded Architecture in your Pod project's Build Settings, but it will be overwritten when you use pod install . In place of this, you can add this snippet in your Podfile . It will write the necessary Build Settings every time you run pod install .


1 Answers

As suspected, the GoogleMobileAds.framework is a static framework, rather than a dynamic framework.

> file GoogleMobileAds
GoogleMobileAds: Mach-O universal binary with 5 architectures: [arm_v7: current ar archive] [arm_v7s] [i386] [x86_64] [arm64]
GoogleMobileAds (for architecture armv7):   current ar archive
GoogleMobileAds (for architecture armv7s):  current ar archive
GoogleMobileAds (for architecture i386):    current ar archive random library
GoogleMobileAds (for architecture x86_64):  current ar archive random library
GoogleMobileAds (for architecture arm64):   current ar archive

Whereas, running file on a dynamic framework, you get a different result:

> file AppKit 
AppKit: Mach-O universal binary with 2 architectures: [i386: Mach-O dynamically linked shared library i386] [x86_64]
AppKit (for architecture i386): Mach-O dynamically linked shared library i386
AppKit (for architecture x86_64):   Mach-O 64-bit dynamically linked shared library x86_64

Unfortunately, the problem you describe is a known limitation of the App Store distribution system. In theory, the correct way to distribute your dynamic framework should be to distribute the full fat binary with all architectures, and let either the build system throw out the the unneeded architectures when building, or let the App Store distribution system do that when slicing the app for specific devices ("slicing"). If I had to guess, the App Store distribution fails with such frameworks due to iOS 8 and below support, since those systems do not support slicing from the App Store.

The reason Google creates static libraries is in order to support iOS 7. A silly reason at this day and age, it has created many issues for developers, since Google also insists on using CocoaPods. Static frameworks, while superficially seem like a silver bullet at first ("no scripts for lipoing out archs; no embedding"), are actually not that great. For instance, if you'd like to include non-compiled resources, a static framework will not do the trick (dynamic frameworks are bundles, while static frameworks are not).

like image 52
Léo Natan Avatar answered Oct 21 '22 10:10

Léo Natan