原文地址:https://github.com/ChenYilong/iOS9AdaptationTips/
[摘要]iOS9 把所有的 http 请求都改为 https 了: iOS9 系统发送的网络请求将统一使用 TLS 1.2 SSL 。采用 TLS 1.2 协议,目的是强制增强数据访问安全,而且
系统 Foundation 框架下的相关网络请求,将不再默认使用 Http 等不安全的网络协议,而默认采用 TLS 1.2 。服务器因此需要更新,以解析相关数据。如不更新,可通过在 Info.plist 中声明,倒退回不安全的网络请求。而这一做法,官方文档称为 ATS ,全称为 App Transport Security ,是 iOS9 的一个新特性。
(注:有童鞋反映:“服务器已支持 TLS 1.2 SSL ,但 iOS9 上还是不行,还要进行本文提出的适配操作。”那是因为: ATS 只信任知名 CA 颁发的证书,小公司所使用的 self signed certificate ,还是会被 ATS 拦截。对此,建议使用下文中给出的 NSExceptionDomains ,并将你们公司的域名挂在下面。)
在讨论之前,跟往常一样,先说下 iOS 程序猿们最关心的问题:
首先咱们来看下业内对 Apple 这一做法的评论:
这是某社交 App 上讨论,看来业内还是吐槽声和肯定声同在。
结论是:
跟你很有关系,加班吧,少年!
书归正传 [严肃脸] ,我们正式讨论下 WHAT , WHY , HOW :
什么是 SSL/TLS ?
SSL 的解释在此不做赘述,网上有好多文章,也不是本文重点。
说下什么是 TLS ,还有跟 HTTP 和 HTTPS 有什么关系。
TLS 是 SSL 新的别称。举个例子:
“ TLS1.0 ”之于“ SSL3.1 ”,犹“公元 2015 ”之于“民国 104 ”,或者是“一千克”之于“一公斤”,或者是“半斤”之于“八两”:称呼不同,但意思相同。
SSL 3.0 版本之后的迭代版本被重新命名为 TLS 1.0,
也就是说:
TLS 1.0 = SSL 3.1
所以他们是一个东西,我们平常也经常简单见到 “ SSL/TLS ” 这种说法。
目前,应用最广泛的是 TLS 1.0 ,接下来是 SSL 3.0 。目前主流浏览器都已经实现了 TLS 1.2 的支持。
常用的有下面这些:
那为什么标题是“使用 HTTPS ”而没有提及 SSL 和 TLS 什么事?
“ SSL/TLS ”跟 HTTP 和 HTTPS 有什么关系?
要理解这个,要看下他们之间的关系:
HTTP+SSL/TLS+TCP = HTTPS
或者
HTTPS = “ HTTP over SSL ”
也就是说:
Apple 让你的 HTTP 采用 SSL/TLS 协议,就是让你从 HTTP 转到 HTTPS 。而这一做法,官方文档称为 ATS ,全称为 App Transport Security 。
不使用 SSL/TLS 的 HTTP 通信,就是不加密的通信!
不使用 SSL/TLS 的 HTTP 通信,所有信息明文传播,带来了三大风险:
SSL/TLS 协议是为了解决这三大风险而设计的,希望达到:
1. 所有信息都是加密传播,第三方无法窃听。
2. 具有校验机制,一旦被篡改,通信双方会立刻发现。
3. 配备身份证书,防止身份被冒充。
SSL/TLS 的作用,打个比方来讲:
如果原来的 HTTP 是塑料水管,容易被戳破;那么如今新设计的 HTTPS 就像是在原有的塑料水管之外,再包一层金属水管( SSL/TLS 协议)。一来,原有的塑料水管照样运行;二来,用金属加固了之后,不容易被戳破。
正如文章开头所说:
TLS 1.2 协议 强制增强数据访问安全 系统 Foundation 框架下的相关网络请求,将不再默认使用 Http 等不安全的网络协议,而默认采用 TLS 1.2 。服务器因此需要更新,以解析相关数据。如不更新,可通过在 Info.plist 中声明,倒退回不安全的网络请求。
总之:
要么咱们 iOS 程序猿加班,要么后台加班:
方案一:立即让公司的服务端升级使用 TLS 1.2 ,以解析相关数据。
方案二:虽 Apple 不建议,但可通过在 Info.plist 中声明,倒退回不安全的网络请求依然能让 App 访问指定 http ,甚至任意的 http ,具体做法见 gif 图,示例 Demo 见 Demo1
这也是官方文档和 WWDC 给出的解决方案:
1. Apple 官方文档
2. WWDC Session : "Networking with NSURLSession" session ( [ WWDC 2015 session 703, “ Privacy and Your App ” O 网页链接 ] , 时间在 30:18 左右)
Info.plist 配置中的 XML 源码如下所示:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>yourserver.com</key>
<dict>
<!--允许子域名:subdomains-->
<key>NSIncludesSubdomains</key>
<true/>
<!--允许 App 进行不安全的 HTTP 请求-->
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<!--在这里声明所支持的 TLS 最低版本-->
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
上面是比较严谨的做法,指定了能访问哪些特定的 HTTP 。当然也有暴力的做法:
彻底倒退回不安全的 HTTP 网络请求,能任意进行 HTTP 请求,比如你在开发一款浏览器 App ,或者你想偷懒,或者后台想偷懒,或者公司不给你升级服务器。。。
你可以在 Info.plist 配置中改用下面的 XML 源码:
<key>NSAppTransportSecurity</key>
<dict>
<!--彻底倒退回不安全的 HTTP 网络请求,能任意进行 HTTP 请求 (不建议这样做)-->
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
[注:以上在 Info.plist 配置中的做法已经验证可行,但目前 Apple 的 prerelease 版本的官方文档并未提及 Info.plist 中配置的代码,我将密切关注官方文档,如有提及,再来更新本文 .你若发现官方文档有提及了,也可在微博 @iOS 程序犭袁通知下我。]
[ iOS9 在定位的问题上,有一个坏消息一个好消息] 坏消息:如果不适配 iOS9 ,就不能偷偷在后台定位(不带蓝条,见图)!好消息:将允许出现这种场景:同一 App 中的多个 location manager :一些只能在前台定位,另一些可在后台定位,并可随时开启或者关闭特定 location manager 的后台定位。
如果没有请求后台定位的权限,也是可以在后台定位的,不过会带蓝条:
如何偷偷在后台定位:请求后台定位权限:
// 1. 实例化定位管理器
_locationManager = [[CLLocationManager alloc] init];
// 2. 设置代理
_locationManager.delegate = self;
// 3. 定位精度
[_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
// 4.请求用户权限:分为:⓵只在前台开启定位⓶在后台也可定位,
//注意:建议只请求⓵和⓶中的一个,如果两个权限都需要,只请求⓶即可,
//⓵⓶这样的顺序,将导致 bug :第一次启动程序后,系统将只请求⓵的权限,⓶的权限系统不会请求,只会在下一次启动应用时请求⓶
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8 ) {
//[_locationManager requestWhenInUseAuthorization];//⓵只在前台开启定位
[_locationManager requestAlwaysAuthorization];//⓶在后台也可定位
}
// 5.iOS9 新特性:将允许出现这种场景:同一 app 中多个 location manager :一些只能在前台定位,另一些可在后台定位(并可随时禁止其后台定位)。
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9 ) {
_locationManager.allowsBackgroundLocationUpdates = YES;
}
// 6. 更新用户位置
[_locationManager startUpdatingLocation];
但是如果照着这种方式尝试,而没有配置 Info.plist , 100%你的程序会崩溃掉,并报错:
*** Assertion failure in -[CLLocationManager setAllowsBackgroundLocationUpdates:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/CoreLocationFramework_Sim/CoreLocation-1808.1.5/Framework/CoreLocation/CLLocationManager.m:593
要将 Info.plist 配置如下:
对应的 Info.plist 的 XML 源码是:
<key>NSLocationAlwaysUsageDescription</key>
<string>微博 @iOS 程序犭袁 请求后台定位权限</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
iOS9 之前,企业级分发十分方便:点击 App 出现“信任按钮”,
iOS9 以后,企业级分发 ipa 包将遭到与 Mac 上 dmg 安装包一样的待遇:默认不能安装,也不再出现“信任按钮”
必须让用户进行 gif 图中的设置(相关 Demo : https://github.com/ChenYilong/iOS9AdaptationTips/ )
[前言] 未来, Watch 应用必须包含 bitcode , iOS 不强制, Mac OS 不支持。
但最坑的一点是: Xcode7 及以上版本会默认开启 bitcode 。
什么是 bitcode ?
Apple 官方文档-- App Distribution Guide – App Thinning (iOS, watchOS ) 是这样定义的:
Bitcode is an intermediate representation of a compiled program. Apps you upload to iTunes Connect that contain bitcode will be compiled and linked on the App Store. Including bitcode will allow Apple to re-optimize your app binary in the future without the need to submit a new version of your app to the store.
翻译过来就是:
bitcode 是被编译程序的一种中间形式的代码。包含 bitcode 配置的程序将会在 App Store 上被编译和链接。 bitcode 允许苹果在后期重新优化我们程序的二进制文件,而不需要我们重新提交一个新的版本到 App Store 上。
在 Xcode 简介--- What ’ s New in Xcode-New Features in Xcode 7 中这样描述:
Bitcode. When you archive for submission to the App Store, Xcode will compile your app into an intermediate representation. The App Store will then compile the bitcode down into the 64 or 32 bit executables as necessary.
也就是
当我们提交程序到 App Store 上时, Xcode 会将程序编译为一个中间表现形式( bitcode )。然后 App store 会再将这个 bitcode 编译为可执行的 64 位或 32 位程序。
再看看这两段描述都是放在 App Thinning (App 瘦身)一节中,可以看出其与包的优化有关了。喵大(@onevcat )在其博客 《开发者所需要知道的 iOS 9 SDK 新特性》 中也描述了 iOS 9 中苹果在 App 瘦身中所做的一些改进,大家可以转场到那去研读一下。
Bitcode 是一种中间代码,那它是什么格式的呢? LLVM 官方文档有介绍这种文件的格式: LLVM Bitcode File Format 。
如何适配?
在上面的错误提示中,提到了如何处理我们遇到的问题:
You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE ), obtain an updated library from the vendor, or disable bitcode for this target. for architecture arm64
正如开头所说的:
未来, Watch 应用必须包含 Bitcode , iOS 不强制, Mac OS 不支持。
但最坑的一点是: Xcode7 及以上版本会默认开启 Bitcode 。
Xcode 7 + 会开启 Bitcode 。
也就是说,也两种方法适配:
方法一:更新 library 使包含 Bitcode ,否则会出现以下中的警告;
(null ): URGENT: all bitcode will be dropped because
'/Users/myname/Library/Mobile
Documents/com~apple~CloudDocs/foldername/appname/GoogleMobileAds.framework/GoogleMobileAds (GADSlot+AdEvents.o )'
was built without bitcode. You must rebuild it with bitcode enabled
(Xcode setting ENABLE_BITCODE ), obtain an updated library from the
vendor, or disable bitcode for this target. Note: This will be an
error in the future.
甚至有的会报错误,无法通过编译:
ld: ‘/Users//Framework/SDKs/PolymerPay/Library/mobStat/libSDK.a (**ForSDK.o )’ does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE ), obtain an updated library from the vendor, or disable bitcode for this target. for architecture arm64
无论是警告还是错误,得到的信息是:我们引入的一个第三方库不包含 bitcode 。
方法二:关闭 Bitcode ,方法见下图
我们可以在” Build Settings ”->” Enable Bitcode ”选项中看到:
用 Xcode 7+ 新建一个 iOS 程序时, bitcode 选项默认是设置为 YES 的。现在需要改成 NO 。
如果我们开启了 bitcode ,在提交包时,下面这个界面也会有个 bitcode 选项:
更多信息,请移步
WWDC 2015 Session 102: "Platforms State of the Union"
WWDC 2015 Session 703: "Privacy and Your App ( 时间在 30 : 18 左右)关于 URL scheme
的介绍,指出:
也就是说:在 iOS9 中,如果使用 canOpenURL:
方法,该方法所涉及到的 URL scheme
必须在"Info.plist"中将它们列为白名单,否则不能使用。 key 叫做 LSApplicationQueriesSchemes ,键值内容是
<key>LSApplicationQueriesSchemes</key>
<array>
<string>urlscheme</string>
<string>urlscheme2</string>
<string>urlscheme3</string>
<string>urlscheme4</string>
</array>
然而,我们却发现了一件意外的事:
当我们在 iOS9-beta (截至本文发布时, iOS9 正式版还未发布)中,使用 openURL:
方法时,不在白名单中的 URL 会报错
“ This app is not allowed to query for scheme xxx ”
无论是官方文档还是 WWDC 的视频中都没有提及 openURL:
方法的这一变动,所以猜测这是 beta 版本一个 bug ,截至本文发布时, iOS9 正式版还未发布,期望在正式版中能得以修复。在此之前,可通过将 openURL:
用到的 URL scheme
列入白名单来解决这个 bug 。
苹果为什么要这么做?
在 iOS9 之前,你可以使用 canOpenURL:
监测用户手机里到底装没装微信,装没装微博。但是也有一些别有用心的 App ,这些 App 有一张常用 App 的 URL scheme
,然后他们会多次调用canOpenURL:
遍历该表,来监测用户手机都装了什么 App ,比如这个用户装了叫“大姨妈”的 App ,你就可以知道这个用户是女性,你就可以只推给这个用户女性用品的广告。这是侵犯用户隐私的行为。
这也许就是原因。
本项目中给出了一个演示用的 Demo ,仓库的文件夹叫“ Demo3_iOS9URLScheme 适配_引入白名单概念”, Demo 引用自 LSApplicationQueriesSchemes-Working-Example
Demo 结构如下:
主要演示的情景是这样的:
假设有两个 App : weixin (微信) and 我的 App. 我的 App 想监测 weixin (微信) 是否被安装了. "weixin (微信)" 在 info.plist 中定义了 URL scheme :
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>weixin</string>
</array>
</dict>
</array>
我的 App 想监测 weixin (微信) 是否被安装了 :
[[UIApplication sharedApplication]
canOpenURL:[NSURL URLWithString:@"weixin (微信)://"]];
即使你安装了微信,在 iOS9 中,这有可能会返回 NO :
因为你需要将 "weixin (微信)" 添加到 “我的 App ” 的 info.plist 文件中:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>weixin</string>
</array>
关于 openURL:
这个问题,可在 Demo3 中自行测试,如果该 bug 修复了的话,请私信微博 @iOS 程序犭袁,我再来更新本文。
另外,推荐一篇博文,其中最关键的是以下部分:
If you call the “ canOpenURL ” method on a URL that is not in your whitelist, it will return “ NO ”, even if there is an app installed that has registered to handle this scheme. A “ This app is not allowed to query for scheme xxx ” syslog entry will appear.
If you call the “ openURL ” method on a URL that is not in your whitelist, it will fail silently. A “ This app is not allowed to query for scheme xxx ” syslog entry will appear.
[ iPad 适配 Slide Over 和 Split View ]
若想适配 multi tasking 特性,唯一的建议:弃纯代码,改用 storyboard 、 xib ,纵观苹果 WWDC 所有 Demo 均是如此:
Posted by 微博 @iOS 程序犭袁
原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0
1
pH 2015-09-01 07:06:08 +08:00
我只是在想,万一兼容了这个。 低版本 iOS 设备运行的话,会如何。
|
2
sauchye 2015-09-01 23:17:20 +08:00
顶起
|