Search

[실험실] SwiftUI - Widget 사용해보기

제 위젯위젯이 응답을 하지 않아서 약간쓰.. 눈물날 뻔.. 😌
이번주도 뒹굴거려서 늦게나마 위젯 열차에 탑승했고, 제 열차는 브레이크가 없어서 생사의 기로에 왔다감 ^^! 와!
저는 정말 제가 해야하는 것만 했어요 .. . ^^*
QR코드는 위젯이 하나밖에 없잖아효? 그래서 그것만 했습니다 .. . ^^*
선배들은 뭐 그렇게 많이 한 거 ㅇ ㅑ..?

SwiftUI

일단 다른 분들이랑 비슷하게 코드를 짰습니다.
struct QRWidgetEntryView : View { var entry: Provider.Entry private static let deeplinkURL: URL = URL(string: "widget://qrcode")! var body: some View { ZStack { Color.init(UIColor.init(red: 249/255, green: 224/255, blue: 7/255, alpha: 1.0)) Image("WidgetBackground") .resizable() .frame(width: 145, height: 130, alignment: .center) } .widgetURL(QRWidgetEntryView.deeplinkURL) } } @main struct QRWidget: Widget { let kind: String = "QRWidget" var body: some WidgetConfiguration { IntentConfiguration(kind: kind, intent: ConfigurationIntent.self, provider: Provider()) { entry in QRWidgetEntryView(entry: entry) } .configurationDisplayName("Kakao QR Widget") .description("클론코딩을 통한 Kakao QR 위젯입니다.") .supportedFamilies([.systemSmall]) } }
Swift
복사
크게 다를 바는 없고 저는 딱 위젯만 만들어서 .systemSmall 사이즈 하나만 넣어줬어요.
body에는 일단 ZStack으로 색깔과 Image를 넣어줬고,
꿀팁일지는 모르겠지만 Color로 UIColor를 SwiftUI에서는 쓸 수 없어요 . . 그래서 저렇게 init을 사용해서 UIColor를 넣어줘야 합니다.. 😉

Deeplink

앱에 뎁스를 줘서 열기 위한 고군분투가 시작됐습니다. 안 열려요.
첫번째 도전
Link를 사용했습니다.
그 분은 아쉽게도 탈락을 했습니다.
탈락사유 : 일단 밑에 있는 이 링크의 블로그님의 예제를 보고 똑같이 따라했지만 저는 뎁스가 있게 열 수 없었습니다. 왜냐면 LinkMedium Large 크기의 위젯에서만 사용 가능하다고 합니다. small의 경우는 안된다고 하네요 . .. 분명 하면서 봤는데 출처를 찾아올 수 없습니다. 제 꿈 속 일지도 😉😉
두번째 도전
widgetURL를 사용했습니다.
이 분으로 성공했습니다.
저어..는 일단 현규 교수님의 블로그의 도움을 받았구요.
그 다음부터 안에 있는 코드들을 Reactor에 맞게 바꿔줬습니다.
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { let qrcodeLinkPath = "" guard let components = NSURLComponents(url: url, resolvingAgainstBaseURL: true), let path = components.path else { return false } if path == qrcodeLinkPath { var nextVC = QRCodeVC() nextVC.bind(reactor: QRCodeReactor(root: nextVC)) nextVC.modalPresentationStyle = .overFullScreen if var rootVC = window?.rootViewController as? MainVC { rootVC.useWidget = true rootVC.bind(reactor: MainReactor()) } return true } else { return false } }
Swift
복사
AppDelegate에서는 이런식으로 쓰는데 만약에 SceneDelegate를 쓴다면
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { if let url = URLContexts.first?.url { if url.absoluteString.starts(with: "widget://pr") { guard let urlComponents = URLComponents(string: url.absoluteString) else { return } guard let pullRequestUrl = urlComponents.queryItems?.first(where: { $0.name == "url" })?.value else { return } let prDetailViewController = PRDetailViewController(urlString: pullRequestUrl) (self.window?.rootViewController as? UINavigationController)?.pushViewController(prDetailViewController, animated: true) } }
Swift
복사
요런 형식을 써주시면 됩니다.
url이라고 써있는 매개변수들로 우리가 넣어준 url들이 들어오면서 해당 함수가 쇽샥 돌아갑니다.
그리고 안에 있는 코드들을 실행시켜줄거예요. 든든하죠. 든든댄스 든든댄스.😉

Reactor

솔직히 저번주에 뷰를 짜면서 어느정도 Reactor 세팅을 마쳤더니 이번에는 크게 세팅해줄 점은 없었습니다.
이번에는 AppDelegate에서 저런 식으로 뷰를 열어줬을 때(위젯 사용),
Reactor를 bind해주지 않으면 Present가 안되길래 애를 좀 먹었고, 안에다가 Present하는 코드를 짜는 것도 애먹었습니다.. . . eat 애 many many . .
func bindReactor() { if useWidget { Observable.just("") .map { _ in Reactor.Action.shake(vc: self) } .bind(to: reactor.action) .disposed(by: bag) } }
Swift
복사
이런식으로 useWidget이 true이면, 저 코드를 실행할건데요.
just 자체가 들어오는 단 하나의 Observable만 바로바로 처리하는 애라서 아모튼 저렇게 map에 있는 shake(QR열어주는 코드)를 실행하도록 했습니다.
useWidget은 위에 AppDelegate 코드를 보면 알겠지만, 저 부분에서 들어가는거라면 true가 되도록 했습니다.