Xcode7 Framework探索

在设计SDK或其它框架的时候,我们大多数不想将自己的源码暴露给别人。在iOS中可行的办法有静态库和静态Framework(虽然苹果今年来开放了动态Framework,但是目前项目中用的最多还是前面两种)。最开始在Xcode中制作静态Framework是很麻烦的,制作静态库要简单的多,毕竟Xcode带了这样一选项。但是使用Xcode6或7的时候发现自带了和静态库制作一样的功能,因此制作动态库已经很简单了。

1. Framework静态库

其中最重要的设置就是将Mach-O Type设为Static Library,因为默认创建Framework的时候是动态库Dynamic Library类型。

步骤
a. 点击创建Framework选项

1.png

b. 设置Mach-O Type为Static Library。(如果要支持bitcode, 还需要在TAGETS的Build setting中搜索Other C Flags,添加命令“-fembed-bitcode”)。

24543C0F-87D3-4673-BDD3-3C50B1C097E1.png
C8929E52-A3B6-4481-8978-A4CC69D94EA5.png

如果没有加cflags可能在使用的时候出现以下错误:


3957B515-0B53-496A-B099-5F1ECD334E77.png

c. 设置头文件类型。(Public(公共的),这里存放供其他人查看的header。Private(私有的)这里存放私有的Header,以上两个Headers存放位置都会暴露出来,所有人可以查看。有些Header是不想给别人看到的。这种header放在第三个类Project中。设置的时候直接将工程中的头文件拖到对应的区域)。如果你用了Category,别人在用你的Framework时会发生崩溃。这时别人在引用时需要在工程中other linker flags中添加-objC如果依然有问题,再添加-all_load。

757C152E-2C8B-47EE-A424-1D9C832A1F4B.png

d.选择通用iOS设备build

如果需要制作模拟器和真机通用版本的可以使用shell脚本在命令行构建,也可以在Xcode新建个build的target,添加构建脚本。
a. 新建target


FA3219B5-2D38-4BA5-8E32-EA61F3C0735F.png

b. 为target添加Run Script,这样就可以在项目工程文件的Products目录生成通用的静态FrameWork。


0C150FC0-6E11-41E0-9F16-4070E5D485AB.png
# Sets the target folders and the final framework product.
# 如果工程名称和Framework的Target名称不一样的话,要自定义FMKNAME
# 例如: FMK_NAME = "MyFramework"
FMK_NAME=${PROJECT_NAME}

# Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework

# Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework

# -configuration ${CONFIGURATION}
# Clean and Building both architectures.
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos -arch armv7 -arch armv7s -arch arm64 clean build
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator -arch x86_64 clean build

# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ]
then
    rm -rf "${INSTALL_DIR}"
fi

mkdir -p "${INSTALL_DIR}"

cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"

# Uses the Lipo Tool to merge both binary files
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}"

rm -r "${WRK_DIR}"

open "${SRCROOT}/Products/"

echo ${FMK_NAME}

c. 查看库的架构可以通过file或者lipo命令来查看

BE5F7DE5-962F-4C78-963D-D1B21A874DD9.png

在使用的时候(链接状态为Required),我们通过MachOView查看可执行文件,并不能看见动态链接了我们的FrameWork,因为静态库编译进了二进制可执行文件中,并不需要动态链接。


7C928AAD-0F66-4A00-92FA-97D19F2C6A68.png

2. Framework动态库

默认情况下如果我们不强制设置Mach-O Type为Static Library,那么编译出来Framework就是动态库。

a. 使用Xcode自动链接动态Framework。此时我们只需要在Embedded Binaries中添加需要使用的动态Framework,如下图:


EF75F2CF-B8BC-4F7C-ABED-12A43559407C.png

添加之后在Build Phases中会多出一项Embed Fraworks,它的作用也就是拷贝动态库到Runpath Search Paths目录。


FA54044E-9958-4D97-AB27-4D23F73B11B6.png

至于app运行的时候如何找到动态库,我们可以设置Runpath Search Paths路径。默认会在@executable_path/Frameworks目录中找,@executable_path/表示可执行文件所在路径,即沙盒中的.app目录,注意不要漏掉最后的/。


FE464BE5-93B6-436D-B173-A3C1F3D06D5E.png

编译好,进入到生成的.app文件的根目录,发现Framework已经拷贝到了Frameworks目录(Runpath Search Paths路径)。


7A1C1BF9-71EA-4FF0-B71A-84C9C540642D.png

通过MachOView查看可执行文件,这时候发现程序需要动态链接我们刚创建的Framework。


378BD826-9F2A-4F16-91DE-7A1634A4525C.png

在使用的过程中如果出现ld: warning: embedded dylibs/frameworks only run on iOS 8 or later警告,这是因为工程默认编译设置的是Dynamic Framework。这种编译只有在iOS8以后才能使用,因此需要设置工程最低支持iOS8.0


68611C0C-A325-44DB-852E-31C58747E98F.png

b. dlopen或NSBundle加载动态库
动态库中真正的可执行代码为KGSDK.framework/KGSDK文件,因此使用dlopen时如果仅仅指定加载动态库的路径为KGSDK.framework是没法成功加载的。使用时将动态库传到特定目录,然后手动加载,最后用runtime来执行相关操作。

- (IBAction)clickButton:(id)sender
{
    NSString *documentsPath = [NSString stringWithFormat:@"%@/Documents/KGSDK.framework/KGSDK",NSHomeDirectory()];
    [self openDylibWithPath:documentsPath];
}

- (void)openDylibWithPath:(NSString *)path
{
    void* libHandle = NULL;
    libHandle = dlopen([path cStringUsingEncoding:NSUTF8StringEncoding], RTLD_NOW);
    if (libHandle == NULL) {
        char *error = dlerror();
        NSLog(@"dlopen error: %s", error);
    } else {
        NSLog(@"dlopen load framework success.");
    }
}
- (void)openDylib
{
    NSString *documentsPath = [NSString stringWithFormat:@"%@/Documents/KGSDK.framework",NSHomeDirectory()];
    NSError *err = nil;
    NSBundle *bundle = [NSBundle bundleWithPath:documentsPath];
    if ([bundle loadAndReturnError:&err]) {
        NSLog(@"bundle load framework success.");
    } else {
        NSLog(@"bundle load framework err:%@",err);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • 静态库与动态库的区别 首先来看什么是库,库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别...
    吃瓜群众呀阅读 11,871评论 3 42
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,431评论 25 707
  • 仅以方便自己查阅记录前言1.静态库和动态库有什么异同?静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗...
    190CM阅读 4,170评论 0 4
  • 周末一直到昨天都为儿子忙了,复盘停了两天。总算告一段落了,接下来就等着周末儿子回来了,对于初中就让儿子住宿,起初很...
    王沐妍阅读 236评论 0 0