iOS 创建Framework

framework瘦身:

(1)设置Generate Debug Symbols 为NO. 可以减少30%左右的体积
(2)设置Optimization Level下的Release模式为:Fastest,Smallest[-Os] .这是Xcode上默认的,但我们要知道,意思是开启不增加代码大小的全部优化,并让可执行文件尽可能小.3M减到了1.8M.
(3)删除无用代码,设置Dead Code Stripping为YES,去掉冗余代码即代码被定义但未被使用
(4)在Architectures中加入了armv7s. 现在我将armv7s删除,重新编译,可以减少三分之一的体积..framework包由原来的1.8M减到1.2M.
指令集:armv6 : iPhone,iPhone2,iPhone3G,第一代和第二代iPod Touch; armv7:iPhone4,iPhone4S; armv7s:iPhone5,iPhone5C; arm64:iPhone5S
指令集是向下兼容的,所以设置了arnv7是可以在armv7s的设备上运行的.
(5),删除framework中无用mach.(注:由于本人很懒,该方法没试过,不过该方法是可信的).http://www.zhimengzhe.com/IOSkaifa/29958.html
(6)自己封装,尽量不要用第三方的.http://blog.csdn.net/a2657222/article/details/45723161
(7)使用HTML5来替换原生的页面

注意

1.调用了Category中的方法,程序直接出现了Unrecognized selector sent to instance 0x10008c098的错误,这时我们需要在引用我们.framework的工程中设置 Build Pharse -> Other Linker Flags中加上 -all_load
2. 导入所有要打包的文件和其他第三方静态库
正常导入要打包的文件就可以了,在导入第三方静态库的时候要注意,不要选择添加到target中,如果添加进去要去target里面把第三方静态库删掉(只需导入,不要添加进target)

这里写图片描述

3.swift要开放的类和方法前要用public
4.图片使用方法:
let image = UIImage(named:"XHWLCoreSDK.framework/RemoteOpenDoor.bundle/scan_back")

一、使用脚本一键构建通用版本的framework(真机、模拟器通吃的版本)

步骤如下:

1.build active architecture only设置为No
这里写图片描述

2.新建一个target,用来构建通用版本framework
这里写图片描述

3.选择Cross-platform->other->Aggregate->Next
这里写图片描述

4.命名为univeralBuilder,新建一个New Run Script Phase
这里写图片描述

5.在shell里面添加以下内容,注意将第九行的FRAMEWORK_NAME改为自己framework的名字。

# Merge Script

# 1
# Set bash script to exit immediately if any commands fail.
set -e

# 2
# Setup some constants for use later on.
FRAMEWORK_NAME="Your framework name" 

# 3
# If remnants from a previous build exist, delete them.
if [ -d "${SRCROOT}/build" ]; then
rm -rf "${SRCROOT}/build"
fi

# 4
# Build the framework for device and for simulator (using
# all needed architectures).
xcodebuild -target "${FRAMEWORK_NAME}" -configuration Release -arch arm64 -arch armv7 -arch armv7s only_active_arch=no defines_module=yes -sdk "iphoneos"
xcodebuild -target "${FRAMEWORK_NAME}" -configuration Release -arch x86_64 -arch i386 only_active_arch=no defines_module=yes -sdk "iphonesimulator"

# 5
# Remove .framework file if exists on Desktop from previous run.
if [ -d "${HOME}/Desktop/${FRAMEWORK_NAME}.framework" ]; then
rm -rf "${HOME}/Desktop/${FRAMEWORK_NAME}.framework"
fi

# 6
# Copy the device version of framework to Desktop.
cp -r "${SRCROOT}/build/Release-iphoneos/${FRAMEWORK_NAME}.framework" "${HOME}/Desktop/${FRAMEWORK_NAME}.framework"

# 7
# Replace the framework executable within the framework with
# a new version created by merging the device and simulator
# frameworks' executables with lipo.
lipo -create -output "${HOME}/Desktop/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${SRCROOT}/build/Release-iphoneos/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${SRCROOT}/build/Release-iphonesimulator/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}"

# 8
# Copy the Swift module mappings for the simulator into the
# framework.  The device mappings already exist from step 6.
cp -r "${SRCROOT}/build/Release-iphonesimulator/${FRAMEWORK_NAME}.framework/Modules/${FRAMEWORK_NAME}.swiftmodule/" "${HOME}/Desktop/${FRAMEWORK_NAME}.framework/Modules/${FRAMEWORK_NAME}.swiftmodule"

# 9
# Delete the most recent build.
if [ -d "${SRCROOT}/build" ]; then
rm -rf "${SRCROOT}/build"
fi

3.最后一步:选择Aggregate target和Simulator然后build,你会看到桌面由构建好通用版本的framework。
参考资料:http://arsenkin.com/ios-universal-framework.html

Update

As pointed out by @Indigo333 - before submitting your app to the AppStore we need to get rid of the simulator binaries that our “fat” framework is going to hold.
In order to do that, you have to create another New Run Script Phase as we did before, but this time in the project you are about to upload into AppStore. Create one and paste this script, written by Daniel Kennett. Now, it is important to note that this script is going to work only if you have your project built without Bitcode support.

APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"

# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
    FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
    FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
    echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"

    EXTRACTED_ARCHS=()

    for ARCH in $ARCHS
    do
        echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
        lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
        EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
    done

    echo "Merging extracted architectures: ${ARCHS}"
    lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
    rm "${EXTRACTED_ARCHS[@]}"

    echo "Replacing original executable with thinned version"
    rm "$FRAMEWORK_EXECUTABLE_PATH"
    mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"

done

After pasting this, each time you are going to Build your project this script will run through framework you included and strip-out binaries for architectures that are not being using.

二、普通构建framework

新建项目选择Cocoa Touch Framework项目,取名为BookRoomKit,选择Swift语言

这里写图片描述

然后新建一个BookRoomManager单例类用来传值设置,并且需要申明为public,这样我们才能够在其他项目上使用我们提供的framwork的代码;

编译framework;我这里以真机发布版本framework的为例。
首先使用Product->Scheme->Edit Scheme 打开如下界面,设置为Release环境,
这里写图片描述

然后按照下图选择,第1步代表真机运行,第2步运行,第3步代表编译成功的BookRoomKit.framework;
这里写图片描述

选中BookRoomKit.framework,右击Show inFinder,会显示编译好的framework在finder中的位置,如下图:
这里写图片描述

三、Framework合并

使用lipo -info查看framework支持的cpu架构,分别对应真机版本和模拟器版本的framework信息
这里写图片描述
使用lipo -create指令将模拟器和真机的framework合并成通用版本
这里写图片描述
具体操作如下:首先,切换到/BookRoomKit/Build/Products;然后执行lipo -create -output [name] [path1] [path2]这条命令;执行完成后在Products目录下生成一个BookRoomKit文件。
这里写图片描述
这里写图片描述
然后将上图红圈的文件复制到Release-iphoneos中去覆盖原来的版本,最后将Release-iphonesimulator中的框架文件里的/Modules/BookRoomKit.swiftmodule里的文件复制到Release-iphoneos对应的文件夹下。这样我们就得到了一个通用的的框架
这里写图片描述
最后用这个framework替换掉测试工程的framewotk就可以在真机和模拟器运行了

四、Framework中使用image,xib,storyboard,font等资源文件

image, xib,storyboard都是需要传递相应的bundle。而我看到网上一些旧的教程都很繁琐,还要建立什么resources.bundle之类的。经过我的实践,我这种方法更为简单。

let bundle = Bundle(identifier: "xcqromance.BookRoomKit") // framework的bundle ID

storyboard的加载,xib类似

let sb = UIStoryboard(name: "BookHome", bundle: bundle)
 let vc = sb.instantiateViewController(withIdentifier: "BookViewController") as! BookViewController
 viewController.navigationController?.pushViewController(vc, animated: true)

image的加载

let image = UIImage(named: "bookroom_down_bg_blue", in: bundle, compatibleWith: nil)
let imageView = UIImageView(image: image)

font的加载则是比较麻烦,得先注册,才能使用!所以我写了个OC的NSObject分类

+ (UIFont *) loadMyCustomFont:(NSString *)name size: (CGFloat)size type: (NSString *)type {
  NSString *fontPath = [[NSBundle bundleWithIdentifier:@"xcqromance.BookRoomKit"] pathForResource:name ofType:type];
  NSData *inData = [NSData dataWithContentsOfFile:fontPath];
  CFErrorRef error;
  CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)inData);
  CGFontRef font = CGFontCreateWithDataProvider(provider);
  if (! CTFontManagerRegisterGraphicsFont(font, &error)) {
    CFStringRef errorDescription = CFErrorCopyDescription(error);
    NSLog(@"Failed to load font: %@,%@", errorDescription,name);
    CFRelease(errorDescription);
  }
  CFRelease(font);
  CFRelease(provider);
  NSString *fontName = (__bridge NSString *)CGFontCopyPostScriptName(font);
  UIFont* uifont = [UIFont fontWithName:fontName size:size];
  return uifont;
}

然后在单例模初始化的时候进行注册。使用这个字体的方法和平时的一样,将fontName传递下就可以了

let label = UILabel()
label.text = "hello word"
label.sizeToFit()
label.center = view.center
label.font = UIFont(name: "Kreon-Bold", size: 17)

五、使用三方导库

有两种方法引入:第一:在壳工程中使用pods、carhtage第三方库管理工具来添加;第二:直接将依赖的framework拖入壳工程。其实这两种方式的本质都是一样的,都有一个很关键的点就是Framework 的Build Settings中设置好依赖的第三方库的Framework Search Paths,同时在Build Phases的Link Binary With Binaries添加依赖的第三方库,
将下载好的ZipArchive.framework拖入壳工程,记得勾选Copy items if needed,此时你在壳工程就已经能够使用这个库了,这是因为你拖入第三库ZipArchive时Xcode已经给你配置好Framework Search Paths,你可以在壳工程的builds settings搜索到。如下图:
这里写图片描述
但是你此时在壳工程中使用ZipArchive.framework,运行起来是会crash的,奔溃信息和前文一张名为奔溃信息日志的图片是一样的,

dyld: Library not loaded: @rpath/ZipArchive.framework/ZipArchive
  Referenced from: /var/containers/Bundle/Application/74F5D1D3-D6B5-4C68-9629-9CAF6C16F133/BookRoomDemo.app/BookRoomDemo
  Reason: image not found

所以解决方案也就是一样的,在EmbeddedBinaies中添加ZipArchive.framework。

设置BookRoomKit.xcodeproj的framework Search Paths
路径务必填写正确,我写的相对路径:$(PROJECT_DIR)/../BookRoomDemo/BookRoomDemo
这里写图片描述
BookRoomKit.xcodeproj的Link Binary With Binaries添加ZipArchive.framework,选在Add Other,添加进来即可。
接下来你就可以在BookroomKit使用ZipArchive了,具体代码你可以在BookRoomDemo下载。

六、使用

接下来我们新建一个壳工程,也就是测试工程,用来使用BookRoomKit.framework;并且命名为BookRoomDemo,如下图:
这里写图片描述
将BookRoomKit.framework拖入项目中,勾选下面三项,然后点击Finish
这里写图片描述
这里就涉及一个问题,那就是我之前的一步操作是直接从Finder中将framework拖拽进壳工程项目的,这样操作默认会将framework放置在Linked Frameworks and Libraries下面,如下图;
这里写图片描述
编写代码前,记得将壳工程切换为release环境,然后真机运行,因为编译的framework必须与壳工程运行的环境一致才能够运行成功。
这里写图片描述

猜你喜欢

转载自blog.csdn.net/weixin_40873814/article/details/78801339