大多数浏览器和
Developer App 均支持流媒体播放。
-
创建位置感知的企业APP
开发可定位的企业 app 来促进事业,并对员工的每日工作进行个性定制。了解 Apple 如何借助 iBeacon 及位置服务为校区内的咖啡厅创建 Caffe Macs app,以及如何在保护员工隐私的同时将这类工具及框架运用到你的个人 app 中。借此,你将了解如何运用定位功能国际员工带来绝佳体验。
资源
相关视频
WWDC20
WWDC19
-
下载
大家好 欢迎来到全球开发者大会 (创建位置感知的企业APP) 大家好 欢迎来到全球开发者大会 我叫卢卡斯 是Apple Caffè Macs团队 一名工程师 此次演讲 我将谈谈在微观和宏观层面 我们如何考虑位置 从而为我们的员工 提供一个很棒的Caffè Macs app体验 我将主要谈谈在社交距离产生前的 员工体验 并分享一些我们围绕安全考虑 已经在开发的新功能 无论你是在开发自己的Caffè app 供企业场所使用 还是开发企业app 供全球员工使用 这些考虑都应帮你提供出色的app体验 首先 我会给各位介绍一下 Apple Park Caffè Macs的内视图 通过了解Caffè Macs体验 你会明白为什么 位置对于我们创建app很重要 第二 我们会讨论用户偏好 如何使我们的用户在调用定位服务前 控制他们的app体验 然后 我们要谈到使用定位服务 获取现场和app内的体验 最后 我们会简单探讨一下国际化的世界 首先 我们来了解一下Caffè Macs的概况 以及我们想提供的员工体验 Caffè Macs是Apple Park的 非官方城市广场 公司所有人都会聚在这里 见面、聊天以及一起用餐 不管你是想来吃午饭、零食还是喝杯咖啡 Caffè Macs都是享用健康 和美味食物的绝佳场所 我们的使命是 为员工提供优质的食品和服务 为此 我们为员工提供内部企业app 使用app可以浏览菜单、点餐 用Apple Pay完成支付 我们在iPad上也有一个售货亭app 客人可以在上面下单 然后订单会被发送到 我们的第三方app 厨房显示系统 在厨房中可以通过iPad使用 收到订单后 厨师会马上开始准备你的食物
准备好之后 他们会借助厨房显示系统 通知用户他们的食物已经可以领取了
Caffè Macs app中的用户偏好 和定位服务 对于为我们的员工 提供出色的定制美食体验来说十分重要 好了 以上就是对餐厅体验的简要概述
下面我们来看看Caffè Macs app中 基于位置的app体验 我们允许员工选择他们的默认位置 我们使用这个偏好是为了在Caffè中 能快速显示菜单 请注意 我目前的默认位置偏好 设定的是“离我最近” 筛选时会使用我的位置 来显示合适的Caffè菜单 等我选好一个Caffè后 app默认显示相应位置的菜单
这样使得用户可以控制基于位置的体验 可以优先使用或拒绝定位服务许可 app启用的时候 我们会查看用户的Caffè偏好 我们允许用户在app运行的时候 选择 “离我最近“ 这一过程会使用定位服务 来决定向用户显示 哪家Caffè 用户也可以直接进行选择 app会显示他们选择的Caffè 这些选项让用户可以控制 他们会看到哪些菜单 我们最近对Caffè Macs app进行了更新 一个很棒的体验是 用户可以在选定的Caffè 快速选择领取窗口 从而确保适当的社交距离 然后你可以存储偏好 并用它来确定app启动时的默认状态 存储用户选择的一种简单方法是 使用Foundation的UserDefaults 这样你可以在app启动时持续存储键值对 UserDefaults是一个很棒的地方 可以来存储你使用app过程中 这种类型的偏好值 正如我们刚才看见的 允许用户选择他们的默认位置 是很好的第一步 下面 我们要更进一步 谈谈我们如何使用定位服务提供现场体验 我们在Caffè Macs app中 遇到的一个挑战 是如何根据用户站的位置 显出示正确的菜单
学校里有一家大型Caffè 附近还有一个咖啡小站 一个人随时可能离两个地方都很近 如果公司中多个兴趣点很接近 你在为其创建app时 可能会遇到同样的挑战 对于我们的app来说 我们想确保用户 在他们预期的位置上下单 为了实现这一点 我们可以使用 Core Location和iBeacon协议 为了在你的app里使用Core Location 你必须向用户请求授权这些服务 在Apple 我们非常关心隐私问题 员工可以选择是否授权给 使用定位服务的企业app 只请求访问app需要的数据 并向用户解释需要的原因 是很重要的 想要更深入地了解 如何在使用位置时确保隐私 请观看今年的相关演讲 你的app可以请求两种类型的授权 “使用时” 和 “始终” 在“使用时” 授权中 你的app在前台时会接收位置事件 通过启用在后台的位置使用标识 app可以继续在后台访问位置 “始终”授权可以允许我们 在后台访问用户位置 不用在前台启动 也不用启用标识 但这对于Caffè Macs app并不是必要的 Caffè Macs app只需“使用时”的偏好 就可利用其定位服务 这对我们的位置体验来说足以 有关请求授权的更多信息 包括最新的近似值授权请求 请观看关于Core Location的演讲 请记住 请求授权 并不能保证你的app能得到授权 你的app授权被拒时 或者用户授予的权限 比你所请求的少时 亦或者用户通过“只允许一次”选项 授予app临时访问权限时 你的app应该要做到 能够得体地处理 为了让我们的app能够调用 “使用时请求”授权 我们用目的字符串 在Info.plist文件中添加了 NSLocationWhenInUse- UsageDescription密钥 系统显示的是目的字符串 和授权请求对话框 在请求授权之前 需要给你的Info.plist文件 添加所需的密钥 如果所需的密钥没有出现 那授权请求会立即失败
另外 在你的用户需要定位服务 来完成app里的任务时 请求授权才会出现
如果用户不清楚 为何你的app需要请求定位服务 那么用户可能会拒绝请求
当你请求授权时 或者当你的app授权状态发生变化时 你可以使用委托对象的locationManager didChangeAuthorization方法 来处理这些变化
定位服务的可用性随时可能会改变 用户可以在系统设置中禁用定位服务 可能禁用你app的定位服务 也可能禁用所有app的 如果你的app在运行 不管是在前台和在后台 当可用性状态改变时 系统会调用locationManager didChangeAuthorization方法 来通知你那些改变
定位服务所需要硬件 或许不会每个设备都具备 在信任特定的定位服务之前 需要通过调用 CLLocationManager对象的方法 来检查设备是否支持定位服务 如果设备不支持定位服务 你可以求助于 我们前面讨论过的默认用户偏好 一旦你的app获得授权 并且你确定设备能够支持 你的app就可以使用定位了 我们可以使用Core Location 来设置信标信号 信标是一种发出信号的设备 可以被系统检测到并传递给你的app 如果用户在某家Caffè内 这些信号是可以识别到的 一旦我们检测到特定的信标信号 我们就可以显示相应Caffè的菜单 前面提到的位置授权 只有使用iBeacon协议时 我们才需要
你在部署信标硬件时 必须用适当的邻近UUID、主要值和次要值 对每个信标进行编程
这些值所标识的每个信标都是独特的 这样你的app在之后能够区分它们
这也可以帮助你建立层次体系 适用到你的用例中 比如 这样可以你匹配Caffè的级别 或者特定的食品小站
信标通过将这些唯一值传播到你的设备 使用户可以获得基于定位的产品和服务
在你的app中添加信标支持 需要涉及在两个不同阶段的信标检测 一:使用区域监控来检测信标的存在 二:使用信标测距来确定 探测到的信标的邻近值 对于这一点 你可以通过观看2019年 《Core Location 的新变化》 来了解更多内容 下面是当信标在附近时 如何使用区域监控来提醒你的app 要监视信标 你需要使用邻近UUID 创建CLBeaconIdentityConstraint对象 然后 实例化CLBeaconRegion对象…
并将其用CLLocationManager对象的 startMonitoring-for方法注册 beaconRegion包含你想要检测的信标的 邻近UUID、主要值和次要值 只有具有匹配值的信标 才会触发对你委托对象的调用 在调用此方法之前 必须创建一个CLLocationManager对象 并且为它指定一个委托
检测到匹配信标时 CLLocationManager对象 会通过调用LocationManager didEnterRegion方法 通知委托
同样地 探测到的信标移出区域时 locationManager会调用 LocationManager didExitRegion方法
下面 你通过调用CLLocationManager上的 isRangingAvailable类型方法 检查运行app的硬件是否可使用测距
只有设备支持服务时才能开始测距 另外 你可以选择性地存储信标 以便可以根据需要停止测距 你可以在这里使用主要值和次要值 以便区分你的唯一信标 如果有多个信标使用了 相同的UUID、主要值和次要值 只可能会依据邻近值和精确值 去区分发送到LocationManager didRangeBeacons-in方法的信标数组 我们已经了解到 对于定制化的现场体验来说 信标信号测距是一个很好的资源 而且这些定位服务使我们的app 与用户的环境在联系上更加紧密 现在我们来谈谈如何调整你app的行为 以便在全球范围内进行定位 在Apple 我们有世界各地的员工 我们希望我们的app 无论在哪里使用 都能够提供良好的体验 对于全球企业app 我们需要考虑许多国际化主题 对于用户可见的日期和时间的显示 DateFormatter提供了各种本地化预置 和配置选项
DateFormatter的示例 会创建日期对象的字符串显示 并将日期和时间的符号表示 转化为日期对象
比如 不同地区的用户 可能期望看到特定格式的日期和时间 在新的拾取窗口功能中 我们增加了社交距离 无论用户在哪里 我们需要将正确的本地化时间 呈现给他们 以供他们选择 这就是创建DateFormatter示例的方法 Foundation框架还提供了 NumberFormatter类 NumberFormatter的示例 可以配置NSNumber对象的文本表示 并且将数值的文本表示 转化成NSNumber对象 要注意NumberFormatter只提供格式 不提供货币转换
你可以使用预定义的 货币数字格式类型来定义货币金额的格式 这一格式类型 NumberFormatter的 numberStyle属性也使用 通过观察设备的区域和ISO 4217货币代码 你可以使用NumberFormatter示例 对金额进行格式化
在售货亭app中 我们在订单汇总屏幕上 使用NumberFormatter 这在用户区域中 是一个格式化总金额的绝佳手段 但是请注意图中 是如何显示乌拉圭比索的总金额的 就在模态对话框后面 你会发现此Caffè 在帕默路五号 位于得克萨斯州 为正确格式化金额 我们需要将货币代码设置为美元 将格式类型设置为预定义的货币类型之后 你还需要设置 自己NumberFormatter的区域和货币代码 货币代码是三个字母的代码 在大多数情况下 由国家两个字符的互联网代码 再加一个表示货币单位的额外字符组成 例如 加元的货币代码是CAD NumberFormatter区域的示例属性 决定了许多格式化程序的属性默认值 比如货币代码和十进制分隔符 通过设置货币代码和区域 我们可以根据用户和业务偏好来展示价格 你可以通过观看今年 关于格式化程序的演讲 来了解更多这方面的内容 为了提供良好的用户体验 我们的企业app应该本地化到 用户阅读的首选语言 对于用户界面文件 Xcode 生成了一个扩展名为.strings的文件 该文件包含了文本的占位符 本地化人员会稍后进行翻译
通过观看这些演讲 了解如何用最佳的方式地本地化你的app 通过了解Caffè Macs app 我们回顾了如何使用用户偏好 来提供默认的定位体验 定位服务通过提供基于位置的产品和服务 得到了更进一步地发展 国际化能确保你的app在世界各地 提供良好的体验 Caffè Macs app 在微观和宏观层面上 结合了定位优势 这让我们能够为Apple的员工 提供一种很棒的体验 我们期待着看到 你如何将所学应用到自己的app上 我们也迫不及待地想看到 你所创建的内容 谢谢大家
-
-
3:28 - Preferences: User-defined Preferred Location
// Storing the user’s preference using UserDefaults UserDefaults.standard.set(defaultLocation.id, forKey: "defaultLocationId") let defaultLocationId = UserDefaults.standard.integer(forKey: "defaultLocationId")
-
6:14 - Location Services: Requesting Authorization
// Add NSLocationWhenInUseUsageDescription to your Info.plist // e.g. “Location is required for placing orders while using the app." locationManager.requestWhenInUseAuthorization() func locationManager( _ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { switch status { case .restricted, .denied: disableLocationFeatures() case .authorizedWhenInUse, .authorizedAlways: enableLocationFeatures() case .notDetermined: // The user hasn’t chosen an authorization status } }
-
7:02 - Location Services: Determining Device Support
if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) { // Supports region monitoring to detect beacon regions } if CLLocationManager.isRangingAvailable() { // Supports obtaining the relative distance to a nearby iBeacon device }
-
8:54 - Stage 1: Region Monitoring
// Stage 1: Region Monitoring func monitorBeacons() { if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) { let constraint = CLBeaconIdentityConstraint(uuid: proximityUUID) let beaconRegion = CLBeaconRegion( beaconIdentityConstraint: constraint, identifier: beaconID ) self.locationManager.startMonitoring(for: beaconRegion) } }
-
9:30 - Stage 2: Beacon Ranging
// Stage 2: Beacon Ranging func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) { guard let region = region as? CLBeaconRegion, CLLocationManager.isRangingAvailable() else { return } let constraint = CLBeaconIdentityConstraint(uuid: region.uuid) manager.startRangingBeacons(satisfying: constraint) beaconsToRange.append(region) } func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) { }
-
10:09 - Stage 2: Beacon Ranging
// Stage 2: Beacon Ranging func locationManager( _ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) { guard let nearestBeacon = beacons.first else { return } let major = CLBeaconMajorValue(truncating: nearestBeacon.major) let minor = CLBeaconMinorValue(truncating: nearestBeacon.major) switch nearestBeacon.proximity { case .near, .immediate: displayInformation(for: major, and: minor) default: handleUnknownOrFarBeacon(for: major, and: minor) } }
-
11:32 - Formatting Dates
// Formatting Dates let dateFormatter = DateFormatter() dateFormatter.dateStyle = .medium dateFormatter.timeStyle = .short dateFormatter.string(from: Date()) // "Jun 25, 2020 at 9:41 AM"
-
12:41 - Configuring the Format of Currency
// Configuring the Format of Currency let formatter = NumberFormatter() formatter.currencyCode = "CAD" formatter.numberStyle = .currency formatter.string(from: amount) // "CA$1.00"
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。