- 启动流程 & 优化
- 启动监控
- 启动屏广告
- 闪屏广告
启动流程 & 优化
APP启动可以分成三个阶段:main函数执行前,main函数执行后,首屏渲染完成后。
main函数执行前
main函数执行前,系统会加载二进制文件(APP的.o文件集合),动态链接,初始化runtime,加载一些类等操作,简而言之就是IOS执行了APP的装载和链接等工作。想让APP启动快,在此期间可以减少动态链接库的数量(苹果支持最多6个非系统提供的动态链接库合并成1个),减少启动后不使用的类和方法。
main函数执行后
main函数就是创建一个UIApplication对象(内含系统功能)和一个UIApplicationDelegate(程序员在里面实现业务逻辑):
#import <UIKit/UIKit.h> #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
创建一个UIApplication对象用于处理APP生命周期,内存告警,UI展示,方向,openURL等,可以用UIApplicationDelegate获得这些功能的控制权。
APP的生命周期有:
Not running:未启动
Inactive:过渡的中间状态,除启动时外,还有双击home键,出现应用列表,此时APP既不是前台运行,也不是进入后台
Active:运行中,系统会分配更多的资源
Background:系统分配较少资源
Suspended:内存不足,系统kill APP
UIApplicationDelegate中可以获得这些生命周期的控制权:
main函数执行后,是从main函数开始执行到delegate提供的didFinishLaunchingWithOptions生命周期回调执行结束。想让APP启动快,在此期间可以针对业务进行梳理,将那些直到开始使用才需要初始化的功能剔除出去。
首屏渲染完成后
首屏渲染完成后主要是,非首屏其他业务服务模块的初始化,注册,配置文件的读取等。这个阶段用户已经能看到首屏了,所以主要处理的是会卡住主线程的操作,以免影响用户交互。
启动监控
上面写的感觉写了和没写一样,具体还是要靠系统工具为我们提供分析报告。可以用xcode的Time Profiler工具,它的原理是:定时(设成0.01s,太长不精确,太短本身又耗性能)抓取主线程上的方法调用堆栈,计算一段时间里各个方法的耗时。
如果对检查精度要求较高,也可以自己hook一下objc_msgSend方法来掌握所有方法的执行耗时。它的原理是:objc_msgSend是Objective-C所有方法的必经之路。
当然objc_msgSend本身是汇编语言写的(因为所有方法都会调用,所以要保证最高的性能要求),改造门槛高。内部逻辑是:先获取对象的对应类的信息,再获取方法的缓存,根据方法的selector查找函数指针,经过异常错误处理后,最后跳到对应函数的实现。
启动屏广告
在main函数执行前,IOS启动APP时有个系统提供的启动屏(Launch Screen),等系统ready后,启动屏自动消失,执行main函数,显示APP的业务首屏。
可以将启动屏(Launch Screen)贴张广告图片增加收入:
1.删除项目中的默认的LaunchScreen.storyboard文件
2.删除项目中info.plist里的【Launch screen interface file base name】:【LaunchScreen】字段
3.点击项目名,进入General tab,点击【App Icons and Launch Images】的【Use Asset Catalog】,弹出窗点击【Migrate】。在项目的Assets.xcassets里就会出现LaunchImage的配置。
4.勾上为iPhone配置启动图的配置项
5.将不同尺寸的广告图片拖进Assets.xcassets中对应的机型中。
这样启动屏(Launch Screen)就能显示我们添加的广告图片了。
闪屏广告
随着IOS速度越来越快,启动屏时间变的越来越短。所以光靠启动屏不能满足日常广告的曝光时长。
现在的做法是:启动屏(Launch Screen)仍旧贴广告图片,等启动屏消失后,APP的首屏UIWindow里addSubView显示同样的图片,过段时间再让广告图片消失。
这样对用户来说是无感知的,以为广告图片显示的时间变长了。
做法很简单,先创建个UIImageView:
#import "SplashView.h" @interface SplashView() @property(nonatomic, strong, readwrite)UIButton *button; // 广告图片右上角显示【跳过】按钮 @end @implementation SplashView - (instancetype)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { self.image = [UIImage imageNamed:@"icon.bundle/splashscreen.jpg"]; [self addSubview:({ _button = [[UIButton alloc] initWithFrame:CGRectMake(330, 100, 60, 40)]; _button.backgroundColor = [UIColor lightGrayColor]; [_button setTitle:@"跳过" forState:UIControlStateNormal]; [_button addTarget:self action:@selector(_removeSplashView) forControlEvents:UIControlEventTouchUpInside]; _button; })]; self.userInteractionEnabled = YES; } return self; } - (void)_removeSplashView{ [self removeFromSuperview]; } @end
在UIApplicationDelegate的didFinishLaunchingWithOptions生命周期里加上闪屏广告:
#import "SplashView.h" - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... // 添加闪屏 [self.window addSubview:({ SplashView *splashView = [[SplashView alloc] initWithFrame:self.window.bounds]; splashView; })]; return YES; }