注册

iOS 组件开发教程——手把手轻松实现灵动岛

1、先在项目里创建一个Widget Target


2、一定要勾选 Include live Activity,然后输入名称,点击完成既可。


3、在 Info.plist 文件中声明开启,打开 Info.plist 文件添加 NSSupportsLiveActivities,并将其布尔值设置为 YES。

4、我们创建一个IMAttributes,

struct IMAttributes: ActivityAttributes {
public typealias IMStatus = ContentState

public struct ContentState: Codable, Hashable {
var callName: String
var imageStr : String
var callingTimer: ClosedRange<Date>
}

var callName: String
var imageStr : String
var callingTimer: ClosedRange<Date>
}

5、灵动岛界面配置

struct IMActivityWidget: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: IMAttributes.self) { context in
// 创建显示在锁定屏幕上的演示,并在不支持动态岛的设备的主屏幕上作为横幅。
// 展示锁屏页面的 UI

} dynamicIsland: { context in
// 创建显示在动态岛中的内容。
DynamicIsland {
//这里创建拓展内容(长按灵动岛)
DynamicIslandExpandedRegion(.leading) {
Label(context.state.callName, systemImage: "person")
.font(.caption)
.padding()
}
DynamicIslandExpandedRegion(.trailing) {
Label {
Text(timerInterval: context.state.callingTimer, countsDown: false)
.multilineTextAlignment(.trailing)
.frame(width: 50)
.monospacedDigit()
.font(.caption2)
} icon: {
Image(systemName: "timer")
}
.font(.title2)
}
DynamicIslandExpandedRegion(.center) {
Text("\(context.state.callName) 正在通话中...")
.lineLimit(1)
.font(.caption)
.foregroundColor(.secondary)
}

}
//下面是紧凑展示内容区(只展示一个时的视图)
compactLeading: {
Label {
Text(context.state.callName)

} icon: {
Image(systemName: "person")
}
.font(.caption2)
} compactTrailing: {
Text(timerInterval: context.state.callingTimer, countsDown: true)
.multilineTextAlignment(.center)
.frame(width: 40)
.font(.caption2)
}
//当多个Live Activities处于活动时,展示此处极小视图
minimal: {
VStack(alignment: .center) {
Image(systemName: "person")


}
}
.keylineTint(.accentColor)
}
}
}

6、在需要的地方启动的地方调用,下面是启动灵动岛的代码

        let imAttributes = IMAttributes(callName: "wqd", imageStr:"¥99", callingTimer: Date()...Date().addingTimeInterval(0))

//初始化动态数据
let initialContentState = IMAttributes.IMStatus(callName: name, imageStr: "ia.imageStr", callingTimer: Date()...Date().addingTimeInterval(0))

do {
//启用灵动岛
//灵动岛只支持Iphone,areActivitiesEnabled用来判断设备是否支持,即便是不支持的设备,依旧可以提供不支持的样式展示
if #available(iOS 16.1, *) {
if ActivityAuthorizationInfo().areActivitiesEnabled == true{

}
} else {
// Fallback on earlier versions
}
let deliveryActivity = try Activity<IMAttributes>.request(
attributes: imAttributes,
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)")
}
6.此处只有一个灵动岛,当一个项目有多个灵动岛时,需要判断更新对应的activity

func update(name:String) {
Task {

let updatedDeliveryStatus = IMAttributes.IMStatus(callName: name, imageStr: "ia.imageStr", callingTimer: Date()...Date().addingTimeInterval(0))

for activity in Activity<IMAttributes>.activities{
await activity.update(using: updatedDeliveryStatus)
}
}
}

7、停止灵动岛

func stop() {
Task {
for activity in Activity<IMAttributes>.activities{
await activity.end(dismissalPolicy: .immediate)
}
}
}


1 个评论

学到了,刚好要适配灵动岛,感谢博主。

要回复文章请先登录注册