From d2f5dd97f58dac065dea9188295ac57220de60b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Augustyniak?= Date: Thu, 24 Oct 2024 11:24:56 -0400 Subject: [PATCH] ios: allow example app users to configure API URL and key (#87) --- examples/swift/hello_world/BUILD | 4 +- .../swift/hello_world/Configuration.swift | 38 +++++++++++++++++++ .../swift/hello_world/ConfigurationView.swift | 28 ++++++++++++++ examples/swift/hello_world/ContentView.swift | 1 + .../swift/hello_world/LoggerCustomer.swift | 16 ++++---- 5 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 examples/swift/hello_world/Configuration.swift create mode 100644 examples/swift/hello_world/ConfigurationView.swift diff --git a/examples/swift/hello_world/BUILD b/examples/swift/hello_world/BUILD index 3a971132..42f73585 100644 --- a/examples/swift/hello_world/BUILD +++ b/examples/swift/hello_world/BUILD @@ -41,7 +41,7 @@ ios_application( "ipad", ], infoplists = ["Info.plist"], - minimum_os_version = "13.0", + minimum_os_version = "16.0", provisioning_profile = select({ "//bazel:ios_device_build": "//bazel/ios:ios_provisioning_profile", "//conditions:default": None, @@ -71,7 +71,7 @@ ios_application( "ipad", ], infoplists = ["Info.plist"], - minimum_os_version = "13.0", + minimum_os_version = "16.0", provisioning_profile = select({ "//bazel:ios_device_build": "//bazel/ios:ios_provisioning_profile", "//conditions:default": None, diff --git a/examples/swift/hello_world/Configuration.swift b/examples/swift/hello_world/Configuration.swift new file mode 100644 index 00000000..15d92b95 --- /dev/null +++ b/examples/swift/hello_world/Configuration.swift @@ -0,0 +1,38 @@ +// capture-sdk - bitdrift's client SDK +// Copyright Bitdrift, Inc. All rights reserved. +// +// Use of this source code is governed by a source available license that can be found in the +// LICENSE file or at: +// https://polyformproject.org/wp-content/uploads/2020/06/PolyForm-Shield-1.0.0.txt + +import Combine +import Foundation + +final class Configuration: ObservableObject { + @Published var apiURL: String + @Published var apiKey: String + + private var subscriptions = Set() + + static var storedAPIURL: String { + get { UserDefaults.standard.string(forKey: "apiURL") ?? "https://api.bitdrift.io" } + set { UserDefaults.standard.setValue(newValue, forKey: "apiURL") } + } + + static var storedAPIKey: String? { + get { UserDefaults.standard.string(forKey: "apiKey") } + set { UserDefaults.standard.setValue(newValue, forKey: "apiKey") } + } + + init() { + self.apiURL = Self.storedAPIURL + self.apiKey = Self.storedAPIKey ?? "" + + $apiURL + .sink(receiveValue: { Self.storedAPIURL = $0 }) + .store(in: &self.subscriptions) + $apiKey + .sink(receiveValue: { Self.storedAPIKey = $0 }) + .store(in: &self.subscriptions) + } +} diff --git a/examples/swift/hello_world/ConfigurationView.swift b/examples/swift/hello_world/ConfigurationView.swift new file mode 100644 index 00000000..fbda36dd --- /dev/null +++ b/examples/swift/hello_world/ConfigurationView.swift @@ -0,0 +1,28 @@ +// capture-sdk - bitdrift's client SDK +// Copyright Bitdrift, Inc. All rights reserved. +// +// Use of this source code is governed by a source available license that can be found in the +// LICENSE file or at: +// https://polyformproject.org/wp-content/uploads/2020/06/PolyForm-Shield-1.0.0.txt + +import SwiftUI + +struct ConfigurationView: View { + @StateObject var configuration = Configuration() + + var body: some View { + Text("API URL").frame(maxWidth: .infinity) + TextField(text: $configuration.apiURL) { Text("Enter API URL") } + .autocapitalization(.none) + + Text("API Key").frame(maxWidth: .infinity) + TextField(text: $configuration.apiKey, axis: .vertical) { Text("Enter API Key") } + .autocapitalization(.none) + + Spacer() + + Text("The app needs to be restarted for any configuration change to take effect.") + .font(.caption2) + .padding(EdgeInsets(top: 10, leading: 10, bottom: 20, trailing: 10)) + } +} diff --git a/examples/swift/hello_world/ContentView.swift b/examples/swift/hello_world/ContentView.swift index edd52ef3..79fcaf1a 100644 --- a/examples/swift/hello_world/ContentView.swift +++ b/examples/swift/hello_world/ContentView.swift @@ -24,6 +24,7 @@ struct ContentView: View { var body: some View { VStack { + NavigationLink("Configuration") { ConfigurationView() } Spacer() VStack { Text("ACTIONS") diff --git a/examples/swift/hello_world/LoggerCustomer.swift b/examples/swift/hello_world/LoggerCustomer.swift index f165332a..1f889770 100644 --- a/examples/swift/hello_world/LoggerCustomer.swift +++ b/examples/swift/hello_world/LoggerCustomer.swift @@ -9,9 +9,6 @@ import Capture import Foundation import MetricKit -private let kBitdriftAPIKey = "" -// swiftlint:disable:next force_unwrapping use_static_string_url_init -private let kBitdriftURL = URL(string: "https://api.bitdrift.io")! private let kDeviceId = "ios-helloworld" private struct EncodableExampleStruct: Encodable { @@ -83,21 +80,26 @@ final class LoggerCustomer: NSObject, URLSessionDelegate { override init() { self.appStartTime = Date() + super.init() + + guard let apiURL = URL(string: Configuration.storedAPIURL) else { + print("failed to initialize logger due to invalid API URL: \(Configuration.storedAPIURL)") + return + } + Logger .start( - withAPIKey: kBitdriftAPIKey, + withAPIKey: Configuration.storedAPIKey ?? "", sessionStrategy: .fixed(), configuration: .init(), fieldProviders: [CustomFieldProvider()], - apiURL: kBitdriftURL + apiURL: apiURL )? .enableIntegrations([.urlSession()], disableSwizzling: true) Logger.addField(withKey: "field_container_field_key", value: "field_container_value") Logger.logInfo("App launched. Logger configured.") - super.init() - MXMetricManager.shared.add(self) }