iOS13内容全介绍
WWDC2019发布了iOS13,将随新iPhone发售正式发布。对于移动开发而言,最关心的必定是新系统特性及应对新系统App所需要做的改变。通过本文阅读,旨在帮助开发者对iOS13各个方面有最基础的认识,更具体详细的内容还需要通过实践不停地探索挖掘。全文将会分为四个部分来全方位的了解iOS13所带来的影响,最后以LC项目为例,查看iOS13对项目产生的影响。
iOS13系统特性
Xcode11新功能介绍
iOS13现代化UI
SwiftUI简介
LCApp(iOS13)
全文涉及新特性使用方法可以查看iOSTestGithub仓库中更详细的说明。
一、 iOS13系统特性
iOS12更多是为了系统的性能和稳定,而iOS13有大幅度的改动,对于原生App、整体界面、安全性、性能方面都有了极大的提升。本节仅列举对产发产生影响及需要注意的模块,更多更全的iOS13系统新特性可以查看Apple 发布 iOS 13 预览版(中文版)。苹果关于iOS13的简易说明及详细说明(英文版)。
1.1 整体界面
深黑模式。iOS13最明显的特性就是在新版本中引入了深黑模式,系统自带的App都会继承深黑模式。可以在设置中心设置手机的显示模式。在深黑模式下,现有App不会产生变化,但是iOS13SDK提供了相应的接口支持第三方App实现深黑模式。
深黑模式应用:
view.overrideUserInterfaceStyle = .dark
通过设置view的overrideUserInterfaceStyle属性即可。
注意:
设置view的overrideUserInterfaceStyle属性会影响当前view及其子view,如果已经view和子view设置了color则修改overrideUserInterfaceStyle,对已设置的color无效。
应用拓展:
1. 在项目中使用深黑模式,如果项目不关闭,则需要对相关页面添加通知(暂时没找到系统设置页修改导致的变化属性),或者在baseViewController设置也可。
2. 如果修改了模式杀死App,则可以对scene设置对应的overrideUserInterfaceStyle属性即可。
1.2 定位服务
增加定位服务的权限选择类型。增加只允许一次类型,目的为了保证Wifi、Bluetooth的情况下使用定位不被泄露。因此大多数关于定位服务相关模块需要进行相对应的改变。
tips: 在对位置权限进行持久化的模块,需要考虑到这个问题,进行一定的修改。
1.3 登陆方式—Sign In with Apple
可以使用Apple ID进行账号的登陆,而不需要借助第三方登录。让用户可以使用面容 ID 或触控 ID 来轻松进行身份认证,而内置的双重认证则再增添一层安全保障。Apple 不会利用 Sign In with Apple 来分析用户特征或他们在各个 app 中的活动。
tips:
Sign in with Apple的功能在测试版中还未开放,需要等到九月份。从各方面信息来看Sign in with Apple功能苹果会封装成一个控件,在正式使用中只需要添加进控件即可。具体内容可能会有偏差,等9月再揭晓其神秘面纱。
1.4 快捷指令 (重要)
iOS13系统中新增快速指令的App,通过在该App中设置一些会话指令,帮助用户通过跟siri对话完成与App的交互。
tips:
该功能的实现,是否需要结合App还需要之后探索。
1.5 性能提升
面容解锁加速30%
App Store采用全新方式封装App,下载空间减少50%,更新所需的空间减少60%,从而极大的加快了启动速度。
实验:
1. 乐橙项目在iOS12的AppStore上显示的大小117M,在iOS13的AppStore显示大小为106.7M,包体大小确实缩小了,但是远远没有达到上面描述的程度。需要后续进一步观察。
2. 同样是iPhone6s,iOS13下载的乐橙App跟iOS12下载的乐橙App在启动时间上有明显的提升。
二、Xcode11新功能介绍
工欲善其事必先利其器。iOS13发布的同时也会发布最新的Xcode工具,本节将介绍三个利于开发的Xcode新功能。
2.1 Debug工具升级
网络配置和温度环境设置
手机与Mac连接的条件下,可以按照如图所示完成手机的网络环境或温度环境的配置。丰富的条件选择有助于Debug。
UI显示可以通过条件控制
需要Xcode11且MacOS10.15以上才会有这个功能,现有条件下暂未完成此模块的测试。
2.2 SPM内置集成
Xcode10中可以使用Swift Package Manager配置文件进行配置,Xcode11自带工具模块可以帮助开发者集成各种第三方库,通过流程进行添加暂时无法将第三方库引入,估计和公司网络条件有关。
tips:
集成SPM的目的是为了替换cocoapod,具体的效果及功能实现需要长时间测试。
2.3 版本对比
Xcode11基于git的版本管理会在新修改的代码前有光标提示,可以更快更准确查看修改。
tips:
上图的"print("git manager \n")"代码行进行了修改,点击前置亮点。
Show Change: 显示上一版本代码行内容。
Discard Change: 恢复上一版本代码。
对于以git管理的工程,十分友好,LC项目以svn管理所以无法享受该好处。
2.4 其他更多
MiniMap
编写代码过程中,右侧有缩略图,可以通过点击缩略图快速的找到相应代码块。
多屏修改代码
之前代码同时最多只能查看两份代码文件,在Xcode11中可以同时查看多个文件代码,对于使用多屏进行开发效果极佳。
command+函数名
通过command+函数名指令可以对(方法、类)增加添加方法、添加说明文档、重命名等操作。重命名修改了方法,会将对应使用到的地方也全部进行修改。
三、iOS13现代化UI
iOS13在UI方面也做了多处改动以方便开发,本节内容根据iOS13现代化UI,对其归纳和实践,如果想要更详细的了解iOS13UI设计的问题,建议看视频学习。
3.1 Flexible UI
###### 3.1.1 Launch
现阶段关于Launch都是设置Launch Images Source,意味着对于每个机型对于都需要设置各自的2倍图、3倍图,这显然不够灵活。2020年4月份,Apple规定所有应用的Launch都需要使用launch.storyboard,否则将无法过审。
3.1.2 适配(待测)
一旦出现新的屏幕尺寸,App就需要去进行一定的适配,但是基于iOS13SDK的App它会自动提供屏幕的全屏分辨率。
3.2 Bars
增加设置toolbar、navigationbar样式的API。
以NavigationBar为例,下面代码通过将UINavigationBarAppearance 对象赋给navigationBar的standardAppearance即可完成对Navigationbar的样式设置。
设置NavigationBar代码:
private func setBar() {
let appearance = UINavigationBarAppearance()
appearance.titleTextAttributes = [.foregroundColor: UIColor.red]
self.navigationController?.navigationBar.standardAppearance = appearance
}
standardAppearance: 竖屏时导航栏外观。
compactAppearance: 横屏时导航栏外观。
scrollEdgeAppearance: 描述当关联的UIScrollView到达与导航栏邻接的边缘时导航栏的外观。
还可以通过UINavigationBarAppearance对象中的属性设置自定义baritem的外观。新增的bar功能可以极好的管理bar外观。
3.3 Presentation
iOS13UI对VC增加了present效果,默认效果由全屏显示变化为下图所示内容,而默认效果的修改不需要改变之前的代码逻辑。
3.3.1 present样式影响及还原
根据上图可知iOS13的Present默认效果会在原有的VC上弹出一个VC,并且不完全覆盖原有VC。经过测试如上效果的原VC是不会Disappear,一直存在在层级树中,而iOS 系统对于层级树的管理内存消耗是极少的,所以不用担心性能问题。
而如果APP非要使用原有的全屏显示模式只需要设置modalPresentationStyle的样式即可。
let presentVC = PresentPageController()
presentVC.modalPresentationStyle = .fullScreen
self.present(presentVC, animated: true, completion: nil)
3.3.2 UIAdaptivePresentationControllerDelegate
可以通过实现UIAdaptivePresentationControllerDelegate来监听dismiss的各个阶段。对于Present转场动画而言modalPresentationStyle非fullScreen,在添加转场动画后会自动加入交互式转场动画,而fullScreen还是需要开发手动实现交互式转场动画代理。
3.4 Search
将暴露UISearchController中UISearchBar更多接口能够满足UISearchBar的定制化,包括修改textfield的样式、显示或隐藏某些按钮等。
tips:
1. UISearchController不能被present。
2. beta中UISearchController有些bug,需要Xcode更新在做测试。
3.5 Gesture
TextView的增加UITextIntercation,并且通过UITextInputProcotol将选中的text进行操作。
tables&collections。比如两个手指滑动即可连续选中cell(可选)实现tableview的相关代理即可。
三个手指左划undo,右滑redo。对于绘画比较有用,正常工程中不太需要。(iPad)
四、SwiftUI简介
4.1 实现页面绘制
4.1.1 环境配置
Xcode 11、 iOS 13,如果想要实现PreviewProvider需要将Mac系统升至10.15以上。现阶段使用SwiftUI的环境:Xcode 11 beta3、iOS13 beta、MacOs10.14.5(App Store)。
新建Swift项目,勾选Use SwiftUI,即可创建基于SwiftUI的Swift工程。工程目录如下所示:
工程目录说明:
1. 增加了SceneDelegate.swift。iOS12之前都是用UIApplication来维护App的生命周期,而到了iOS13,是通过UISceneSession维护App的生命周期,详细内容将在第五节中做更详细的说明。
2. 增加ContentView.swift文件去除ViewController.swift文件,去掉Controller的概念,都以View实现页面的展示。
4.1.2 通过SwiftUI实现页面
import SwiftUI
struct ContentView : View {
@State private var isPlayer: Bool = false
var body: some View {
HStack {
VStack {
Text("★★★★★")
Text("5 stars")
}.font(.caption)
VStack(alignment: .leading) {
HStack {
Text("Avocado Toast").font(.title)
Spacer()
ButtonView(isPlayer: $isPlayer)
}
Text(isPlayer ? "选中了ButtonView" : "未选中ButtonView")
.font(.caption).lineLimit(1)
}
}
}
}
struct ButtonView : View {
@Binding var isPlayer: Bool
var body: some View {
Button("选中") {
self.isPlayer.toggle()
}.foregroundColor(isPlayer ? Color.red : Color.blue)
}
}
显示结果:
代码说明:
1. 功能实现。通过点击选中按钮修改label的显示内容。
2. 页面显示完全除了之前放在了HostViewController,所有的显示逻辑都是基于View实现的。
上图页面的层级结构
通过层级结构我们可以很清楚的知道,ContentView的显示。但在代码实现中含有HStack嵌套HStack和VStack的部分,在层级结构中没有显示。只显示了最外层的HStack及其内层的View。
使用说明:
1. 使用SwiftUI和UIKit大大减少的代码量。
2. 掌握内容。数据传递、变量、属性结构器的定义。
2. 缺陷。会造成一定的阅读缺陷。当层级复杂会导致属性设置出问题。
4.2 数据流转
WWDC上官方的说法视图是方法的状态而不是一系列的事件。上面的话比较难懂,下图诠释了用户操作到改变视图状态的全过程。
想要更深入理解关于action改变view的显示可以查看Onevcat关于单数据流VC设计或者笔者关于单数据函数流关于VC设计的文档。
需要完成上述流程,思路就是view绑定数据,所以swiftUI系统了很多种属性结构器来使数据绑定在view上。
属性结构器
@State。支持读和写。
@Binding。 不需要持有者读和写,是@State的子类。
@objectBinding。 使用@objectBinding对model进行定义,会对model的相关性属性进行跟踪。并且在初始化阶段必须传入model。
@environmentObject。是对满足BindableObject 协议model的封装,一个environmentObject可以包含多个实现协议的model。
建议:
1. 为了方便维护view上尽量少用State修饰符修饰的内容,尽量多用environmentObject。所以对于页面功能的设计提出了更高的要求。
2. 关于这部分的学习,本文只是提炼,WWDC视频部分更为详细,因公司网络原因限制,建议在非公司环境下学习。
视频地址: https://developer.apple.com/videos/play/wwdc2019/226 视频+PPT。
五、iOS13新增文件SceneDelegate
基于iOS13SDK新建的应用程序,会发现增加了SceneDelegate.swift文件,之前应用的生命周期通过UIApplication去控制,iOS13之后通过UISceneSession去控制应用的生命周期,因此main函数运行之后的过程会出现差别,本节将详细对比前后版本的差别以明确在iOS13SDK开发APPmain函数执行之后所执行的操作。
5.1 整体流程
APP启动后Main函数执行之前还是按照之前的流程链接动态库、初始化类等流程。Main函数执行之后
是否否是Main函数AppDelagate是否main.storyboard或设置window无效info.plist是否配置SceneDelegate黑屏SceneDelegatemain.storyboard或设置windowsceneDidBecomeActive显示内容
通过上图可以明确地知道Main函数执行之后App的整理流程,其中有两个部分需要注意.
1. 关于是否设置SceneDelegate作为配置写在info.plist文件中,5.2节会对其有更详尽的说明。
2. 最终页面到Active状态调用了SceneDelegate中sceneDidBecomeActive的方法,由此可看出通过Scene来管理APP的生命周期而不是UIApplication。
3. 在AppDelegate的didFinishLaunchingWithOptions设置window无效,详细内容会在5.3节中说明。
5.2 info.plist
上节提到通过info.plist中的配置去设置启动时具体执行哪一个SceneDelegate,看一下关于Scene的配置相关项。
<key>UIApplicationSceneManifest</key>
<key>UIApplicationSupportsMultipleScenes</key>
UISceneConfigurations
UIWindowSceneSessionRoleApplication
UILaunchStoryboardName
LaunchScreen
UISceneStoryboardFile
Main
UISceneConfigurationName
Default Configuration
UISceneDelegateClassName
$(PRODUCT_MODULE_NAME).SceneDelegate
通过UISceneDelegateClassName的配置项去设置具体的调用的函数名,经过测试将该配置项去除,将会导致调用不到相关内容。
5.3 纯代码UI操作
在info.plist中默认设置了"UISceneStoryboardFile = Main",以满足通过sb对页面进行布局。对于非sb布局的产品,之前会把相关的代码写在AppDelegate中,现阶段需要将初始化Window的操作放在SceneDelegate中。
代码块:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = UINavigationController(rootViewController: HomeViewController())
window?.makeKeyAndVisible()
}
按照之前初始化window的方法执行发现是黑屏。通过Hierarchy工具查看页面的布局结构如下所示:
会发现最外层结构是UIWindowScene,回过来看关于UIWindow初始化的方法,会发现增加了
@available(iOS 13.0, *)
public init(windowScene: UIWindowScene)
对window进行初始化,所以需要纯代码绘制UI需要按照如下内容
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
window = UIWindow(windowScene: scene as! UIWindowScene)
window?.rootViewController = UINavigationController(rootViewController: HomeViewController())
window?.makeKeyAndVisible()
}
5.4 总结
本节对SceneDelegate相关的进行简单的说明。iOS13中通过UIScene实现了管理APP的生命周期,以UIScene的子类UIWindowScene来管理APP页面的布局结构。如此修改对于管理APP生命周期、页面布局、APP启动的影响还需要更多的关注。