Understanding Dynamic Island and Live Activities

Emre Karaoğlu
Appcent
Published in
4 min readMar 22, 2024

Hi, Hello and Welcome! Today we are going to talk about Dynamic Island and Live Activities. Dynamic island is a new feature that appears on iPhone 14 Pro and above devices. It was officially announced for devices running iOS 16.1 and above. Let’s jump into it without further ado.

Example Usage of Dynamic Island

Types of Dynamic Island

The dynamic island and live activity appears to us in various forms in various situations. Let’s take a look at that before everything else.

Here are some examples about Dynamic Island and Activity Kit;

Example of Live Activity
Example of Dynamic Island

Usage Example

Now let’s create a real life scenario. Let’s say you log into an app and create an account. Afterwards, you will see a countdown timer reflecting the validity period of the code sent to you for email or SMS confirmation. You need to see the remaining time on your dynamic island and live activity.

Let’s create an Xcode Project. Xcode -> File -> New -> Project.

Then go to Xcode -> File -> New -> Target… Select iOS and search for “Widget Extension” You are going to see something like this;

Click to “Next” and on the next page make sure that “Include Live Activity” is enabled.

Then hit “Finish” and you are going to see your extension on Project Navigator! Probably something like this;

You can move on with this template or create your own structure like mine.

Before we move on I’m going to create an Attribute to pass any content into dynamic island. Live activities such as on dynamic island and on the lock screen they do need an attribute to communicate. That’s how they become dynamic. I do need to pass my timer’s endDate from app to widgetExtension target so i need something similar to this;

struct SmsAndOTPAttribute: ActivityAttributes {
public struct ContentState: Codable, Hashable {
var endDate: Date?
}
}

Then Let’s create our Activity Configuration.

        ActivityConfiguration(for: SmsAndOTPAttribute.self) { context in
// Live Activity view here!
} dynamicIsland: { context in
DynamicIsland {
DynamicIslandExpandedRegion(.leading) {
// Expanded Leading
}
DynamicIslandExpandedRegion(.trailing) {
// Expanded Trailing
}
DynamicIslandExpandedRegion(.center) {
// Expanded Center
}
} compactLeading: {
// Compact Leading
} compactTrailing: {
// Compact Trailing
} minimal: {
// Minimal
}
}

As you can see you can manage all presentation types of Dynamic Island and Live Activity right there.

Let me show you what these are meant;

Expanded Regions
Compact Leading and Trailing

Now, we are going to need some sort of manager to handle the communication between our app and widget target. There are many ways to do that but I’m going to make something like DynamicIslandManager.

import Foundation
import ActivityKit

@available(iOS 16.1, *)
final class DynamicIslandManager {

private init() {}
static var shared: DynamicIslandManager = DynamicIslandManager()
private var endDate: Date?
private var contentState: SmsAndOTPAttribute.ContentState? {
guard let endDate = endDate else {
return nil
}
return SmsAndOTPAttribute.ContentState( endDate: endDate)
}
private var activity: Activity<SmsAndOTPAttribute>?

func showDynamic(endDate: Date) {
self.endDate = endDate
do {
activity = try Activity<SmsAndOTPAttribute>.request(attributes: SmsAndOTPAttribute(), contentState: contentState ?? SmsAndOTPAttribute.ContentState(), pushType: nil)
} catch {
print(error.localizedDescription)
}
}

func endDynamic() {
Task {
await activity?.end(dismissalPolicy: .immediate)
}
}
}

Then in our ViewController call these methods.

// MARK: - Dynamic Island Methods
extension ViewController {
@available(iOS 16.1, *)
private func showDynamicIsland() {
DynamicIslandManager.shared.showDynamic(endDate: expireDate)
}

@available(iOS 16.1, *)
private func hideDynamicIsland() {
DynamicIslandManager.shared.endDynamic()
}
}

You can pass any data like that to your widgetExtension from your app.

Uh, and one more thing! Don’t forget to add a key to your app’s Info.plist which is:

<key>NSSupportsLiveActivities</key>
<true/>

Now let’s see the result!

Oh, It works! By the way i have to remind you that not all data are suitable for dynamic island. As you can see on Always-On Display mode content isn’t updated regularly but it continues on the background for a while. So be carefull about what you put into your live activities.

I’m not going to tell you more about the views that i’ve added into Dynamic Island. Instead i’m going to give you the project link so you can check it out or change it according to your needs.

Thanks for reading it, I hope you understand the point. If you have further questions please comment below, I’d like to help.

--

--

Emre Karaoğlu
Appcent
Writer for

Hey, it's a me Emre! Join me in my iOS developer journey.