跳至主要内容

How to build and use an XCFramework

 原文链接


XCFramework were introduced on wwdc 2019. They allow us to package different architectures of the same module into one entity.

On iOS, frameworks (dynamic or static) and libraries (static only) are two types of module that can be linked to another module, either in a compiled state or not.

Building an XCFramework is a two step process. First the framework or library needs to be compiled from source code. Xcode calls this product an archive. Then the archive is packaged into an XCFramework.

This article will show you how to proceed with both steps.

Why an archive

There are two main reasons for picking an archive (a compiled state of code) over source code.

The most obvious one is when you have no other choice. The framework or library might be from a vendor that only shares the compiled version of their code.

The second reason is to improve compile time. Even though Xcode gets smarter with the years, linking against a non compiled framework or library will increase your app compile time. If your project includes a framework or library that doesn’t change very often, it makes sense to consider compiling it and linking against its archive.

How to archive a framework

iPhone and Simulators run apps on different architectures. When Xcode builds an archive, it builds it for a specific architecture. Therefore if you want to create an XCFramework to run on both iPhone and Simulators, you will need to create two versions of the archive. Here’s the command line for archiving a framework with the iPhone sdk:

xcodebuild archive 
-project SomeFramework.xcodeproj
-scheme SomeFramework
-destination "generic/platform=iOS"
-archivePath "archives/SomeFramework"
SKIP_INSTALL=NO
BUILD_LIBRARY_FOR_DISTRIBUTION=YES

One small edit will archive the framework for the simulators: -destination "generic/platform=iOS Simulator". Notice the BUILD_LIBRARY_FOR_DISTRIBUTION flag. You need it to create a stable Swift module, i.e a module that is compatible with different version of Swift.

How to archive a library

Building an archive for a library is quite similar to the process of archiving a framework. Except if you want to make it available to Swift. Whereas the default option for a framework is to define a module, it is not the case for a library.

Packaging a library into a module requires editing two build settings and adding a build phase:

  • Turn the Define Module setting to YES.
  • Create a module.modulemap (create a new file, pick the empty template) and place it in your library directory. A simple module map file can look like: (see http://clang.llvm.org/docs/Modules.html#module-map-file for documentation on module maps)
module SomeLibrary {
umbrella header "SomeLibrary.h"
export *
}
  • Edit the Module Map setting with your file locationSomeLibrary/module.modulemap. Make sure the module map is in the same directory than the public header files. Or modify the header’s path accordingly.
  • Add a Copy Files build phases and include the umbrealla header and the module map.

After completing these preliminary steps, run the following command line for archiving a library with the iPhone sdk:

xcodebuild archive 
-project SomeLibrary.xcodeproj
-scheme SomeLibrary
-destination "generic/platform=iOS"
-archivePath "archives/SomeLibrary"
SKIP_INSTALL=NO
BUILD_LIBRARY_FOR_DISTRIBUTION=YES

One small edit will archive the library for the simulators: -destination "generic/platform=iOS Simulator".Notice the BUILD_LIBRARY_FOR_DISTRIBUTION flag. You need it to create a stable Swift module, i.e a module that is compatible with different version of Swift.

Why an XCFramework

Or why is an archive not enough.

As mentioned above, Xcode builds an archive for a specific architecture. Therefore an archive could be run on the iPhone or on the simulator but not on both.

One solution is to combine different archives, each supporting a targeted architecture, into one package and let Xcode pick the correct archive at compile time.

Before XCFramework was introduced, developers packaged multiple archives into a so called Fat Framework. This enabled developers to ship only one package, supporting different architectures, but it also meant that it was upon the package users to add a build phase to strip the Fat Framework from not compatible archives.

Apple introduced XCFramework in 2019. XCFramework packages different archives into one xcframework product. On top of that, XCFramework format is supported by Xcode, removing the need to manually strip out not compatible archives during a build phase. Xcode takes care of it automatically.

How to build an XCFramework

You can create an archive by running a command line, as shown above. Or you can use Xcode interface. At the time of this writing, Xcode doesn’t provide any graphical interface to create an XCFramework. You are left with the command line (official documentation):

xcodebuild -create-xcframework
-framework "archives/SomeFramework-Sim.xcarchive/Products/Library/Frameworks/SomeFramework.framework"
-framework "archives/SomeFramework.xcarchive/
Products/Library/Frameworks/SomeFramework.framework"
-output "xcframeworks/SomeFramework.xcframework"

It takes as input all your targeted architectures archives. If you have archived a library instead of a framework, simply change -framework with -library .

How to use an XCFramework

Drag and drop your .xcframework into the Frameworks, Libraries, and Embedded Content section of your target’s General tab.

Now is time to tell Xcode where to look for the module.

If your XCFramework includes a framework, edit the Framework Search Paths setting.

If your XCFramework includes a library, edit the Header Search Paths and Library Search Paths . If you link against a library that is not part of the same repo, you will need to copy over the public header files as well (in addition of the XCFramework of course!).

That’s it, you can now call your framework or library from another module. I hope that after reading this tutorial, you have acquired a better understanding of why you should consider using XCFramework and how to build them.

评论

此博客中的热门博文

Resolving errSecInternalComponent errors during code signing

原文链接 One code signing issue I commonly see, both here on DevForums and in my Day Job™ with DTS, is that the codesign command fails with errSecInternalComponent. This issue crops up in a wide variety of circumstances and the correct fix depends on the specific problem. This post is my attempt to clarify the potential causes of this error and help folks resolve it. If you have any questions or comments about this, please start a new thread, tagging it with Code Signing so that I see it. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Resolving errSecInternalComponent errors during code signing In some circumstances the codesign command might fail with the error errSecInternalComponent. For example: % codesign -s "Apple Development" "MyTrue" MyTrue: errSecInternalComponent This typically affects folks who are signing code in a nonstandard environm...

iOS:检测使用VPN或Proxy

参考链接: https://www.jianshu.com/p/c3b950dbf86a https://gist.github.com/PramodJoshi/4faad4c91f7dcb4eb9b06be8390c01db http://noodlecode.net/2018/04/check-if-ios-app-is-connected-to-vpn 第一种方法 需要导入框架CFNetwork 然后,这个方法是mrc的:需要添加-fno-objc-arc的flag 代码如下: + ( BOOL )getProxyStatus { NSDictionary *proxySettings = NSMakeCollectable ([( NSDictionary *) CFNetworkCopySystemProxySettings () autorelease]); NSArray *proxies = NSMakeCollectable ([( NSArray *) CFNetworkCopyProxiesForURL (( CFURLRef )[ NSURL URLWithString: @"http://www.google.com" ], ( CFDictionaryRef )proxySettings) autorelease]); NSDictionary *settings = [proxies objectAtIndex: 0 ]; NSLog ( @"host=%@" , [settings objectForKey:( NSString *)kCFProxyHostNameKey]); NSLog ( @"port=%@" , [settings objectForKey:( NSString *)kCFProxyPortNumberKey]); NSLog ( @"type=%@" , [settings objectForKey:( NSString *)kCFProxyTypeKey]); if ([[settings object...

去广告DNS设置,国内ADGuard DNS方案,手机电脑iOS去广告,保护隐私

 原文链接 之前分享过使用mac系统搭建adguard home,这几个月用下来零零散散基本上也被弃用了。主要原因是因为需要保持电脑一直开机。但是我的电脑是笔记本,存在移动各个地域的情况,也就是说只能够屏蔽电脑自身,对于手机而言不太现实。今天偶然发现dnspod推出了高级版的公共解析。dnspod背靠腾讯云,肯定是合法合规的公共解析服务,这个高级版用起来不错。 国内自己搭建解析服务是违法行为,所以这也是为什么使用dnspod的原因。 后台截图 开始使用 首先我们先进入dnspod的公共解析页面,点击开始使用。 专业版公共解析 dnspod会提供几种预设,我们选择「开发者」即可 开发者 然后你就成功的申请到自己个人使用的dns了! 更新拦截规则 我们可以将常见的广告过滤规则加入到dns中。我们在顶部选项卡中选择「拦截规则」。 拦截规则设置 打开adguard adguard 绑定iOS设备 推荐使用描述文件的方式,删除配置时删除描述文件即可。 描述文件 绑定macOS 推荐使用描述文件的方式,删除配置时删除描述文件即可。 描述文件 mac需要在「系统偏好设置」的「网络」中查看是否正在运行。 代理 如果没有运行需要点击「···」来启动服务。 启动服务 绑定路由器 找到自己路由器的DHCP设置,修改dns,然后记得绑定自己的ip。 修改dns 绑定ip 费用 目前有300万次/月的免费额度,但没有超出之后的价格。300万次一个人比较难用完,可以放心使用。 我个人使用iOS设备两台、智能家居、电脑两台,日均请求数大致2万/日。 判断是否搭建成功 可以通过查看日志的方式,日志大概有半小时到一小时的延迟,请耐心等待。