Implementing HealthKit in an iOS App

Introduction Previously, I worked with a healthcare app that used the HealthKit framework, but I did not get the opportunity to implement it myself. I decided to look into it and share what I found. In this article, I will focus on the steps to integrate HealthKit, write, and access its data. Preparation Before we dive into implementation, I assume that you have an active Apple Developer account; without it, you will not be able to access the HealthKit Store. Let’s add: ...

July 26, 2024 · 4 min · Dmytro Chumakov

Implementing ChatGPT in an iOS App

Introduction I haven’t had the opportunity to build a chatbot before. This topic was trending some time ago, and I always wanted to implement it myself. In this article, I will focus on the steps you need to know to successfully build and run a chatbot application. First Step The first step is to add the OpenAI dependency to your project: .package(url: "https://github.com/MacPaw/OpenAI.git", branch: "main") dependencies: [ .byNameItem( name: "OpenAI", condition: .when(platforms: [ .iOS, ]) ), ], Second Step The second step is to generate an OpenAI key and replace it inside your project. ...

July 21, 2024 · 2 min · Dmytro Chumakov

Accessibility iOS SwiftUI

Introduction Previously, I posted about Accessibility for UIKit. The idea behind this post is to find differences between UIKit Accessibility and SwiftUI features. Similarities: Both UIKit and SwiftUI have accessibilityLabel and accessibilityHints APIs. Differences: To use dynamic type for fonts, you need additional modifiers in SwiftUI. struct ScaledFont: ViewModifier { @Environment(\.sizeCategory) var sizeCategory var name: String var size: Double func body(content: Content) -> some View { let scaledSize = UIFontMetrics.default.scaledValue(for: size) return content.font(.custom(name, size: scaledSize)) } } extension View { func scaledFont(name: String, textSize size: Double) -> some View { return self.modifier(ScaledFont(name: name, size: size)) } } To step over elements in a list, you need to add .accessibilityElement(children: .combine) to each row in SwiftUI. struct FruitCaloriesCounter: View { var body: some View { NavigationView { List(fruits) { fruit in FruitRow(fruit: fruit) .accessibilityElement(children: .combine) } .navigationTitle("Fruits Calories Counter") .accessibilityElement(children: .contain) .navigationBarTitleDisplayMode(.inline) } } } In UIKit, you can insert and remove accessibilityTraits depending on the button state: if button.isSelected { button.accessibilityTraits.insert(.header) } else { button.accessibilityTraits.remove(.header) } In SwiftUI, you need to pass .accessibilityAddTraits(selected ? [.isSelected, .isButton] : .isButton) to one modifier. Button(action: { selected.toggle() }) { Image(systemName: selected ? "star.fill" : "star") .frame(width: 44, height: 44) .accessibilityLabel("favourite") .accessibilityHint(selected ? "removes favourite" : "makes favourite") .accessibilityAddTraits(selected ? [.isSelected, .isButton] : .isButton) } .buttonStyle(.plain) Complete Sample import SwiftUI let fruits = [ Fruit(name: "Apple", calories: 52), Fruit(name: "Banana", calories: 89), Fruit(name: "Orange", calories: 47), Fruit(name: "Pineapple", calories: 50), Fruit(name: "Strawberry", calories: 32) ] struct Fruit: Identifiable { var id: String { name } let name: String let calories: Int } struct FruitRow: View { @State private var selected = false let fruit: Fruit var body: some View { HStack(spacing: 8) { VStack(alignment: .leading, spacing: 8) { Text(fruit.name) .scaledFont(name: "Helvetica", textSize: 20) .accessibilityLabel(fruit.name) Text("\(fruit.calories) per 100g") .scaledFont(name: "Helvetica", textSize: 15) .accessibilityLabel("\(fruit.calories) calories per 100 grams") } Spacer() Button(action: { selected.toggle() }) { Image(systemName: selected ? "star.fill" : "star") .frame(width: 44, height: 44) .accessibilityLabel("favourite") .accessibilityHint(selected ? "removes favourite" : "makes favourite") .accessibilityAddTraits(selected ? [.isSelected, .isButton] : .isButton) } .buttonStyle(.plain) } } } struct FruitCaloriesCounter: View { var body: some View { NavigationView { List(fruits) { fruit in FruitRow(fruit: fruit) .accessibilityElement(children: .combine) } .navigationTitle("Fruits Calories Counter") .accessibilityElement(children: .contain) .navigationBarTitleDisplayMode(.inline) } } } struct ContentView: View { var body: some View { FruitCaloriesCounter() } } #Preview { ContentView() } struct ScaledFont: ViewModifier { @Environment(\.sizeCategory) var sizeCategory var name: String var size: Double func body(content: Content) -> some View { let scaledSize = UIFontMetrics.default.scaledValue(for: size) return content.font(.custom(name, size: scaledSize)) } } extension View { func scaledFont(name: String, textSize size: Double) -> some View { return self.modifier(ScaledFont(name: name, size: size)) } } Thank you for reading! 😊

June 2, 2024 · 3 min · Dmytro Chumakov

Animation - SwiftUI

Introduction I was eager to learn about creating complex animations in SwiftUI. The few questions that were on my mind included what types of animations exist and what I can animate. Here is what I found: Types of Animation SwiftUI has explicit and implicit animation types. Implicit Animation: This is specified with the .animation() modifier. SwiftUI will animate changes in old and new values. struct ImplicitAnimation: View { @State private var half = false @State private var dim = false var body: some View { Image("tower") .scaleEffect(half ? 0.5 : 1.0) .opacity(dim ? 0.2 : 1.0) .animation(.easeInOut(duration: 1.0)) .onTapGesture { self.dim.toggle() self.half.toggle() } } } ...

May 17, 2024 · 2 min · Dmytro Chumakov

Implementing In-App Purchases to SwiftUI app using StoreKit 2

Introduction I was wondering how to add in-app purchases to my app. I chose non-consumable in-app purchase because you can pay one time for this item. Here are a few steps on how I did it. First Step Set up In-App Purchases for your app in App Store Connect account or add a .storekit configuration file and start from there. If you’ve already set up In-App Purchases in your account, you can sync the StoreKit config with that data. ...

May 12, 2024 · 3 min · Dmytro Chumakov