Vidjetlar va kengaytmalar


ULASHISH

Vidjetlar va ilova kengaytmalari (App Extensions)

Kichik ma’lumotlarni App Groups yordamida ulashing va bir qarashda ko‘rinadigan qisqa ma’lumotlarni ko‘rsatish uchun WidgetKit yordamida vidjetlar yarating.


Vidjet timeline’i

Vaqt yozuvlaridan iborat timeline’ni ko‘rsatadigan vidjet yarating.

Sintaksis:

  • timeline provider’ni aniqlash uchun TimelineProvider protokoli

Misol

import WidgetKit
import SwiftUI

struct TimeEntry: TimelineEntry { let date: Date }

struct TimeProvider: TimelineProvider {
  func placeholder(in context: Context) -> TimeEntry { .init(date: Date()) }
  func getSnapshot(in context: Context, completion: @escaping (TimeEntry) -> Void) { completion(.init(date: Date())) }
  func getTimeline(in context: Context, completion: @escaping (Timeline<TimeEntry>) -> Void) {
    let entries = stride(from: 0, through: 60*30, by: 60).map { offset in
      TimeEntry(date: Date().addingTimeInterval(Double(offset)))
    }
    completion(Timeline(entries: entries, policy: .atEnd))
  }
}

struct TimeWidgetView: View {
  var entry: TimeEntry
  var body: some View { Text(entry.date, style: .time).font(.headline) }
}

@main
struct TimeWidget: Widget {
  var body: some WidgetConfiguration {
    StaticConfiguration(kind: "TimeWidget", provider: TimeProvider()) { e in TimeWidgetView(entry: e) }
  }
}
import SwiftUI

struct ContentView: View { var body: some View { Text("Widget timeline demo") } }
import SwiftUI

@main
struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } } }

Yuqoridagi misolda placeholder, snapshot va timeline provider’ga ega oddiy vidjet timeline’i ko‘rsatilgan.


Share extension karkasi

Foydalanuvchilarga kontentni ilovangiz bilan ulashish imkonini beradigan share extension yarating.

Sintaksis:

  • share extension karkasini aniqlash uchun ShareExtensionSkeleton struct’i

Misol

import SwiftUI

struct ShareExtensionSkeleton: View {
  @State private var sharedText = ""
  var body: some View {
    VStack(spacing: 12) {
      Text("Incoming content")
      TextEditor(text: $sharedText).frame(minHeight: 120).border(.secondary)
      HStack { Spacer(); Button("Post") { /* handle share */ } }
    }
    .padding()
  }
}
import SwiftUI

struct ContentView: View { var body: some View { ShareExtensionSkeleton() } }
import SwiftUI

struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } } }

Yuqoridagi misolda matn muharriri va yuborish (post) tugmasiga ega oddiy share extension karkasi ko‘rsatilgan.



App Groups (vidjet bilan ma’lumot ulashish)

Ilova uchun ham, vidjet kengaytmasi uchun ham App Groups ni yoqing va kichik ma’lumotlar almashish uchun umumiy suite’dan foydalaning.

Sintaksis: UserDefaults(suiteName: "group.id"), set(_:forKey:) bilan yozing, integer(forKey:) bilan o‘qing.

Nazorat ro‘yxati

  • App target’iga va Widget target’iga App Groups imkoniyatini (capability) qo‘shing
  • Guruh identifikatorini yarating, masalan, group.com.example.notes
import Foundation

func updateSharedNotesCount(_ count: Int) {
  let defaults = UserDefaults(suiteName: "group.com.example.notes")
  defaults?.set(count, forKey: "notesCount")
}
import WidgetKit
import SwiftUI

struct CountEntry: TimelineEntry { let date: Date; let count: Int }

struct NotesProvider: TimelineProvider {
  func placeholder(in context: Context) -> CountEntry { .init(date: Date(), count: 0) }
  func getSnapshot(in context: Context, completion: @escaping (CountEntry) -> Void) {
    let defaults = UserDefaults(suiteName: "group.com.example.notes")
    let count = defaults?.integer(forKey: "notesCount") ?? 0
    completion(.init(date: Date(), count: count))
  }
  func getTimeline(in context: Context, completion: @escaping (Timeline<CountEntry>) -> Void) {
    let defaults = UserDefaults(suiteName: "group.com.example.notes")
    let count = defaults?.integer(forKey: "notesCount") ?? 0
    let entries = [CountEntry(date: Date(), count: count)]
    completion(Timeline(entries: entries, policy: .after(Date().addingTimeInterval(1800))))
  }
}

Ushbu misol qaydlar sonini App Groups orqali ulashadi: ilova qiymatni yozadi, vidjet esa uni ko‘rsatish uchun o‘qiydi.


Vidjetlar

Xcode’da Widget Extension target’ini yarating, so‘ng WidgetKit va SwiftUI yordamida timeline/view’larni loyihalang.

Sintaksis: TimelineProvider ni realizatsiya qiling, Widget ni e’lon qiling va StaticConfiguration(kind:provider:content:) ni qaytaring.

Misol

import WidgetKit
import SwiftUI

struct Provider: TimelineProvider {
  func placeholder(in context: Context) -> SimpleEntry { .init(date: Date()) }
  func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) { completion(.init(date: Date())) }
  func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> ()) {
    completion(Timeline(entries: [.init(date: Date())], policy: .atEnd))
  }
}

struct SimpleEntry: TimelineEntry { let date: Date }

struct MyWidgetEntryView: View {
  var entry: SimpleEntry
  var body: some View { Text(entry.date, style: .time) }
}

  @main
  struct MyWidget: Widget {
    var body: some WidgetConfiguration {
      StaticConfiguration(kind: "MyWidget", provider: Provider()) { entry in
        MyWidgetEntryView(entry: entry)
      }
    }
  }
}

Yuqoridagi misolda timeline provider va statik konfiguratsiyaga ega oddiy vidjet ko‘rsatilgan.


Vidjetlardan deep link’lar

URL taqdim etish orqali vidjet bosilganda ilovangizni muayyan ekranda oching.

Sintaksis: Link va onOpenURL ni realizatsiya qiling.

Misol

import SwiftUI

struct NotesCountView: View {
  var body: some View {
    Link(destination: URL(string: "myapp://notes")!) {
      Text("Notes: \(entry.count)")
    }
  }
}
import SwiftUI

@main
struct MyApp: App {
  var body: some Scene {
    WindowGroup {
      ContentView()
        .onOpenURL { url in
          // Route based on url.host / path (e.g., "notes")
        }
    }
  }
}

Yuqoridagi misolda muayyan ekranga havolasi bor oddiy vidjet va URL’ni qayta ishlaydigan ilova ko‘rsatilgan.


Yangilash va timeline siyosati

Yangilash strategiyasini tanlang va ma’lumotlar o‘zgarganda qayta yuklashni ishga tushiring.

Sintaksis: TimelineProvider va WidgetCenter ni realizatsiya qiling.

Misol

import WidgetKit
// Update at a future date
completion(Timeline(entries: entries, policy: .after(Date().addingTimeInterval(1800))))

// Or end when entries are exhausted
// completion(Timeline(entries: entries, policy: .atEnd))
import WidgetKit

// Refresh a specific widget kind after writing new data to App Group
WidgetCenter.shared.reloadTimelines(ofKind: "NotesCount")

// Or refresh all widget kinds
// WidgetCenter.shared.reloadAllTimelines()

Yuqoridagi misolda timeline provider va statik konfiguratsiyaga ega oddiy vidjet ko‘rsatilgan.


Qo‘llab-quvvatlanadigan oilalar (families)

Vidjetingiz qaysi o‘lchamlarni qo‘llab-quvvatlashini e’lon qiling.

Sintaksis: WidgetConfiguration va supportedFamilies ni realizatsiya qiling.

Misol

import WidgetKit

@main
struct NotesCountWidget: Widget {
  var body: some WidgetConfiguration {
    StaticConfiguration(kind: "NotesCount", provider: NotesProvider()) { entry in
      NotesCountView(entry: entry)
    }
    .supportedFamilies([.systemSmall, .systemMedium])
  }
}

Yuqoridagi misolda timeline provider va statik konfiguratsiyaga ega oddiy vidjet ko‘rsatilgan.


Vidjetlarni testlash

Sintaksis: WidgetPreviewProvider va WidgetCenter ni realizatsiya qiling.

  • Widget preview provider’laridan foydalaning va vidjetni Home/Lock ekraniga qo‘shib, qurilmada sinab ko‘ring.
  • Yangilanishni tekshirish uchun App Group qiymatlarini o‘zgartiring va WidgetCenter.shared.reloadTimelines ni chaqiring.
  • Turli oilalarni (small/medium/large) va qorong‘i/yorug‘ rejimni tekshiring.


W3Schools Pathfinder

Yutuqlaringizni kuzating – bu bepul!