-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: adds NavigationView, NavigationLink based navigation to our sim…
…ple SwiftUI app
- Loading branch information
1 parent
d723084
commit ce82245
Showing
4 changed files
with
342 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
// | ||
// UtilView.swift | ||
// testApp (iOS) | ||
// | ||
// Created by Anna Huller on 6/14/22. | ||
// | ||
|
||
import SwiftUI | ||
import NewRelic | ||
|
||
struct UtilityView: View { | ||
|
||
@StateObject var viewModel: ViewModel | ||
|
||
var body: some View { | ||
VStack { | ||
HStack { | ||
var label = "Breadcrumbs:" + String(viewModel.numBreadcrumbs) | ||
Text(label) | ||
VStack { | ||
Button("Add Valid Breadcrumb") { | ||
viewModel.makeEvent() | ||
viewModel.makeBreadcrumb(name: "test", attributes: ["button" : "Breadcrumb"]) | ||
label = "Breadcrumbs:" + String(viewModel.numBreadcrumbs) | ||
} | ||
|
||
Button("Add Invalid Breadcrumb") { | ||
viewModel.makeEvent() | ||
viewModel.makeBreadcrumb(name: "", attributes: ["button" : "Breadcrumb"]) | ||
label = "Breadcrumbs:" + String(viewModel.numBreadcrumbs) | ||
} | ||
} | ||
} | ||
HStack { | ||
var label = "Attributes: " + viewModel.attributes | ||
Text(label) | ||
Button("Set Attributes!") { | ||
viewModel.makeEvent() | ||
viewModel.setAttributes() | ||
label = viewModel.attributes | ||
} | ||
} | ||
|
||
Button("Crash Now!") { | ||
viewModel.makeEvent() | ||
viewModel.crash() | ||
} | ||
Button("Make Huge Crash Report!") { | ||
viewModel.makeEvent() | ||
viewModel.hugeCrashReport() | ||
} | ||
Button("Remove Attributes!") { | ||
viewModel.makeEvent() | ||
|
||
if viewModel.removeAttributes() == true { | ||
viewModel.attributes = "" | ||
|
||
} | ||
} | ||
Button("Record Error") { | ||
viewModel.makeError() | ||
viewModel.makeEvent() | ||
} | ||
|
||
Group { | ||
let label = "Button Presses: " + String(viewModel.events) | ||
Text(label) | ||
Button("Make 100 events") { | ||
viewModel.make100Events() | ||
} | ||
Button("START Interaction Trace") { | ||
viewModel.startInteractionTrace() | ||
} | ||
Button("END Interaction Trace") { | ||
viewModel.stopInteractionTrace() | ||
|
||
} | ||
Button("Send Redirect Request") { | ||
viewModel.sendRedirectRequest() | ||
} | ||
Button("Notice Network Request") { | ||
viewModel.noticeNWRequest() | ||
} | ||
Button("Notice Network Failure") { | ||
viewModel.noticeFailedNWRequest() | ||
} | ||
|
||
Button("URLSession dataTask") { | ||
viewModel.doDataTask() | ||
} | ||
|
||
Button("URLSession dataTask w/ completion") { | ||
viewModel.doDataTaskWithCompletionHandler() | ||
} | ||
} | ||
} | ||
.navigationBarTitle(viewModel.title) | ||
.NRTrackView(name: "UtilityView") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
// | ||
// UtilViewModel.swift | ||
// testApp (iOS) | ||
// | ||
// Created by Anna Huller on 6/14/22. | ||
// | ||
|
||
import SwiftUI | ||
import NewRelic | ||
|
||
extension UtilityView { | ||
@MainActor class ViewModel: ObservableObject { | ||
|
||
let title = "Utility" | ||
@Published var numBreadcrumbs = 0 | ||
@Published var goodAttribute = false | ||
@Published var badAttribute = false | ||
@Published var attributes = "" | ||
@Published var events = 0 | ||
|
||
var uniqueInteractionTraceIdentifier: String? = nil | ||
|
||
let taskProcessor = TaskProcessor() | ||
|
||
func crash() { | ||
NewRelic.crashNow("New Relic intentionally crashed to test Utils") | ||
} | ||
func hugeCrashReport() { | ||
let crashOutputFilePath = String(format: "%@%@/%d.%@", NSTemporaryDirectory(), "nrcrashreports", 42, "nrcrashreport") | ||
|
||
let data = makeBigDictionary() | ||
do { | ||
try FileManager.default.createDirectory(atPath: String(format: "%@/%@", NSTemporaryDirectory(), "nrcrashreports"), withIntermediateDirectories: true) | ||
|
||
let success = FileManager.default.createFile(atPath: crashOutputFilePath, contents: data) | ||
|
||
} catch { | ||
print(error.localizedDescription) | ||
} | ||
} | ||
func removeAttributes() -> Bool{ | ||
return NewRelic.removeAllAttributes() | ||
} | ||
func setAttributes(){ | ||
attributes = "test1: " + String(NewRelic.setAttribute("test1", value: 1)) + " '': " + String(NewRelic.setAttribute("", value: 2)) | ||
} | ||
func makeError(){ | ||
do { | ||
try errorMethod() | ||
} catch { | ||
NewRelic.recordError(error) | ||
|
||
} | ||
} | ||
private func errorMethod() throws { | ||
throw CancellationError.init() | ||
} | ||
func makeBreadcrumb(name: String, attributes: Dictionary<String, Any>){ | ||
let madeBreadCrumb = NewRelic.recordBreadcrumb(name, | ||
attributes: attributes) | ||
if madeBreadCrumb == true { | ||
self.numBreadcrumbs += 1 | ||
} | ||
} | ||
|
||
func makeEvent(){ | ||
let madeEvent = NewRelic.recordCustomEvent("ButtonPress") | ||
if madeEvent == true { | ||
events += 1 | ||
} | ||
} | ||
|
||
func make100Events() { | ||
for i in 0...100 { | ||
NewRelic.recordCustomEvent("ButtonPress") | ||
} | ||
} | ||
|
||
func sendRedirectRequest() { | ||
guard let url = URL(string: "https://easynvest.com.br") else { return } | ||
|
||
var request = URLRequest(url: url) | ||
request.httpMethod = "GET" | ||
|
||
let task = URLSession.shared.dataTask(with: request) { data, response, error in | ||
print("ok") | ||
} | ||
task.resume() | ||
} | ||
func stopInteractionTrace() { | ||
guard let identifier = uniqueInteractionTraceIdentifier else { | ||
print("no interaction to stop...") | ||
return | ||
} | ||
NewRelic.stopCurrentInteraction(identifier) | ||
|
||
uniqueInteractionTraceIdentifier = nil | ||
} | ||
|
||
func startInteractionTrace() { | ||
uniqueInteractionTraceIdentifier = NewRelic.startInteraction(withName: "myInteractionName") | ||
} | ||
|
||
|
||
|
||
func noticeFailedNWRequest() { | ||
NewRelic.noticeNetworkFailure(for: URL(string: "https://www.google.com"), httpMethod: "GET", | ||
with: NRTimer(), andFailureCode: NSURLErrorTimedOut) | ||
} | ||
|
||
func noticeNWRequest() { | ||
// NewRelic.noticeNetworkRequest(for: URL(string: "https://www.google.com"), httpMethod: "GET", with: NRTimer(), responseHeaders: [:], | ||
// statusCode: 200, bytesSent: 1000, bytesReceived: 1000, responseData: Data(), traceHeaders: nil, andParams: nil) | ||
|
||
NewRelic.noticeNetworkRequest(for: URL(string:"https://fakeurl.com"), | ||
httpMethod: "GET", | ||
startTime: Date().timeIntervalSince1970, | ||
endTime: Date().timeIntervalSince1970, | ||
responseHeaders: nil, | ||
statusCode: 400, | ||
bytesSent: 100, | ||
bytesReceived: 200, | ||
responseData: Data("example response body".utf8), | ||
traceHeaders: nil, | ||
andParams: nil) | ||
} | ||
|
||
func setBuild() { | ||
NewRelic.setApplicationBuild("42") | ||
} | ||
|
||
|
||
func doDataTask() { | ||
let urlSession = URLSession(configuration: URLSession.shared.configuration, delegate: taskProcessor, delegateQueue: nil) | ||
guard let url = URL(string: "https://www.google.com") else { return } | ||
|
||
let request = URLRequest(url: url) | ||
|
||
let dataTask = urlSession.dataTask(with: request) | ||
|
||
dataTask.resume() | ||
} | ||
|
||
func doDataTaskWithCompletionHandler() { | ||
let urlSession = URLSession(configuration: URLSessionConfiguration.default) | ||
guard let url = URL(string: "https://www.google.com") else { return } | ||
|
||
let request = URLRequest(url: url) | ||
|
||
let dataTask = urlSession.dataTask(with: request) { data, response, error in | ||
//Handle | ||
if let httpResponse = response as? HTTPURLResponse { | ||
print("SUCCESS w/ dataTask w/ completionHandler") | ||
|
||
} | ||
else if let errorCode = error?._code { | ||
print(error?.localizedDescription) | ||
|
||
} | ||
else { | ||
|
||
} | ||
} | ||
|
||
dataTask.resume() | ||
urlSession.finishTasksAndInvalidate() | ||
} | ||
|
||
func makeBigDictionary() -> Data { | ||
var dictionary = [String:String]() | ||
var data = Data() | ||
for i in 0...30000 { | ||
dictionary.updateValue("42", forKey: "The meaning of life #"+String(i)) | ||
} | ||
do { | ||
data = try JSONSerialization.data(withJSONObject: dictionary) | ||
} catch { | ||
print(error.localizedDescription) | ||
} | ||
return data | ||
} | ||
} | ||
} | ||
|
||
class TaskProcessor: NSObject, URLSessionDelegate, URLSessionDataDelegate, URLSessionTaskDelegate { | ||
|
||
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) { | ||
|
||
completionHandler(.allow) | ||
} | ||
|
||
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { | ||
print("DataTask rcv data.") | ||
} | ||
|
||
public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { | ||
print("DataTask did complete.") | ||
} | ||
|
||
public func urlSession(_ session: URLSession, | ||
task: URLSessionTask, | ||
didReceive challenge: URLAuthenticationChallenge, | ||
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { | ||
// completionHandler(.performDefaultHandling, nil) | ||
|
||
//completionHandler(.cancelAuthenticationChallenge, nil) | ||
|
||
if let trust = challenge.protectionSpace.serverTrust, | ||
SecTrustGetCertificateCount(trust) > 0 { | ||
if let certificate = SecTrustGetCertificateAtIndex(trust, 0) { | ||
let data = SecCertificateCopyData(certificate) as Data | ||
|
||
completionHandler(.useCredential, URLCredential(trust: trust)) | ||
return | ||
} | ||
|
||
} | ||
completionHandler(.cancelAuthenticationChallenge, nil) | ||
|
||
|
||
} | ||
} |