ios9/sdk9/xcode7/iphone6s(+)适配
ios9 企业级分发
iOS9网络适配_ATS
为了强制增强数据访问安全,iOS9 默认会把所有从NSURLConnection 、 CFURL 、 NSURLSession发出的 HTTP 请求,都改为 HTTPS 请求:iOS9.x-SDK编译时,默认会让所有从NSURLConnection 、 CFURL 、 NSURLSession发出的 HTTP 请求统一采用TLS 1.2 协议。这一做法,官方文档称为ATS,全称为App Transport Security,是iOS9的一个新特性。
一个符合 ATS 要求的 HTTPS,应该满足如下条件:
Transport Layer Security协议版本要求TLS1.2以上
服务的Ciphers配置要求支持Forward Secrecy等
证书签名算法符合ATS要求等
适配:
方案一:立即让公司的服务端升级使用TLS 1.2,以解析相关数据。要求站点使用支持forward secrecy协议的密码。证书也要求是符合ATS规格的,ATS只信任知名CA颁发的证书。
方案二:虽Apple不建议,但可通过在 Info.plist 中声明,倒退回不安全的网络请求依然能让App访问指定http
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Key
Type
NSAppTransportSecurity
Dictionary
NSAllowsArbitraryLoads
Boolean
NSExceptionDomains
Dictionary
<domain-name-for-exception-as-string>
Dictionary
NSExceptionMinimumTLSVersion
String
NSExceptionRequiresForwardSecrecy
Boolean
NSExceptionAllowsInsecureHTTPLoads
Boolean
NSIncludesSubdomains
Boolean
NSThirdPartyExceptionMinimumTLSVersion
String
NSThirdPartyExceptionRequiresForwardSecrecy
Boolean
NSThirdPartyExceptionAllowsInsecureHTTPLoads
Boolean
另外需要注意的是,即使写了上述配置,在HTTPS页面中,HTTP的javascript或css不会被加载,因为苹果认为这降低了页面的安全性。
https://developer.apple.com/library/prerelease/ios/technotes/App-Transport-Security-Technote/index.html#//apple_ref/doc/uid/TP40016240
https://github.com/ChenYilong/iOS9AdaptationTips#%E4%BB%A3%E7%A0%81%E5%88%9B%E5%BB%BA%E7%9A%84-tableview-%E6%97%A0%E6%B3%95%E9%9A%90%E8%97%8F-cell-%E5%88%86%E5%89%B2%E7%BA%BF
bitcode 是被编译程序的一种中间形式的代码。包含 bitcode 配置的程序将会在 App Store 上被编译和链接。 bitcode 允许苹果在后期重新优化我们程序的二进制文件,而不需要我们重新提交一个新的版本到 App Store 上。
注意以下几点:
- Watch 应用必须包含 bitcode ,iOS不强制,Mac OS不支持。 Xcode7 及以上版本会默认开启 bitcode 。
- 如果应用开启 Bitcode,那么其集成的其他第三方库也需要是 Bitcode 编译的包才能真正进行 Bitcode 编译
- 开启 Bitcode 编译后,编译产生的 .app 体积会变大(中间代码,不是用户下载的包),且 .dSYM 文件不能用来崩溃日志的符号化(用户下载的包是 Apple 服务重新编译产生的,有产生新的符号文件)
- 通过 Archive 方式上传 AppStore 的包,可以在Xcode的Organizer工具中下载对应安装包的新的符号文件
framework支持bitcode:
在TAGETS的Build setting中搜索Other C Flags,添加命令“-fembed-bitcode”。同样的设置在PROJECT中。如果不进行以上操作。别人在集成你的framework时可以编译,亦可以真机测试。唯独在打包时会发出警告并打包失败。警告为framework不支持bitcode!
iOS9 URL Scheme
- (BOOL)canOpenURL:(NSURL *)url NS_AVAILABLE_IOS(3_0);
在 iOS9 之前,你可以使用 canOpenURL: 监测用户手机里到底装没装微信等软件,安装返回YES,
在iOS9中,需要将 "weixin(微信)" 添加到我们app的 info.plist 文件中:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>weixin</string>
</array>
只有LSApplicationQueriesSchemes配置了白名单和安装了才返回YES
如果是用Xcode6编译,系统会在用户手机上记住APP每次调用canOpenUrl的scheme,如果累计达到50种,剩下的其它调用,也会直接返回NO。
- (BOOL)openURL:(NSURL*)url NS_EXTENSION_UNAVAILABLE_IOS("");不受影响
一般修改
if (canOpenUrl(scheme)) then openUrl(scheme);else xxx;
这种只需要改写成
if (!openUrl(scheme)) then xxx;
解决supportedInterfaceOrientations在xcode7和xcode6.4中警告
#if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0
- (NSUInteger)supportedInterfaceOrientations
#else
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
#endif
{
return UIInterfaceOrientationMaskPortrait;
}
字体间隙变大导致 UI 显示异常
iOS8中,字体是Helvetica,中文的字体有点类似于“华文细黑”。只是苹果手机自带渲染,所以看上去可能比普通的华文细黑要美观。iOS9中,中文系统字体变为了专为中国设计的“苹方” 有点类似于一种word字体“幼圆”。字体有轻微的加粗效果,并且最关键的是字体间隙变大了!
所以很多原本写死了width的label可能会出现“...”的情况,如果不将 label 的 width 写死,仅仅添加左端约束则右端的四个数字会越界。
所以为了在界面显示上不出错,就算是固定长度的文字也还是建议使用sizetofit 或者ios向上取整 ceilf() 或者提前计算:
- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(nullable NSDictionary<NSString *, id> *)attributes context:(nullable NSStringDrawingContext *)context NS_AVAILABLE(10_11, 7_0);
- (CGSize)sizeWithAttributes:(nullable NSDictionary<NSString *, id> *)attrs NS_AVAILABLE(10_0, 7_0);
对返回的size使用CGSize adjustedSize = CGSizeMake(ceilf(size.width), ceilf(size.height));
statusbar
这个还好只是报一个警告,如果就是不管他,也不会出现问题。
: CGContextSaveGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
以前我们为了能够实时的控制顶部statusbar的样式,可能会在喜欢使用
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]
[[UIApplication sharedApplication]setStatusBarHidden:YES];
但是这么做之前需要将 info.plist 里面加上View controller-based status bar appearance BOOL值设为NO,就是把控制器控制状态栏的权限给禁了,用UIApplication来控制。但是这种做法在iOS9不建议使用了,建议我们使用吧那个BOOL值设为YES,然后用控制器的方法来管理状态栏:
- (UIStatusBarStyle)preferredStatusBarStyle;
- (UIViewController *)childViewControllerForStatusBarStyle;
- (void)setNeedsStatusBarAppearanceUpdate
点进头文件可以验证刚才说法:
@property(readwrite, nonatomic,getter=isStatusBarHidden) BOOL statusBarHidden NS_DEPRECATED_IOS(2_0, 9_0, "Use -[UIViewController prefersStatusBarHidden]");
在didFinishLaunchingWithOptions结束后还没有设置window的rootViewController会导致崩溃
iOS9 不允许在 didFinishLaunchingWithOptions 结束了之后,还没有设置 window 的 rootViewController 就会crash。 也许是 Xcode7 的编译器本身就不支持。
iOS国际化问题:当前设备语言字符串返回有变化。
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSArray *allLanguage = [defaults objectForKey:@"AppleLanguages"]; NSString *currentLanguage = [allLanguage objectAtIndex:0]; NSLog(@"The current language is : %@", currentLanguage);
iOS 9 之前:以上返回结果:语言字符串代码。例如:"zh-Hans"
iOS 9:以上返回结果:语言字符串代码 + 地区代码。例如:"zh-Hans-US"
备注:
1.请注意判断当前语言类型,不要用以下形式的代码了,不然在iOS9上就会遇到坑。
if ([currentLanguage isEqualToString:@"zh-Hans"])
可以使用:
if ([currentLanguage hasPrefix:@"zh-Hans"])
另外:对于中文,语言有:
简体中文:zh-Hans
繁体中文:zh-Hant
香港中文:zh-HK
澳门中文:zh-MO
台湾中文:zh-TW
新加坡中文:zh-SG
备注:以上iOS9 当前语言字符串返回结果:语言字符串代码 + 地区代码。在某些情况下不是这样,本人手机型号:大陆版电信iPhone5S/A1533/16GB测试结果:zh-HK/zh-TW,在地区为"中国"、"中国香港"、"中国台湾"的时候,显示的还是zh-HK/zh-TW,一旦切换到其它地区,设备语言会自动的切换到中文繁体。请开发人员注意中文的问题!
代码创建的 tableView 无法隐藏 cell 分割线
iOS9 里面用到 tableView 突然跑出来了很多 cell 的分割线, 但是在用xib创建的 tableview,就不存在这个问题
解决方法是将设置分割线隐藏的方法 self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 写在 -layoutSubviews 中:
-(void)layoutSubviews{
[super layoutSubviews];
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
}
当你app顺利提交几分钟后收到如下邮件:
Dear developer, We have discovered one or more issues with your recent delivery for "BTN2Go". To process your delivery, the following issues must be corrected: Invalid Executable - The app in 《ProjectName》.app has been built with an unsupported version of Xcode. Make sure Gatekeeper is enabled, download the latest version of Xcode from developer.apple.com, rebuild the app, and submit it again. Once these issues have been corrected, you can then redeliver the corrected binary. Regards, The App Store team
嗯,我升级了xcode到最新的7.1(从mac app store下载的)后还是收到这个邮件!开始以为苹果的bug,后来发现不是!请检查你的framework,可能编译的framework的xcode是中了xcodeghost的,一个一个排除查查找framework吧。
如何启用iPad分屏
a. 用Xcode7 iOS9 SDK编译
b. 用Launch StoryBoard做启动界面
c. 支持所有的旋转方向
需要注意的是,支持分屏后,iPad上所有界面都需要支持转屏。如果以前通过supportedInterfaceOrientations等函数来限制某些界面在iPad上不能转屏,在启用分屏后这个限制将失效。
如果不支持分屏,需要在项目设置中的General - Deployment Info中勾选Requires full screen
分屏后的几个问题
**有了分屏后,APP当前屏幕的大小不能再用[UIScreen mainScreen].bound来获取了,这个取到的是整个设备的屏幕大小,不是分屏后的屏幕大小。
解决办法是,启动时初始化window,不需要initWithFrame,直接用init就可以了。系统知道当前屏幕的大小,会帮我们正确地设置frame。然后取这个frame就能拿到实际屏幕大小了。
**以前适配iPad转屏时,有些地方会使用willRotateToInterfaceOrientation等转屏回调来处理屏幕尺寸变化。从iOS8开始,系统新增了viewWillTransitionToSize:withTransitionCoordinator回调来代替它。新的回调可以用来处理转屏和分屏引起的屏幕尺寸变化。
**分屏状态下,系统的视频录制功能不可用。如果某个功能用到了视频录制功能,建议像系统照相机一样,在分屏时给用户提示一下。
**避免hardcode。要注意iPad的屏幕不再是1024*768,而且在运行中屏幕的尺寸是会随时变化的(分屏或转屏时),所以如果以前有些代码做了hardcode,会导致分屏后有bug。
键盘windowLevel问题
当键盘已经弹起的时候,再显示我们自己写的确认窗口等window,会发现window被键盘挡住了。
这是因为iOS9下系统键盘的windowLevel是很高的,达到10^7。而且进一步发现,这个值是系统允许的最大值。如果把某个window的windowLevel改成比10^7大的值,系统只会设为10^7。
解决这个问题有两种方法:
一个是把我们自己window的level调大,同样设为10^7,因为比系统键盘晚出现,所以还是能够把系统键盘盖住。这种方法的缺点是使得window的层次结构不好管理,且依赖于系统键盘的level。而且window上也无法再显示UIAlertView等系统窗口了。
另一种方法是在显示window时先调用[mainWindow endEditing:YES],把主window的键盘收起来,然后再显示window。这种方法的缺点是,有些场景下用户是正在输入的,收起键盘对用户的体验不好。
两种方法各有优缺点,可以根据使用场景来选择。
AddressBookUI.framework在iOS9上已经被淘汰,需要改用ContactsUI.framework
旧接口还能够读取通讯录,但是添加信息到通讯录时,系统界面会卡住。