From ef880c67af99df90d3e1bb92e6fb46e55372c1ab Mon Sep 17 00:00:00 2001 From: lollipopkit Date: Sat, 16 Sep 2023 17:53:34 +0800 Subject: [PATCH] new: `watchOS` watch end app --- ios/Runner.xcodeproj/project.pbxproj | 224 +++++++++++++++++++++++++++ ios/WatchApp/ContentView.swift | 151 ++++++++++++++++++ ios/WatchApp/PhoneConnMgr.swift | 54 +++++++ ios/WatchApp/Store.swift | 20 +++ ios/WatchApp/WatchEndApp.swift | 17 ++ 5 files changed, 466 insertions(+) create mode 100644 ios/WatchApp/ContentView.swift create mode 100644 ios/WatchApp/PhoneConnMgr.swift create mode 100644 ios/WatchApp/Store.swift create mode 100644 ios/WatchApp/WatchEndApp.swift diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index b4827b56..0d5fa2fe 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -23,6 +23,11 @@ E39515C02AB5AC85003602C1 /* Info-Release.plist in Resources */ = {isa = PBXBuildFile; fileRef = E39515BD2AB5AC85003602C1 /* Info-Release.plist */; }; E39515C12AB5AC85003602C1 /* Info-Debug.plist in Resources */ = {isa = PBXBuildFile; fileRef = E39515BE2AB5AC85003602C1 /* Info-Debug.plist */; }; E39515C22AB5AC85003602C1 /* Info-Profile.plist in Resources */ = {isa = PBXBuildFile; fileRef = E39515BF2AB5AC85003602C1 /* Info-Profile.plist */; }; + E39515CA2AB5AD62003602C1 /* WatchEndApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E39515C92AB5AD62003602C1 /* WatchEndApp.swift */; }; + E39515CC2AB5AD62003602C1 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E39515CB2AB5AD62003602C1 /* ContentView.swift */; }; + E39515D42AB5AD64003602C1 /* WatchEnd Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = E39515C72AB5AD62003602C1 /* WatchEnd Watch App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + E39515DB2AB5AE7F003602C1 /* PhoneConnMgr.swift in Sources */ = {isa = PBXBuildFile; fileRef = E39515DA2AB5AE7F003602C1 /* PhoneConnMgr.swift */; }; + E39515DD2AB5AE9E003602C1 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = E39515DC2AB5AE9E003602C1 /* Store.swift */; }; E3DB67ED2A31FE200027B8CB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E3DB67EB2A31FE200027B8CB /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ @@ -34,6 +39,13 @@ remoteGlobalIDString = E33A3E342A626DCD009744AB; remoteInfo = StatusWidgetExtension; }; + E39515D22AB5AD64003602C1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = E39515C62AB5AD62003602C1; + remoteInfo = "WatchEnd Watch App"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -58,6 +70,17 @@ name = "Embed Foundation Extensions"; runOnlyForDeploymentPostprocessing = 0; }; + E39515D52AB5AD64003602C1 /* Embed Watch Content */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(CONTENTS_FOLDER_PATH)/Watch"; + dstSubfolderSpec = 16; + files = ( + E39515D42AB5AD64003602C1 /* WatchEnd Watch App.app in Embed Watch Content */, + ); + name = "Embed Watch Content"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -86,6 +109,11 @@ E39515BD2AB5AC85003602C1 /* Info-Release.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Info-Release.plist"; path = "../../../server_box_bak/ios/Runner/Info-Release.plist"; sourceTree = ""; }; E39515BE2AB5AC85003602C1 /* Info-Debug.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Info-Debug.plist"; path = "../../../server_box_bak/ios/Runner/Info-Debug.plist"; sourceTree = ""; }; E39515BF2AB5AC85003602C1 /* Info-Profile.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Info-Profile.plist"; path = "../../../server_box_bak/ios/Runner/Info-Profile.plist"; sourceTree = ""; }; + E39515C72AB5AD62003602C1 /* WatchEnd Watch App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "WatchEnd Watch App.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + E39515C92AB5AD62003602C1 /* WatchEndApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchEndApp.swift; sourceTree = ""; }; + E39515CB2AB5AD62003602C1 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + E39515DA2AB5AE7F003602C1 /* PhoneConnMgr.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneConnMgr.swift; sourceTree = ""; }; + E39515DC2AB5AE9E003602C1 /* Store.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = ""; }; E398BF6A29BDB34500FE4FD5 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; E3DB67EC2A31FE200027B8CB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXFileReference section */ @@ -108,6 +136,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + E39515C42AB5AD62003602C1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -138,6 +173,7 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, E33A3E3A2A626DCE009744AB /* StatusWidget */, + E39515C82AB5AD62003602C1 /* WatchApp */, 97C146EF1CF9000F007C117D /* Products */, 65C40392B90925608A0465EE /* Pods */, D242A20E381A343934B6A7B6 /* Frameworks */, @@ -149,6 +185,7 @@ children = ( 97C146EE1CF9000F007C117D /* Runner.app */, E33A3E352A626DCD009744AB /* StatusWidgetExtension.appex */, + E39515C72AB5AD62003602C1 /* WatchEnd Watch App.app */, ); name = Products; sourceTree = ""; @@ -192,6 +229,17 @@ path = StatusWidget; sourceTree = ""; }; + E39515C82AB5AD62003602C1 /* WatchApp */ = { + isa = PBXGroup; + children = ( + E39515C92AB5AD62003602C1 /* WatchEndApp.swift */, + E39515CB2AB5AD62003602C1 /* ContentView.swift */, + E39515DA2AB5AE7F003602C1 /* PhoneConnMgr.swift */, + E39515DC2AB5AE9E003602C1 /* Store.swift */, + ); + path = WatchApp; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -208,11 +256,13 @@ 3B06AD1E1E4923F5004D2608 /* Thin Binary */, AA0A1FF2F3246F84EB0D91F2 /* [CP] Embed Pods Frameworks */, E33A3E4A2A626DD0009744AB /* Embed Foundation Extensions */, + E39515D52AB5AD64003602C1 /* Embed Watch Content */, ); buildRules = ( ); dependencies = ( E33A3E482A626DD0009744AB /* PBXTargetDependency */, + E39515D32AB5AD64003602C1 /* PBXTargetDependency */, ); name = Runner; productName = Runner; @@ -236,6 +286,23 @@ productReference = E33A3E352A626DCD009744AB /* StatusWidgetExtension.appex */; productType = "com.apple.product-type.app-extension"; }; + E39515C62AB5AD62003602C1 /* WatchEnd Watch App */ = { + isa = PBXNativeTarget; + buildConfigurationList = E39515D92AB5AD64003602C1 /* Build configuration list for PBXNativeTarget "WatchEnd Watch App" */; + buildPhases = ( + E39515C32AB5AD62003602C1 /* Sources */, + E39515C42AB5AD62003602C1 /* Frameworks */, + E39515C52AB5AD62003602C1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "WatchEnd Watch App"; + productName = "WatchEnd Watch App"; + productReference = E39515C72AB5AD62003602C1 /* WatchEnd Watch App.app */; + productType = "com.apple.product-type.application"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -253,6 +320,9 @@ E33A3E342A626DCD009744AB = { CreatedOnToolsVersion = 14.3; }; + E39515C62AB5AD62003602C1 = { + CreatedOnToolsVersion = 14.3.1; + }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; @@ -270,6 +340,7 @@ targets = ( 97C146ED1CF9000F007C117D /* Runner */, E33A3E342A626DCD009744AB /* StatusWidgetExtension */, + E39515C62AB5AD62003602C1 /* WatchEnd Watch App */, ); }; /* End PBXProject section */ @@ -296,6 +367,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + E39515C52AB5AD62003602C1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -392,6 +470,17 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + E39515C32AB5AD62003602C1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E39515DB2AB5AE7F003602C1 /* PhoneConnMgr.swift in Sources */, + E39515CC2AB5AD62003602C1 /* ContentView.swift in Sources */, + E39515CA2AB5AD62003602C1 /* WatchEndApp.swift in Sources */, + E39515DD2AB5AE9E003602C1 /* Store.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -400,6 +489,11 @@ target = E33A3E342A626DCD009744AB /* StatusWidgetExtension */; targetProxy = E33A3E472A626DD0009744AB /* PBXContainerItemProxy */; }; + E39515D32AB5AD64003602C1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = E39515C62AB5AD62003602C1 /* WatchEnd Watch App */; + targetProxy = E39515D22AB5AD64003602C1 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -766,6 +860,126 @@ }; name = Profile; }; + E39515D62AB5AD64003602C1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = ""; + DEVELOPMENT_TEAM = BA88US33G6; + ENABLE_PREVIEWS = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = WatchEnd; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; + INFOPLIST_KEY_WKCompanionAppBundleIdentifier = com.lollipopkit.toolbox; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "watchsimulator watchos"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + WATCHOS_DEPLOYMENT_TARGET = 7.0; + }; + name = Debug; + }; + E39515D72AB5AD64003602C1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = ""; + DEVELOPMENT_TEAM = BA88US33G6; + ENABLE_PREVIEWS = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = WatchEnd; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; + INFOPLIST_KEY_WKCompanionAppBundleIdentifier = com.lollipopkit.toolbox; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "watchsimulator watchos"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + WATCHOS_DEPLOYMENT_TARGET = 7.0; + }; + name = Release; + }; + E39515D82AB5AD64003602C1 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = ""; + DEVELOPMENT_TEAM = BA88US33G6; + ENABLE_PREVIEWS = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = WatchEnd; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; + INFOPLIST_KEY_WKCompanionAppBundleIdentifier = com.lollipopkit.toolbox; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "watchsimulator watchos"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + WATCHOS_DEPLOYMENT_TARGET = 7.0; + }; + name = Profile; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -799,6 +1013,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + E39515D92AB5AD64003602C1 /* Build configuration list for PBXNativeTarget "WatchEnd Watch App" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E39515D62AB5AD64003602C1 /* Debug */, + E39515D72AB5AD64003602C1 /* Release */, + E39515D82AB5AD64003602C1 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; diff --git a/ios/WatchApp/ContentView.swift b/ios/WatchApp/ContentView.swift new file mode 100644 index 00000000..c2531060 --- /dev/null +++ b/ios/WatchApp/ContentView.swift @@ -0,0 +1,151 @@ +// +// ContentView.swift +// WatchEnd Watch App +// +// Created by lolli on 2023/9/16. +// + +import SwiftUI + +struct ContentView: View { + @ObservedObject var _mgr = PhoneConnMgr() + + var body: some View { + let _count = _mgr.urls.count == 0 ? 1 : _mgr.urls.count + TabView { + ForEach(0 ..< _count, id:\.self) { index in + let url = _count == 1 && _mgr.urls.count == 0 ? nil : _mgr.urls[index] + PageView(url: url, state: .loading) + } + } + .tabViewStyle(PageTabViewStyle()) + } +} + +struct PageView: View { + let url: String? + @State var state: ContentState + + var body: some View { + if url == nil { + VStack { + Spacer() + Image(systemName: "exclamationmark.triangle.fill") + Spacer() + Text("Tip: Config it in the iOS app settings.").font(.system(.body, design: .monospaced)).padding(.horizontal, 7) + Spacer() + } + } else { + switch state { + case .loading: + ProgressView().padding().onAppear { + getStatus(url: url!) + } + case .error(let string): + VStack { + Spacer() + Image(systemName: "exclamationmark.triangle.fill").foregroundColor(.red) + Spacer() + Text(string).padding() + Spacer() + } + case .normal(let status): + VStack(alignment: .leading) { + HStack { + Text(status.name).font(.system(.title, design: .monospaced)) + Spacer() + Button(action: { + state = .loading + }){ + Image(systemName: "arrow.clockwise") + }.buttonStyle(.plain) + } + Spacer() + DetailItem(icon: "cpu", text: status.cpu) + DetailItem(icon: "memorychip", text: status.mem) + DetailItem(icon: "externaldrive", text: status.disk) + DetailItem(icon: "network", text: status.net) + }.frame(maxWidth: .infinity, maxHeight: .infinity).padding([.horizontal], 7) + } + } + } + + func getStatus(url: String) { + state = .loading + if url.count < 12 { + state = .error("url is too short") + return + } + guard let url = URL(string: url) else { + state = .error("url is invalid") + return + } + let task = URLSession.shared.dataTask(with: url) { (data, response, error) in + guard error == nil else { + state = .error(error!.localizedDescription) + return + } + guard let data = data else { + state = .error("data is nil") + return + } + guard let jsonAll = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { + state = .error("json parse fail") + return + } + guard let code = jsonAll["code"] as? Int else { + state = .error("code is nil") + return + } + if (code != 0) { + let msg = jsonAll["msg"] as? String ?? "" + state = .error(msg) + return + } + + let json = jsonAll["data"] as? [String: Any] ?? [:] + let name = json["name"] as? String ?? "" + let disk = json["disk"] as? String ?? "" + let cpu = json["cpu"] as? String ?? "" + let mem = json["mem"] as? String ?? "" + let net = json["net"] as? String ?? "" + state = .normal(Status(name: name, cpu: cpu, mem: mem, disk: disk, net: net)) + } + task.resume() + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} + +struct DetailItem: View { + let icon: String + let text: String + + var body: some View { + HStack(spacing: 5.7) { + Image(systemName: icon).resizable().foregroundColor(.white).frame(width: 11, height: 11, alignment: .center) + Text(text) + .font(.system(.caption2, design: .monospaced)) + .foregroundColor(.white) + } + } +} + +enum ContentState { + case loading + case error(String) + case normal(Status) +} + +struct Status { + let name: String + let cpu: String + let mem: String + let disk: String + let net: String +} + diff --git a/ios/WatchApp/PhoneConnMgr.swift b/ios/WatchApp/PhoneConnMgr.swift new file mode 100644 index 00000000..ab552ff1 --- /dev/null +++ b/ios/WatchApp/PhoneConnMgr.swift @@ -0,0 +1,54 @@ +// +// PhoneConnMgr.swift +// WatchEnd Watch App +// +// Created by lolli on 2023/9/16. +// + +import WatchConnectivity + +class PhoneConnMgr: NSObject, WCSessionDelegate, ObservableObject { + var session: WCSession? + var _ctx: [String: Any] = [:] + var ctx: [String: Any] { + set { + Store.setCtx(newValue) + updateUrls(newValue) + } + get { + return _ctx + } + } + @Published var urls: [String] = [] + + override init() { + super.init() + if !WCSession.isSupported() { + print("WCSession not supported") + } + session = WCSession.default + session?.delegate = self + session?.activate() + + ctx = Store.getCtx() + print("init", ctx) + } + + func updateUrls(_ val: [String: Any]) { + if let urls = val["urls"] as? [String] { + self.urls = urls.filter { !$0.isEmpty } + } + } + + func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { + + } + + // implement session:didReceiveApplicationContext: + func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) { + ctx = applicationContext + print("update", ctx) + } +} + + diff --git a/ios/WatchApp/Store.swift b/ios/WatchApp/Store.swift new file mode 100644 index 00000000..4bac2d8e --- /dev/null +++ b/ios/WatchApp/Store.swift @@ -0,0 +1,20 @@ +// +// Store.swift +// WatchEnd Watch App +// +// Created by lolli on 2023/9/16. +// + +import Foundation + +class Store { + static let defaults = UserDefaults.standard + + static let _ctxKey = "ctx" + static func getCtx() -> [String: Any] { + return defaults.object(forKey: _ctxKey) as? [String: Any] ?? [:] + } + static func setCtx(_ ctx: [String: Any]) { + defaults.set(ctx, forKey: _ctxKey) + } +} diff --git a/ios/WatchApp/WatchEndApp.swift b/ios/WatchApp/WatchEndApp.swift new file mode 100644 index 00000000..fe351840 --- /dev/null +++ b/ios/WatchApp/WatchEndApp.swift @@ -0,0 +1,17 @@ +// +// WatchEndApp.swift +// WatchEnd Watch App +// +// Created by lolli on 2023/9/16. +// + +import SwiftUI + +@main +struct WatchEndApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +}