当前位置: 代码网 > it编程>App开发>苹果IOS > 带你走进灵动岛

带你走进灵动岛

2024年05月12日 苹果IOS 我要评论
苹果在 iPhone 14 Pro 及 iPhone 14 Pro MAX 上推出了灵动岛,是一次交互玩法的革新。本文从灵动岛的展现形式、场景限制、适配情况和远程通知更新数据几个方面全面带你走进灵动岛 ...

前言

ios最近几年新特性

ios14 视频画中画 applibrary 桌面小组件 照片隐私加强 应用限免 智能折叠 全新siri悬浮显示
ios15 facetime支持屏幕共享 信息和新增拟我表情 推出专注模式 通知重新设计,图标变得更大 地图公共交通路线置顶,增加时间显示 识别图片上文字信息 支持照片信息和照片上的文字进行搜索
ios16 ios 16 锁定界面 锁定界面小组件 锁屏界面的实时活动 iphone锁定全屏幕音乐播放器 电池百分比出来啦 视频实况文本 快速查询wi-fi密码
ios17 设置您的待机屏幕 优先考虑交互式小部件 定制您的联系海报 创建您自己的贴纸 设置新的 safari 配置文件 开启反追踪 分享您的 icloud 钥匙串密码

一、简介

实时活动(live activity),是ios16新增的扩展组件功能,可以在灵动岛和锁定屏幕上显示应用程序的实时数据。用于追踪事件和任务进度实时活动的开始和结束都是离散的,具体画面场景如下:苹果

苹果在 iphone 14 pro 及 iphone 14 pro max 上推出了灵动岛。灵动岛将 iphone 前置镜头和软件通知结合在一起的全新设计,用出色的交互设计掩盖硬件的缺陷,是一次交互玩法的革新。灵动岛可以通过点按、长按、轻扫来进行交互,最多支持两个应用同时“登岛”。

灵动岛全称 dynamic island,作为 ios 中实时活动(live activities)功能的一部分,用来展示需要实时更新的消息。例如外卖配送信息,地图实时导航信息等。灵动岛有 3 种展现形式。

1.1 展现形式

1.1.1 紧凑(compact)

当系统只有 1 个实时活动的内容时,灵动岛默认使用紧凑模式。紧凑模式下ui由头部(leading side)和尾部(trailing side)组成,如图所示。用户可以点击灵动岛打开 app 查看实时活动的内容

1.1.2 最小化(minimal)

当系统有多个实时活动的内容时,灵动岛自动切换使用最小化模式。最小化模式下由附着的头部(leading(attached))和分割开的尾部(trailing(detached))组成,如图所示。和紧凑模式一样,最小化模式也支持用户点击打开 app。

1.1.3扩展(expanded)

当用户在紧凑或最小化模式轻扫或长按灵动岛时,灵动岛可以切换成扩展模式。用于向用户展示更多信息。扩展模式的 ui

设计尽量保持和紧凑模式一致,用户从紧凑模式切换到扩展模式会有一个平滑的体验。

当我们向 app store 提交了适配灵动岛的 app 版本时,以上 3 种模式都需要适配。

二、场景限制

2.1样式限制

1、实时活动针对锁定屏幕和灵动岛提供了不同的视图。锁定屏幕可以出现在所有支持 ios 16 的设备上。而灵动岛在支持设备上,使用以下视图显示实时活动:紧凑前视图、紧凑尾视图、最小视图和扩展视图。

2、当用户触摸灵动岛,且灵动岛中有紧凑或最小视图,同时实时活动更新时,会出现扩展视图。在不支持灵动岛的设备上,扩展视图显示为实时活动更新的横幅。

3、为确保系统可以在每个位置显示 app 的实时活动,开发者必须支持所有视图

建议:同场景多卡片由于样式趋同且折叠,不建议同时创建多卡片

灵动岛页面需要实现的部分有4个:

a、不支持灵动岛的机型 或 锁屏时的 显示

b、紧凑级展示(即左右贴合灵动岛的展示)

c、多live activity时的展示(即极小视图,左贴合,右分离)

d、扩展视图(长按灵动岛时触发)

备注:还有一个app同时存在的实时活动面板最多只能创建5个,这也是一个场景约束条件。error requesting delivery live activity the operation couldn’t be completed. maximum number of activities for target already exists

2.2 时间限制

实时活动最多可以保持八小时的活动状态,除非其应用程序或人员在此限制之前结束活动。超过八小时限制后,系统自动结束直播活动,并立即将其移出动态岛。但是,实时活动会保留在锁定屏幕上,直到有人将其删除,或者在系统将其删除之前最多再保留四个小时(以先到者为准)。因此,实时活动在锁定屏幕上保留最多 12 小时。

官方表述:https://developer.apple.com/documentation/activitykit/displaying-live-data-with-live-activities

a live activity can be active for up to eight hours unless your app or a person ends it before this limit. after the 8-hour limit, the system automatically ends it. when a live activity ends, the system immediately removes it from the dynamic island. however, the live activity remains on the lock screen until a person removes it or for up to four additional hours before the system removes it — whichever comes first. as a result, a live activity remains on the lock screen for a maximum of twelve hours.

2.3 数据更新

每个实时活动运行在自己的沙盒中,与小组件不同的是,它无法访问网络或接收位置更新。若要更新实时活动的动态数据,少量(不能超过4kb)数据可通过远程推送通知发送,或通过activitykit 框架后台活动刷新数据。

activitykit 更新和 activitykit 推送通知的更新动态数据大小不能超过 4 kb。

2.4 网络限制

a、卡片本身禁止定位以及网络请求,数据刷新依赖本地刷新,实施活动推送刷新,同2)所述;

b、live activity内部禁用网络图片,传统的服务端传图片url的方式无法满足实际使用,但是希望传入订单图片来个性化地表达并且区分不同订单。

ios 16 beta版创建时可以通过将图片转为data格式传入卡片,但是ios16.1该方案仅限传入4kb左右的图片(api限制),因此暂时不考虑非本地图片方案,采用内置图片方式实现。

2.5 埋点限制

场景情况:由于默认情况点击是回主程序,而并不是固定页面,因此有必要自定义widgeturl(如用于回到订单页面),也可以通过link实现分区域的跳转,link和widgeturl共存时,点击link区域会响应link,因此两者同时使用即可。

无法在widget内部直接添加埋点,并且灵动岛收起时,仅支持添加同一个widgeturl,对于收起状态添加link并没有响应。

埋点方式:因为点击直接跳转到主app,因此考虑将埋点参数加入url参数即可,主app解析时埋点。但是无法记录包括用户查看、用户关闭(关闭卡片 继续发送推送也没有报错 因此无法判断)等行为的埋点。

对于灵动岛的区分,实际测试发现,在展开模式下,可以加入link并且可以正常响应,这与官方文档中的描述一致。

三、适配

3.1 ui适配

1、尺寸

目前只有 iphone 14 pro 及 iphone 14 pro max 具有灵动岛功能。在两种机型上,灵动岛的圆角半径都为 44points,这个数值和前置深感摄像头的半径是一样的。按照前述的 3 种模式,灵动岛的具体参数如下表格所示(表格涉及的数值表示points)。

机型 屏幕尺寸 紧凑模式(头部) 紧凑模式(尾部) 最小化模式 展开模式
iphone 14 pro 393*852 52.33*36.67 52.33*36.67 36.67*36.67 371*(84-160)
iphone 14 pro max 430*932 62.33*36.67 62.33*36.67 36.67*36.67 408*(84-160)

2、颜色

开发者无法更改灵动岛的背景颜色,只能更改文字颜色、素材颜色、灵动岛边框颜色等。ui 适配需要考虑系统的深色模式,必要情况可以使用两套 ui。

3.2开发适配

3.2.1开发框架简介

苹果在 ios 16.1 正式对外开放了灵动岛适配框架activitykit,第三方 app 可以使用这些activitykit完成灵动岛适配工作。注意activitykit的 api 目前仅适用于 iphone。灵动岛使用widgetkitswiftui完成 ui 开发工作,activitykit在其中扮演创建activity,请求数据,更新数据,结束activity的角色。

3.2.2权限管理

灵动岛作为实时活动的一部分,需要实时活动权限才能正常展示。和通知权限,相机权限等类似,实时活动权限需要 app

3.2.3 生命周期

request

update

observe avtivity state

end

import activitykit

struct adventureattributes: activityattributes {
//不可变
    let hero: emojiranger
    /// the associated type that describes the dynamic content of a live activity.
    ///
    /// the dynamic data of a live activity that's encoded by `contentstate` can't exceed 4kb.
    struct contentstate: codable & hashable {
        let currenthealthlevel: double
        let eventdescription: string
    }
}





let adventure = adventureattributes(hero: hero)

let initialstate = adventureattributes.contentstate(
    currenthealthlevel: hero.healthlevel,
    eventdescription: "adventure has begun!"
)
let content = activitycontent(state: initialstate, staledate: nil, relevancescore: 0.0)

let activity = try activity.request(
    attributes: adventure,
    content: content,
    pushtype: nil
)





let heroname = activity.attributes.hero.name               
let contentstate = adventureattributes.contentstate(
    currenthealthlevel: hero.healthlevel,
    eventdescription: "\(heroname) has taken a critical hit!"
)

var alertconfig = alertconfiguration(
    title: "\(heroname) has taken a critical hit!",
    body: "open the app and use a potion to heal \(heroname)",
    sound: .default
)  
     
activity.update(
    activitycontent<adventureattributes.contentstate>(
        state: contentstate,
        staledate: nil
    ),
    alertconfiguration: alertconfig
)





// observe activity state asynchronously
func observeactivity(activity: activity<adventureattributes>) {
    task {
        for await activitystate in activity.activitystateupdates {
            if activitystate == .dismissed {
                self.cleanupdismissedactivity()
            }
        }
    }
}

// observe activity state synchronously
let activitystate = activity.activitystate
if activitystate == .dismissed {
    self.cleanupdismissedactivity()
}





let hero = activity.attributes.hero

let finalcontent = adventureattributes.contentstate(
    currenthealthlevel: hero.healthlevel,
    eventdescription: "adventure over! \(hero.name) has defeated the boss! congrats!"
)

let dismissalpolicy: activityuidismissalpolicy = .default

activity.end(
    activitycontent(state: finalcontent, staledate: nil),
    dismissalpolicy: dismissalpolicy)
}

3.2.4ui



import widgetkit
import swiftui

@main
struct emojirangerswidgetbundle: widgetbundle {
    var body: some widget {
        emojirangerwidget()
        leaderboardwidget()
        adventureactivityconfiguration()
    }
}





struct adventureactivityconfiguration: widget {
    var body: some widgetconfiguration {
        activityconfiguration(for: adventureattributes.self) { context in
            // ...
            // create the view that appears on the lock screen and as a
            // banner on the home screen of devices that don't support the
            // dynamic island.
        } dynamicisland: { context in
 // create the views that appear in the dynamic island.
            dynamicisland {
                // create the expanded view.
                // leading region
                

                // expanded region
                

                // bottom region
                 
            } compactleading: {
                // create the compact leading view.
                // ...
            } compacttrailing: {
                // create the compact trailing view.
                // ...
            } minimal: {
                // create the minimal view.
                // ...
            }
        }
    }
}





四、远程通知更新数据

实时活动也支持远程推送更新,根据文档以下9点要求实现(avtivity远程推送每小时有通知预算(数量未明确),超出后系统将关闭通知)

1、确保启动activity时[request(attributes:contentstate:pushtype:)传入pushtype参数(.token);

2、获取启动后的activity的推送令牌pushtoken,传给服务端用来推送更新activity;(实时活动的pushtoken不是消息通知的token,这个是独立出来的)

3、服务端推送的更新内容字段需要和activityattributes的contentstate中定义的动态数据字段对应;

4、设置推送的报头apns-push-type的值为liveactivity;

5、设置推送的报头apns-topic的值为.push-type.liveactivity;

6、正确的推送对应的内容和状态;

7、使用pushtokenupdates监听pushtoken变化,如有变化,就令牌失效,需要将新的令牌传给服务器;

8、当activity结束时,服务器端的pushtoken将失效;

{
    "aps": {
        "timestamp": 1685952000,
        "event": "update",
        "content-state": {
            "currenthealthlevel": 0.0,
            "eventdescription": "power panda has been knocked down!"
        },
        "alert": {
            "title": "power panda is knocked down!",
            "body": "use a potion to heal power panda!",
            "sound": "default"
        }
    }
}





注意:

1、不用为推送提供声音 , 如果推送延迟,在activity结束后收到时将被忽略,avtivity每小时有通知预算(数量未明确),超出后系统将关闭通知;

2、实时活动的pushtoken不是消息通知的token,这个token上报到jdpush服务,需要单独管理和归类。

备注:

  1. 灵动岛的实时信息要有明确的开始和结束时间点

  2. 当一个实时信息持续超过 8 小时,系统会从灵动岛移除这个 app 的信息

  3. 当一个实时活动结束时,灵动岛上的展示信息也会立即被系统移除

  4. 避免在灵动岛上显示广告,毕竟引起用户反感可以被直接关闭

  5. app 要能够响应灵动岛的点击信息,跳转到 app 中的正确子页面,而不是停留在 app 的首页

运用场景

1、需在屏幕驻留的文字、图像为主的信息:如地图导航、airdrop 传输情况等;

2、后台进行的音频类:如接电话、放音乐、录音、倒计时等;

3、即时交互反馈:如充电、静音、人脸识别等。超过这三类信息后,桌面可能会变得杂乱无章

参考文章

activitykit官方文档

https://developer.apple.com/videos/play/wwdc2023/10194

https://developer.apple.com/videos/play/wwdc2023/10184

https://www.jianshu.com/p/f410eba6c392

https://www.bilibili.com/read/cv18549307/

作者:京东零售 李艳敏

来源:京东云开发者社区 转载请注明来源

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com