iOS_灵动岛<Dynamic Island>

简介

苹果在 iPhone 14 Pro 及 iPhone 14 Pro MAX 上推出了灵动岛。灵动岛可以通过点按、长按、轻扫来进行交互,最多支持两个应用同时“登岛”。
灵动岛全称 Dynamic Island,作为 iOS 中实时活动(Live Activities)功能的一部分,用来展示需要实时更新的消息。

  • 展现形式
    展现形式有三种:Compact <紧凑>、Minimal <最小化>、Expanded <扩展>,在开发提交的时候,必须适配这三种形式
  • UI尺寸适配<尺寸单位Points>
    圆角半径均为 44
机型 紧凑< Leading Side> 紧凑< Trailing Side > 最小化 扩展
14 Pro 52.33 * 36.67 52.33 * 36.67 36.67 * 36.67 371 * (84-160)
14 Pro Max 62.33 * 36.67 62.33 * 36.67 36.67 * 36.67 408 * (84-160)
  • 颜色适配
    无法更改灵动岛的背景颜色,只能更改文字颜色、素材颜色、灵动岛边框颜色等。UI 适配需要考虑系统的深色模式,必要情况可以使用两套 UI。

  • 开发适配

    • 苹果在 iOS 16.1 正式对外开放了灵动岛适配框架 ActivityKit,第三方 App 可以使用这些 ActivityKit 完成灵动岛适配工作。注意 ActivityKitAPI 目前仅适用于 iPhone。灵动岛使用 WidgetKitSwiftUI 完成 UI 开发工作,ActivityKit 在其中扮演创建 Activity,请求数据,更新数据,结束 Activity 的角色。
    • 需要打开"实时活动权限",才可以使用灵动岛功能。
  • 开发注意要点

    • 灵动岛的实时信息要有明确的开始和结束时间点
    • 当一个实时信息持续超过 8 小时,系统会从灵动岛移除这个 App 的信息
    • 当一个实时活动结束时,灵动岛上的展示信息也会立即被系统移除
    • App 要能够响应灵动岛的点击信息,跳转到 App 中的正确子页面,而不是停留在 App 的首页

开发

新增权限

在主项目的Info.plist中添加NSSupportsLiveActivities = YES

创建小组件

  1. Xcode 中打开你的 App 项目,并选取File(文件) >New(新建) >Target(目标)。
  2. Application Extension(App 扩展) 组中,选择Widget Extension(小组件扩展),然后点按Next(下一步)。
  3. 输入你的扩展的名称。
  4. 如果小组件提供用户可配置的属性,请选中Include Configuration Intent(包含配置意图) 复选框。
  5. 点按Finish(完成)。

编写小组件

编写数据模型

数据模型,需要遵循ActivityAttributes协议

struct DynamicAttributes: ActivityAttributes {
    
    
    // 动态数据
    public struct ContentState: Codable, Hashable {
    
    
        var value: Int
    }
    // 静态数据
    var name: String
}

编写页面样式<SwiftUI>

struct DynamicLiveActivity: Widget {
    
    
    var body: some WidgetConfiguration {
    
    
        ActivityConfiguration(for: DynamicAttributes.self) {
    
     context in
            // 通知区域
            // Lock screen/banner UI goes here
            VStack {
    
    
                Text("Hello")
            }
            .activityBackgroundTint(Color.cyan)
            .activitySystemActionForegroundColor(Color.black)

        } dynamicIsland: {
    
     context in
            DynamicIsland {
    
    
                // 扩展
                // Leading Space
                DynamicIslandExpandedRegion(.leading) {
    
    
                    Text("Leading")
                }
                // Bottom
                DynamicIslandExpandedRegion(.bottom) {
    
    
                    Text("bottom")
                }
                // Trailing Space
                DynamicIslandExpandedRegion(.trailing) {
    
    
                   Text("trailing")
                }
                // Center Space
                DynamicIslandExpandedRegion(.center) {
    
    
                    Text("center")
                }                
            } compactLeading: {
    
    
                // 紧凑
                Text("L")
            } compactTrailing: {
    
    
                // 紧凑
                Text("T")
            } minimal: {
    
    
                // 最小化
                Text("Min")
            }
            .widgetURL(URL(string: "http://www.apple.com"))
            .keylineTint(Color.red)
        }
    }
}

数据更新

class DynamicManager {
    
    
    static let shared: DynamicManager = DynamicManager()
    private init () {
    
    }
    /// 开始
    /**
     active 处于活动中
     ended 已经终止且不会有任何更新,但依旧在锁屏界面展示
     dismissed 结束且不再展示
     */
    func stratDynamicActivity() {
    
    
        // 初始化静态数据
        let dynamicAttributes = DynamicAttributes(name: "ceshi", data: "ceshiData")
        // 初始化动态数据
        let initialContentState = DynamicAttributes.ContentState(value: 100, id: 1000)
        
        do {
    
    
            // 启用灵动岛
            // 灵动岛只支持iPhone,areActivitiesEnabled用来判断设备是否支持,
            // 即便是不支持的设备,依旧可以提供不支持的样式展示
            if ActivityAuthorizationInfo().areActivitiesEnabled == true {
    
    
                        
            }
            let deliveryActivity = try Activity<DynamicAttributes>.request(attributes: dynamicAttributes,contentState: initialContentState,pushType: nil)
            // 判断启动成功后,获取推送令牌 ,发送给服务器,用于远程推送Live Activities更新
            // 不是每次启动都会成功,当已经存在多个Live activity时会出现启动失败的情况
            if deliveryActivity.activityState == .active{
    
    
                _ = deliveryActivity.pushToken
            }
            // deliveryActivity.pushTokenUpdates //监听token变化
            print("Current activity id -> \(deliveryActivity.id)")
        } catch (let error) {
    
    
            print("Error info -> \(error.localizedDescription)")
        }
    }
    /// 更新
    func updateDynamicActivity() {
    
    
        Task {
    
    
            let newContent = DynamicAttributes.ContentState(value: 10, id: 10)
            //此处只有一个灵动岛,当一个项目有多个灵动岛时,需要判断更新对应的activity
            for activity in Activity<DynamicAttributes>.activities {
    
    
                await activity.update(using: newContent)
            }
        }
    }
    /// 停止
    /**
     结束分为两种
     .default 系统默认,结束后在锁屏界面保留4小时
     .immediate 立即结束,不会在锁屏界面停留
     */
    func stopDynamicActivity() {
    
    
        Task {
    
    
            //此处只有一个灵动岛,当一个项目有多个灵动岛时,需要判断更新对应的activity
            for activity in Activity<DynamicAttributes>.activities {
    
    
                await activity.end(nil,dismissalPolicy: .immediate)
            }
        }
    }
}


注意事项
灵动岛的活动状态一共有3种:
active 处于活动中
ended 已经终止且不会有任何更新,但依旧在锁屏界面展示
dismissed 结束且不再展示


参考链接:苹果开发网站

猜你喜欢

转载自blog.csdn.net/FlyingKuiKui/article/details/131281542
今日推荐