iOS - swift 后使用打包动态库
WWDC2014上发布的Xcode6 beta
版有了不少更新,其中令我惊讶的一个是苹果在iOS上开放了动态库,在Xcode6 Beta
版的更新文档中是这样描述的:
Frameworks for iOS. iOS developers can now create dynamic frameworks. Frameworks are a collection of code and resources to encapsulate functionality that is valuable across multiple projects. Frameworks work perfectly with extensions, sharing logic that can be used by both the main application, and the bundled extensions.
详情见官方文档New Features in Xcode 6 Beta。
framework是Cocoa/Cocoa Touch程序中使用的一种资源打包方式,可以将将代码文件、头文件、资源文件、说明文档等集中在一起,方便开发者使用,作为一名Cocoa/Cocoa Touch程序员每天都要跟各种各样的Framework打交道。Cocoa/Cocoa Touch开发框架本身提供了大量的Framework,比如Foundation.framework/UIKit.framework /AppKit.framework等。需要注意的是,这些framework无一例外都是动态库。
但残忍的是,Cocoa Touch上并不允许我们使用自己创建的framework。不过由于framework是一种优秀的资源打包方式,拥有无穷智慧的程序员们便想出了以 framework的形式打包静态库的招数,因此我们平时看到的第三方发布的framework无一例外都是静态库,真正的动态库是上不了 AppStore的。
WWDC2014给我的一个很大感触是苹果对iOS的开放态度:允许使用动态库、允许第三方键盘、App Extension
等等,这些在之前是想都不敢想的事。
iOS上动态库可以做什么
和静态库在编译时和app代码链接并打进同一个二进制包中不同,动态库可以在运行时手动加载,这样就可以做很多事情,比如:
- 共享可执行文件
在其它大部分平台上,动态库都可以用于不同应用间共享,这就大大节省了内存。从目前来看,iOS仍然不允许进程间共享动态库,即iOS上的动态库只能是私有的,因为我们仍然不能将动态库文件放置在除了自身沙盒以外的其它任何地方。
不过iOS8上开放了App Extension
功能,可以为一个应用创建插件,这样主app和插件之间共享动态库还是可行的。
2014-6-23修正:
经@唐巧_boy提醒,sandbox会验证动态库的签名,所以如果是动态从服务器更新的动态库,是签名不了的,因此应用插件化、软件版本实时模块升级等功能在iOS上无法实现。
创建动态库
1、创建动态库
- 创建工程文件
在下图所示界面能够找到Cocoa Touch动态库的创建入口:
跟随指引一步步操作即可创建一个新的动态库工程,我的工程名字叫Dylib,Xcode会同时创建一个和工程target同名的.h文件,比如我的就是Dylib.h。
- 向工程中添加文件
接下来就可以在工程中随意添加文件了。我在其中新建了一个名为Person的测试类,提供的接口如下:
1 |
|
对应的实现部分:
1 |
|
- 设置开放的头文件
一个库里面可以后很多的代码,但是我们需要设置能够提供给外界使用的接口,可以通过Target—>Build Phases—>Headers来设置,如下图所示:
我们只需将希望开放的头文件放到Public列表中即可,比如我开放了Dylib.h
和Person.h
两个头文件,在生成的framework的Header目录下就可以看到这两个头文件,如下图所示:
一切完成,Run以后就能成功生成framework文件了。
2、通用动态库
经过第一步我们只是创建了一个动态库文件,但是和静态库类似,该动态库并同时不支持真机和模拟器,可以通过以下步骤创建通用动态库:
- 创建Aggregate Target
按下图所示,在动态库工程中添加一个类型为Aggregate的target:
按提示一步步操作即可,我给Aggregate
的Target的命名是CommonDylib
。
- 设置Target Dependencies
按以下路径设置CommonDylib
对应的Target Dependencies
:
1 |
|
将真正的动态库Dylib Target添加到其中。
- 添加Run Script
按以下路径为CommonDylib
添加Run Script
:
1 |
|
添加的脚本为:
1 |
|
添加以后的效果如图所示:
该脚本是我根据一篇文章中介绍的脚本改写的,感谢原文作者。
脚本的主要功能是:
1.分别编译生成真机和模拟器使用的framework; 2.使用lipo命令将其合并成一个通用framework; 3.最后将生成的通用framework放置在工程根目录下新建的Products目录下。
如果一切顺利,对CommonDylib
target执行run操作以后就能生成一个如图所示的通用framework文件了:
使用动态库
添加动态库到工程文件
经过以上步骤的努力,生成了最终需要的framework文件,为了演示动态库的使用,新建了一个名为FrameworkDemo
的工程。通过以下方式将刚生成的framework添加到工程中:
1 |
|
同时设置将framework作为资源文件拷贝到Bundle中:
1 |
|
如图所示:
仅仅这样做是不够的,还需要为动态库添加链接依赖。
自动链接动态库
添加完动态库后,如果希望动态库在软件启动时自动链接,可以通过以下方式设置动态库依赖路径:
1 |
|
由于向工程中添加动态库时,将动态库设置了Copy Bundle Resources,因此就可以将Runpath Search Paths
路径依赖设置为main bundle,即沙盒中的FrameworkDemo.app目录,向Runpath Search Paths
中添加下述内容:
1 |
|
如图所示:
其中的@executable_path/
表示可执行文件所在路径,即沙盒中的.app目录,注意不要漏掉最后的/
。
如果你将动态库放到了沙盒中的其他目录,只需要添加对应路径的依赖就可以了。
需要的时候链接动态库
动态库的另一个重要特性就是即插即用
性,我们可以选择在需要的时候再加载动态库。
- 更改设置
如果不希望在软件一启动就加载动态库,需要将
1 |
|
中Dylib.framework
对应的Status由默认的Required
改成Optional
;或者更干脆的,将Dylib.framework
从Link Binary With Libraries
列表中删除即可。
- 使用dlopen加载动态库
以Dylib.framework
为例,动态库中真正的可执行代码为Dylib.framework/Dylib
文件,因此使用dlopen时如果仅仅指定加载动态库的路径为Dylib.framework
是没法成功加载的。
示例代码如下:
1 |
|
以dlopen方式使用动态库不知道是否能通过苹果审核。
- 使用NSBundle加载动态库
也可以使用NSBundle来加载动态库,实现代码如下:
1 |
|
使用动态库中代码
通过上述任一一种方式加载的动态库后,就可以使用动态库中的代码文件了,以Dylib.framework
中的Person
类的使用为例:
1 |
|
注意,如果直接通过下属方式初始化Person
类是不成功的:
1 |
|
监测动态库的加载和移除
我们可以通过下述方式,为动态库的加载和移除添加监听回调:
1 |
|
github上有一个完整的示例代码,
从这里看出,原来就算空白工程软件启动的时候也会加载多达一百二十多个动态库,如果这些都是静态库,那该有多可怕!!
Demo
本文使用的例子已经上传到github上,需要的朋友请自取。
另外,本文对某些东西可能有理解错误的地方,还请指出。
参考文档:
iOS - swift 后使用打包动态库的更多相关文章
- 使用XCode7打包动态库(Framework)
iOS中的静态库和动态库 概念 静态库(Static Library)以 .a 为后缀,它是你的源码的实现.m文件编译而成的二进制文件集合,需要配合上暴漏的.h文件使用,它在引用链接时拷贝至可执行文件 ...
- iOS 获取真机上系统动态库文件
iOS 获取真机上所有系统库文件 系统动态库文件存放真机地址(/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64) 在Mac\i ...
- iOS 静态库,动态库与 Framework 浅析
静态库与动态库的区别 首先来看什么是库,库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别人使用. 什么时候我们会用到库呢?一种情况是某些代码需要给别人使用,但是我们不希望别人 ...
- ios 开发中 动态库 与静态库的区别
使用静态库的好处 1,模块化,分工合作 2,避免少量改动经常导致大量的重复编译连接 3,也可以重用,注意不是共享使用 动态库使用有如下好处: 1使用动态库,可以将最终可执行文件体积缩小 2使用动态库, ...
- iOS 静态库和动态库的区别&静态库的生成
linux中静态库和动态库的区别 一.不同 库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行.库分静态库和动态库两种. 1. 静态函数库 这类库的名字一般是libxxx.a:利用静态函 ...
- iOS 动态库、静态库 . framework 总结(2017.1.25 修改)
修改于2017.1.25 使用Xcode Version 8.2.1 1.怎么创建.framework? 打开Xcode, 选择File ----> New ---> Project 选择 ...
- Unity跨平台C/CPP动态库编译---可靠UDP网络库kcp基于CMake的各平台构建实践
1.为什么需要动态库 a)提供原生代码(native code)的支持,也叫原生插件,但是我实践的是c/cpp跨平台动态库,这里不具体涉及安卓平台java库和ios平台的objectc库构建. b)某 ...
- C 语言与动态库相关基础知识
1.导入文件<>和“”的区别 #include <xxx.h>导入的是标准目录下的.h文件,所谓的标准目录指的是:/use/local/include(一般是第三方头文件)以及 ...
- Unity3D跨平台动态库编译---记kcp基于CMake的各平台构建实践
一 为什么需要动态库 1)提供原生代码(native code)的支持,也叫原生插件,但是我实践的是c/cpp跨平台动态库,这里不具体涉及安卓平台java库和ios平台的objectc库构建. 2)某 ...
随机推荐
- JAVA:使用栈实现一个队列
使用栈实现一个队列,需要弄清楚栈和队列的区别: 栈:先进后出: 队列:先进先出. 实现思路: 1)通过两个栈(pushStack / popStack)对倒,确保 popStack 栈的出栈顺序与队列 ...
- 微信公众号开发系统入门教程(公众号注册、开发环境搭建、access_token管理、Demo实现、natapp外网穿透)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/a1786223749/article/ ...
- LinQ中List,取某个字段,然后用逗号拼接
string htDetails = string.Join(",", DemoList.Select(t => t.id).Distinct().ToArray());
- ADB命令使用大法
前言 Android开发调试工具ADB的使用.ADB(Android Debug Bridge)是Android SDK中的一个工具, 使用ADB可以直接操作管理Android模拟器或者真实的And ...
- Oracle表存在则删除后再重建
简单的执行方式: drop table USERINFO; create table USERINFO ( EnglishName ), ChineseName ), Sex ), Age int, ...
- 使用Termux,在手机上做nodejs编程,运行nodejs程序。
如果你是一名nodejs开发者,是否想过以下问题:在手机上运行nodejs程序?用手机当nodejs服务器?在手机上做nodejs编程?YES!使用Termux,以上都可以做到! 下面展示如何实现这个 ...
- [LeetCode] 151. Reverse Words in a String 翻转字符串中的单词
Given an input string, reverse the string word by word. For example,Given s = "the sky is blue& ...
- 密码工具:KeePassXC
KeePassXC 开源免费 只支持数据库存放在本地, 跨平台 自动填充 使用浏览器插件时,软件必须启动着 KeePassXC is a community fork of KeePassX, a n ...
- Python 内置函数--super()
描述 super() 函数是用于调用父类(超类)的一个方法. super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO).重复 ...
- 系统中提示未找到/usr/bin/ld: cannot find -lxxx错误的通用解决方法
在linux环境编译应用程式或lib的source code时常常会出现如下的错误讯息: 代码如下: /usr/bin/ld: cannot find -lxxx 这些讯息会随着编译不同类型的sour ...